if (ipv6_addr_any(&rs->rs_bound_addr) || !rs->rs_transport) {
ret = -ENOTCONN; /* XXX not a great errno */ goto out;
}
if (!rs->rs_transport->get_mr) {
ret = -EOPNOTSUPP; goto out;
}
/* If the combination of the addr and size requested for this memory *regioncausesanintegeroverflow,returnerror.
*/ if (((args->vec.addr + args->vec.bytes) < args->vec.addr) ||
PAGE_ALIGN(args->vec.addr + args->vec.bytes) <
(args->vec.addr + args->vec.bytes)) {
ret = -EINVAL; goto out;
}
if (!can_do_mlock()) {
ret = -EPERM; goto out;
}
nr_pages = rds_pages_in_vec(&args->vec); if (nr_pages == 0) {
ret = -EINVAL; goto out;
}
/* Restrict the size of mr irrespective of underlying transport *Toaccountforunalignedmrregions,subtractonefromnr_pages
*/ if ((nr_pages - 1) > (RDS_MAX_MSG_SIZE >> PAGE_SHIFT)) {
ret = -EMSGSIZE; goto out;
}
/* XXX clamp nr_pages to limit the size of this alloc? */
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); if (!pages) {
ret = -ENOMEM; goto out;
}
mr = kzalloc(sizeof(struct rds_mr), GFP_KERNEL); if (!mr) {
ret = -ENOMEM; goto out;
}
/* Stick all pages into the scatterlist */ for (i = 0 ; i < nents; i++)
sg_set_page(&sg[i], pages[i], PAGE_SIZE, 0);
rdsdebug("RDS: trans_private nents is %u\n", nents);
} /* Obtain a transport specific MR. If this succeeds, the *s/glistisnowownedbytheMR. *Notethatdma_map()impliesthatpendingwritesare
* flushed to RAM, so no dma_sync is needed here. */
trans_private = rs->rs_transport->get_mr(
sg, nents, rs, &mr->r_key, cp ? cp->cp_conn : NULL,
args->vec.addr, args->vec.bytes,
need_odp ? ODP_ZEROBASED : ODP_NOT_NEEDED);
if (IS_ERR(trans_private)) { /* In ODP case, we don't GUP pages, so don't need *toreleaseanything.
*/ if (!need_odp) {
unpin_user_pages(pages, nr_pages);
kfree(sg);
}
ret = PTR_ERR(trans_private); /* Trigger connection so that its ready for the next retry */ if (ret == -ENODEV && cp)
rds_conn_connect_if_down(cp->cp_conn); goto out;
}
/* The user may pass us an unaligned address, but we can only *mappagealignedregions.Sowekeeptheoffset,andbuild *a64bitcookiecontaining<R_Key,offset>andpassthat
* around. */ if (need_odp)
cookie = rds_rdma_make_cookie(mr->r_key, 0); else
cookie = rds_rdma_make_cookie(mr->r_key,
args->vec.addr & ~PAGE_MASK); if (cookie_ret)
*cookie_ret = cookie;
if (args->cookie_addr &&
put_user(cookie, (u64 __user *)(unsignedlong)args->cookie_addr)) { if (!need_odp) {
unpin_user_pages(pages, nr_pages);
kfree(sg);
}
ret = -EFAULT; goto out;
}
/* Inserting the new MR into the rbtree bumps its
* reference count. */
spin_lock_irqsave(&rs->rs_rdma_lock, flags);
found = rds_mr_tree_walk(&rs->rs_rdma_keys, mr->r_key, mr);
spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
BUG_ON(found && found != mr);
rdsdebug("RDS: get_mr key is %x\n", mr->r_key); if (mr_ret) {
kref_get(&mr->r_kref);
*mr_ret = mr;
}
ret = 0;
out:
kfree(pages); if (mr)
kref_put(&mr->r_kref, __rds_put_mr_final); return ret;
}
int rds_get_mr(struct rds_sock *rs, sockptr_t optval, int optlen)
{ struct rds_get_mr_args args;
if (optlen != sizeof(struct rds_get_mr_args)) return -EINVAL;
if (copy_from_sockptr(&args, optval, sizeof(struct rds_get_mr_args))) return -EFAULT;
/* *FreetheMRindicatedbythegivenR_Key
*/ int rds_free_mr(struct rds_sock *rs, sockptr_t optval, int optlen)
{ struct rds_free_mr_args args; struct rds_mr *mr; unsignedlong flags;
if (optlen != sizeof(struct rds_free_mr_args)) return -EINVAL;
if (copy_from_sockptr(&args, optval, sizeof(struct rds_free_mr_args))) return -EFAULT;
/* Special case - a null cookie means flush all unused MRs */ if (args.cookie == 0) { if (!rs->rs_transport || !rs->rs_transport->flush_mrs) return -EINVAL;
rs->rs_transport->flush_mrs(); return0;
}
/* Look up the MR given its R_key and remove it from the rbtree *sonobodyelsefindsit. *Thisshouldalsopreventraceswithrds_rdma_unuse.
*/
spin_lock_irqsave(&rs->rs_rdma_lock, flags);
mr = rds_mr_tree_walk(&rs->rs_rdma_keys, rds_rdma_cookie_key(args.cookie), NULL); if (mr) {
rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
RB_CLEAR_NODE(&mr->r_rb_node); if (args.flags & RDS_RDMA_INVALIDATE)
mr->r_invalidate = 1;
}
spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
spin_lock_irqsave(&rs->rs_rdma_lock, flags);
mr = rds_mr_tree_walk(&rs->rs_rdma_keys, r_key, NULL); if (!mr) {
pr_debug("rds: trying to unuse MR with unknown r_key %u!\n",
r_key);
spin_unlock_irqrestore(&rs->rs_rdma_lock, flags); return;
}
/* Get a reference so that the MR won't go away before calling *sync_mr()below.
*/
kref_get(&mr->r_kref);
/* If it is going to be freed, remove it from the tree now so *thatnootherthreadcanfinditandfreeit.
*/ if (mr->r_use_once || force) {
rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
RB_CLEAR_NODE(&mr->r_rb_node);
zot_me = 1;
}
spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
/* May have to issue a dma_sync on this memory region. *NotewecouldavoidthisiftheoperationwasaRDMAREAD,
* but at this point we can't tell. */ if (mr->r_trans->sync_mr)
mr->r_trans->sync_mr(mr->r_trans_private, DMA_FROM_DEVICE);
/* Release the reference held above. */
kref_put(&mr->r_kref, __rds_put_mr_final);
/* If the MR was marked as invalidate, this will
* trigger an async flush. */ if (zot_me)
kref_put(&mr->r_kref, __rds_put_mr_final);
}
if (ro->op_odp_mr) {
kref_put(&ro->op_odp_mr->r_kref, __rds_put_mr_final);
} else { for (i = 0; i < ro->op_nents; i++) { struct page *page = sg_page(&ro->op_sg[i]);
/* Mark page dirty if it was possibly modified, which *isthecaseforaRDMA_READwhichcopiesfromremote *tolocalmemory
*/
unpin_user_pages_dirty_lock(&page, 1, !ro->op_write);
}
}
/* Mark page dirty if it was possibly modified, which *isthecaseforaRDMA_READwhichcopiesfromremote
* to local memory */
unpin_user_pages_dirty_lock(&page, 1, true);
/* *Countthenumberofpagesneededtodescribeanincomingiovecarray.
*/ staticint rds_rdma_pages(struct rds_iovec iov[], int nr_iovecs)
{ int tot_pages = 0; unsignedint nr_pages; unsignedint i;
/* figure out the number of pages in the vector */ for (i = 0; i < nr_iovecs; i++) {
nr_pages = rds_pages_in_vec(&iov[i]); if (nr_pages == 0) return -EINVAL;
/* *TheapplicationasksforaRDMAtransfer. *Extractallargumentsandsetuptherdma_op
*/ int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm, struct cmsghdr *cmsg, struct rds_iov_vector *vec)
{ struct rds_rdma_args *args; struct rm_rdma_op *op = &rm->rdma; int nr_pages; unsignedint nr_bytes; struct page **pages = NULL; struct rds_iovec *iovs; unsignedint i, j; int ret = 0; bool odp_supported = true;
if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args))
|| rm->rdma.op_active) return -EINVAL;
args = CMSG_DATA(cmsg);
if (ipv6_addr_any(&rs->rs_bound_addr)) {
ret = -ENOTCONN; /* XXX not a great errno */ goto out_ret;
}
if (args->nr_local > UIO_MAXIOV) {
ret = -EMSGSIZE; goto out_ret;
}
if (vec->len != args->nr_local) {
ret = -EINVAL; goto out_ret;
} /* odp-mr is not supported for multiple requests within one message */ if (args->nr_local != 1)
odp_supported = false;
iovs = vec->iov;
nr_pages = rds_rdma_pages(iovs, args->nr_local); if (nr_pages < 0) {
ret = -EINVAL; goto out_ret;
}
pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL); if (!pages) {
ret = -ENOMEM; goto out_ret;
}
for (i = 0; i < args->nr_local; i++) { struct rds_iovec *iov = &iovs[i]; /* don't need to check, rds_rdma_pages() verified nr will be +nonzero */ unsignedint nr = rds_pages_in_vec(iov);
/* If it's a WRITE operation, we want to pin the pages for reading. *Ifit'saREADoperation,weneedtopinthepagesforwriting.
*/
ret = rds_pin_pages(iov->addr, nr, pages, !op->op_write); if ((!odp_supported && ret <= 0) ||
(odp_supported && ret <= 0 && ret != -EOPNOTSUPP)) goto out_pages;
if (ret == -EOPNOTSUPP) { struct rds_mr *local_odp_mr;
if (!rs->rs_transport->get_mr) {
ret = -EOPNOTSUPP; goto out_pages;
}
local_odp_mr =
kzalloc(sizeof(*local_odp_mr), GFP_KERNEL); if (!local_odp_mr) {
ret = -ENOMEM; goto out_pages;
}
RB_CLEAR_NODE(&local_odp_mr->r_rb_node);
kref_init(&local_odp_mr->r_kref);
local_odp_mr->r_trans = rs->rs_transport;
local_odp_mr->r_sock = rs;
local_odp_mr->r_trans_private =
rs->rs_transport->get_mr(
NULL, 0, rs, &local_odp_mr->r_key, NULL,
iov->addr, iov->bytes, ODP_VIRTUAL); if (IS_ERR(local_odp_mr->r_trans_private)) {
ret = PTR_ERR(local_odp_mr->r_trans_private);
rdsdebug("get_mr ret %d %p\"", ret,
local_odp_mr->r_trans_private);
kfree(local_odp_mr);
ret = -EOPNOTSUPP; goto out_pages;
}
rdsdebug("Need odp; local_odp_mr %p trans_private %p\n",
local_odp_mr, local_odp_mr->r_trans_private);
op->op_odp_mr = local_odp_mr;
op->op_odp_addr = iov->addr;
}
/* We are reusing a previously mapped MR here. Most likely, the *applicationhaswrittentothebuffer,soweneedtoexplicitly *flushthosewritestoRAM.OtherwisetheHCAmaynotseethem *whendoingaDMAfromthatbuffer.
*/
r_key = rds_rdma_cookie_key(rm->m_rdma_cookie);
if (rm->atomic.op_notify || rm->atomic.op_recverr) { /* We allocate an uninitialized notifier here, because *wedon'twanttodothatinthecompletionhandler.We *wouldhavetouseGFP_ATOMICthere,anddon'twanttodeal *withfailedallocations.
*/
rm->atomic.op_notifier = kmalloc(sizeof(*rm->atomic.op_notifier), GFP_KERNEL); if (!rm->atomic.op_notifier) {
ret = -ENOMEM; goto err;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.