mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Some RDMA work and some good bugfixes, and two new features that could
benefit from user testing:
Anna Schumacker contributed a simple NFSv4.2 COPY implementation. COPY
is already supported on the client side, so a call to copy_file_range()
on a recent client should now result in a server-side copy that doesn't
require all the data to make a round trip to the client and back.
Jeff Layton implemented callbacks to notify clients when contended locks
become available, which should reduce latency on workloads with
contended locks.
-----BEGIN PGP SIGNATURE-----
iQIcBAABAgAGBQJX/mcsAAoJECebzXlCjuG+MU0P/3SzTLGYXU5yOTAorx255/uf
fUVKQQhTzzaA2xj3gWWWztYx3y0ZJUVgwU56a+Ap5Z8/goqDQ78H+ePEc+MG7BT/
/UXS/bITvt0MP/dvPrDzhSltvqx/wpelLPBo29hGLlAQ2dsnD4Y75IbOOQccWqcC
iD2v6x7lnpWZ7j9Zhwzg/JNQHwISIb7tiLoYBjfcdNDEMU76KIyhxD0Cx9MSeBzH
9Rq/oEdwGDFS5WqVfNe2jxbngoauq1IupziQ2eQGv2D/POyXCx8fphoYjDz1XaW8
PxaJtJtM2owPGG+z2CxklJqNaS1Z4F+oppjg+nf4i/ibxmIBaTy8NluASX3vMh69
CDO1+ly+TiF0l1VqMOQJWRnqn1qGk6fLpF6P1Ac62B0oWpeLGU7nmik7XN1ORgsi
8ksxRKNAWeprZo3wl5xNrADu/wlZ7XCJTc4QoHEgYT04aHF+j8EMCHv+mtZ8+Bwn
WWiA8iItZOgXV4vitCRJlvsixjYvmF3djPIoI2Lt5KDWIg+eL89sKwzTALSfeC4m
Vjb0svzPX1MmZCNP1rCStFbl3gZYXZyqPk+uA6M7H8mjAjVeKxRPowWpMBgvYZHr
FjCPb878bAuqCeBVbIyOLLcKWBLTw8PsUWZAor3gNg454JGkMjLUyJ/S22Cz5Nbo
HdjoiTJtbPrHnCwTMXwa
=nozl
-----END PGP SIGNATURE-----
Merge tag 'nfsd-4.9' of git://linux-nfs.org/~bfields/linux
Pull nfsd updates from Bruce Fields:
"Some RDMA work and some good bugfixes, and two new features that could
benefit from user testing:
- Anna Schumacker contributed a simple NFSv4.2 COPY implementation.
COPY is already supported on the client side, so a call to
copy_file_range() on a recent client should now result in a
server-side copy that doesn't require all the data to make a round
trip to the client and back.
- Jeff Layton implemented callbacks to notify clients when contended
locks become available, which should reduce latency on workloads
with contended locks"
* tag 'nfsd-4.9' of git://linux-nfs.org/~bfields/linux:
NFSD: Implement the COPY call
nfsd: handle EUCLEAN
nfsd: only WARN once on unmapped errors
exportfs: be careful to only return expected errors.
nfsd4: setclientid_confirm with unmatched verifier should fail
nfsd: randomize SETCLIENTID reply to help distinguish servers
nfsd: set the MAY_NOTIFY_LOCK flag in OPEN replies
nfs: add a new NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK constant
nfsd: add a LRU list for blocked locks
nfsd: have nfsd4_lock use blocking locks for v4.1+ locks
nfsd: plumb in a CB_NOTIFY_LOCK operation
NFSD: fix corruption in notifier registration
svcrdma: support Remote Invalidation
svcrdma: Server-side support for rpcrdma_connect_private
rpcrdma: RDMA/CM private message data structure
svcrdma: Skip put_page() when send_reply() fails
svcrdma: Tail iovec leaves an orphaned DMA mapping
nfsd: fix dprintk in nfsd4_encode_getdeviceinfo
nfsd: eliminate cb_minorversion field
nfsd: don't set a FL_LAYOUT lease for flexfiles layouts
This commit is contained in:
commit
2778556474
25 changed files with 683 additions and 96 deletions
|
|
@ -129,7 +129,7 @@ static int svc_rdma_bc_sendto(struct svcxprt_rdma *rdma,
|
|||
ret = -EIO;
|
||||
goto out_unmap;
|
||||
}
|
||||
atomic_inc(&rdma->sc_dma_used);
|
||||
svc_rdma_count_mappings(rdma, ctxt);
|
||||
|
||||
memset(&send_wr, 0, sizeof(send_wr));
|
||||
ctxt->cqe.done = svc_rdma_wc_send;
|
||||
|
|
|
|||
|
|
@ -159,7 +159,7 @@ int rdma_read_chunk_lcl(struct svcxprt_rdma *xprt,
|
|||
ctxt->sge[pno].addr);
|
||||
if (ret)
|
||||
goto err;
|
||||
atomic_inc(&xprt->sc_dma_used);
|
||||
svc_rdma_count_mappings(xprt, ctxt);
|
||||
|
||||
ctxt->sge[pno].lkey = xprt->sc_pd->local_dma_lkey;
|
||||
ctxt->sge[pno].length = len;
|
||||
|
|
|
|||
|
|
@ -225,6 +225,48 @@ svc_rdma_get_reply_array(struct rpcrdma_msg *rmsgp,
|
|||
return rp_ary;
|
||||
}
|
||||
|
||||
/* RPC-over-RDMA Version One private extension: Remote Invalidation.
|
||||
* Responder's choice: requester signals it can handle Send With
|
||||
* Invalidate, and responder chooses one rkey to invalidate.
|
||||
*
|
||||
* Find a candidate rkey to invalidate when sending a reply. Picks the
|
||||
* first rkey it finds in the chunks lists.
|
||||
*
|
||||
* Returns zero if RPC's chunk lists are empty.
|
||||
*/
|
||||
static u32 svc_rdma_get_inv_rkey(struct rpcrdma_msg *rdma_argp,
|
||||
struct rpcrdma_write_array *wr_ary,
|
||||
struct rpcrdma_write_array *rp_ary)
|
||||
{
|
||||
struct rpcrdma_read_chunk *rd_ary;
|
||||
struct rpcrdma_segment *arg_ch;
|
||||
u32 inv_rkey;
|
||||
|
||||
inv_rkey = 0;
|
||||
|
||||
rd_ary = svc_rdma_get_read_chunk(rdma_argp);
|
||||
if (rd_ary) {
|
||||
inv_rkey = be32_to_cpu(rd_ary->rc_target.rs_handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (wr_ary && be32_to_cpu(wr_ary->wc_nchunks)) {
|
||||
arg_ch = &wr_ary->wc_array[0].wc_target;
|
||||
inv_rkey = be32_to_cpu(arg_ch->rs_handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (rp_ary && be32_to_cpu(rp_ary->wc_nchunks)) {
|
||||
arg_ch = &rp_ary->wc_array[0].wc_target;
|
||||
inv_rkey = be32_to_cpu(arg_ch->rs_handle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
out:
|
||||
dprintk("svcrdma: Send With Invalidate rkey=%08x\n", inv_rkey);
|
||||
return inv_rkey;
|
||||
}
|
||||
|
||||
/* Assumptions:
|
||||
* - The specified write_len can be represented in sc_max_sge * PAGE_SIZE
|
||||
*/
|
||||
|
|
@ -280,7 +322,7 @@ static int send_write(struct svcxprt_rdma *xprt, struct svc_rqst *rqstp,
|
|||
if (ib_dma_mapping_error(xprt->sc_cm_id->device,
|
||||
sge[sge_no].addr))
|
||||
goto err;
|
||||
atomic_inc(&xprt->sc_dma_used);
|
||||
svc_rdma_count_mappings(xprt, ctxt);
|
||||
sge[sge_no].lkey = xprt->sc_pd->local_dma_lkey;
|
||||
ctxt->count++;
|
||||
sge_off = 0;
|
||||
|
|
@ -464,7 +506,8 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
|||
struct page *page,
|
||||
struct rpcrdma_msg *rdma_resp,
|
||||
struct svc_rdma_req_map *vec,
|
||||
int byte_count)
|
||||
int byte_count,
|
||||
u32 inv_rkey)
|
||||
{
|
||||
struct svc_rdma_op_ctxt *ctxt;
|
||||
struct ib_send_wr send_wr;
|
||||
|
|
@ -489,7 +532,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
|||
ctxt->sge[0].length, DMA_TO_DEVICE);
|
||||
if (ib_dma_mapping_error(rdma->sc_cm_id->device, ctxt->sge[0].addr))
|
||||
goto err;
|
||||
atomic_inc(&rdma->sc_dma_used);
|
||||
svc_rdma_count_mappings(rdma, ctxt);
|
||||
|
||||
ctxt->direction = DMA_TO_DEVICE;
|
||||
|
||||
|
|
@ -505,7 +548,7 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
|||
if (ib_dma_mapping_error(rdma->sc_cm_id->device,
|
||||
ctxt->sge[sge_no].addr))
|
||||
goto err;
|
||||
atomic_inc(&rdma->sc_dma_used);
|
||||
svc_rdma_count_mappings(rdma, ctxt);
|
||||
ctxt->sge[sge_no].lkey = rdma->sc_pd->local_dma_lkey;
|
||||
ctxt->sge[sge_no].length = sge_bytes;
|
||||
}
|
||||
|
|
@ -523,23 +566,9 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
|||
ctxt->pages[page_no+1] = rqstp->rq_respages[page_no];
|
||||
ctxt->count++;
|
||||
rqstp->rq_respages[page_no] = NULL;
|
||||
/*
|
||||
* If there are more pages than SGE, terminate SGE
|
||||
* list so that svc_rdma_unmap_dma doesn't attempt to
|
||||
* unmap garbage.
|
||||
*/
|
||||
if (page_no+1 >= sge_no)
|
||||
ctxt->sge[page_no+1].length = 0;
|
||||
}
|
||||
rqstp->rq_next_page = rqstp->rq_respages + 1;
|
||||
|
||||
/* The loop above bumps sc_dma_used for each sge. The
|
||||
* xdr_buf.tail gets a separate sge, but resides in the
|
||||
* same page as xdr_buf.head. Don't count it twice.
|
||||
*/
|
||||
if (sge_no > ctxt->count)
|
||||
atomic_dec(&rdma->sc_dma_used);
|
||||
|
||||
if (sge_no > rdma->sc_max_sge) {
|
||||
pr_err("svcrdma: Too many sges (%d)\n", sge_no);
|
||||
goto err;
|
||||
|
|
@ -549,7 +578,11 @@ static int send_reply(struct svcxprt_rdma *rdma,
|
|||
send_wr.wr_cqe = &ctxt->cqe;
|
||||
send_wr.sg_list = ctxt->sge;
|
||||
send_wr.num_sge = sge_no;
|
||||
send_wr.opcode = IB_WR_SEND;
|
||||
if (inv_rkey) {
|
||||
send_wr.opcode = IB_WR_SEND_WITH_INV;
|
||||
send_wr.ex.invalidate_rkey = inv_rkey;
|
||||
} else
|
||||
send_wr.opcode = IB_WR_SEND;
|
||||
send_wr.send_flags = IB_SEND_SIGNALED;
|
||||
|
||||
ret = svc_rdma_send(rdma, &send_wr);
|
||||
|
|
@ -581,6 +614,7 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
|||
int inline_bytes;
|
||||
struct page *res_page;
|
||||
struct svc_rdma_req_map *vec;
|
||||
u32 inv_rkey;
|
||||
|
||||
dprintk("svcrdma: sending response for rqstp=%p\n", rqstp);
|
||||
|
||||
|
|
@ -591,6 +625,10 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
|||
wr_ary = svc_rdma_get_write_array(rdma_argp);
|
||||
rp_ary = svc_rdma_get_reply_array(rdma_argp, wr_ary);
|
||||
|
||||
inv_rkey = 0;
|
||||
if (rdma->sc_snd_w_inv)
|
||||
inv_rkey = svc_rdma_get_inv_rkey(rdma_argp, wr_ary, rp_ary);
|
||||
|
||||
/* Build an req vec for the XDR */
|
||||
vec = svc_rdma_get_req_map(rdma);
|
||||
ret = svc_rdma_map_xdr(rdma, &rqstp->rq_res, vec, wr_ary != NULL);
|
||||
|
|
@ -633,9 +671,9 @@ int svc_rdma_sendto(struct svc_rqst *rqstp)
|
|||
goto err1;
|
||||
|
||||
ret = send_reply(rdma, rqstp, res_page, rdma_resp, vec,
|
||||
inline_bytes);
|
||||
inline_bytes, inv_rkey);
|
||||
if (ret < 0)
|
||||
goto err1;
|
||||
goto err0;
|
||||
|
||||
svc_rdma_put_req_map(rdma, vec);
|
||||
dprintk("svcrdma: send_reply returns %d\n", ret);
|
||||
|
|
@ -692,7 +730,7 @@ void svc_rdma_send_error(struct svcxprt_rdma *xprt, struct rpcrdma_msg *rmsgp,
|
|||
svc_rdma_put_context(ctxt, 1);
|
||||
return;
|
||||
}
|
||||
atomic_inc(&xprt->sc_dma_used);
|
||||
svc_rdma_count_mappings(xprt, ctxt);
|
||||
|
||||
/* Prepare SEND WR */
|
||||
memset(&err_wr, 0, sizeof(err_wr));
|
||||
|
|
|
|||
|
|
@ -198,6 +198,7 @@ struct svc_rdma_op_ctxt *svc_rdma_get_context(struct svcxprt_rdma *xprt)
|
|||
|
||||
out:
|
||||
ctxt->count = 0;
|
||||
ctxt->mapped_sges = 0;
|
||||
ctxt->frmr = NULL;
|
||||
return ctxt;
|
||||
|
||||
|
|
@ -221,22 +222,27 @@ out_empty:
|
|||
void svc_rdma_unmap_dma(struct svc_rdma_op_ctxt *ctxt)
|
||||
{
|
||||
struct svcxprt_rdma *xprt = ctxt->xprt;
|
||||
int i;
|
||||
for (i = 0; i < ctxt->count && ctxt->sge[i].length; i++) {
|
||||
struct ib_device *device = xprt->sc_cm_id->device;
|
||||
u32 lkey = xprt->sc_pd->local_dma_lkey;
|
||||
unsigned int i, count;
|
||||
|
||||
for (count = 0, i = 0; i < ctxt->mapped_sges; i++) {
|
||||
/*
|
||||
* Unmap the DMA addr in the SGE if the lkey matches
|
||||
* the local_dma_lkey, otherwise, ignore it since it is
|
||||
* an FRMR lkey and will be unmapped later when the
|
||||
* last WR that uses it completes.
|
||||
*/
|
||||
if (ctxt->sge[i].lkey == xprt->sc_pd->local_dma_lkey) {
|
||||
atomic_dec(&xprt->sc_dma_used);
|
||||
ib_dma_unmap_page(xprt->sc_cm_id->device,
|
||||
if (ctxt->sge[i].lkey == lkey) {
|
||||
count++;
|
||||
ib_dma_unmap_page(device,
|
||||
ctxt->sge[i].addr,
|
||||
ctxt->sge[i].length,
|
||||
ctxt->direction);
|
||||
}
|
||||
}
|
||||
ctxt->mapped_sges = 0;
|
||||
atomic_sub(count, &xprt->sc_dma_used);
|
||||
}
|
||||
|
||||
void svc_rdma_put_context(struct svc_rdma_op_ctxt *ctxt, int free_pages)
|
||||
|
|
@ -600,7 +606,7 @@ int svc_rdma_post_recv(struct svcxprt_rdma *xprt, gfp_t flags)
|
|||
DMA_FROM_DEVICE);
|
||||
if (ib_dma_mapping_error(xprt->sc_cm_id->device, pa))
|
||||
goto err_put_ctxt;
|
||||
atomic_inc(&xprt->sc_dma_used);
|
||||
svc_rdma_count_mappings(xprt, ctxt);
|
||||
ctxt->sge[sge_no].addr = pa;
|
||||
ctxt->sge[sge_no].length = PAGE_SIZE;
|
||||
ctxt->sge[sge_no].lkey = xprt->sc_pd->local_dma_lkey;
|
||||
|
|
@ -642,6 +648,26 @@ int svc_rdma_repost_recv(struct svcxprt_rdma *xprt, gfp_t flags)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
svc_rdma_parse_connect_private(struct svcxprt_rdma *newxprt,
|
||||
struct rdma_conn_param *param)
|
||||
{
|
||||
const struct rpcrdma_connect_private *pmsg = param->private_data;
|
||||
|
||||
if (pmsg &&
|
||||
pmsg->cp_magic == rpcrdma_cmp_magic &&
|
||||
pmsg->cp_version == RPCRDMA_CMP_VERSION) {
|
||||
newxprt->sc_snd_w_inv = pmsg->cp_flags &
|
||||
RPCRDMA_CMP_F_SND_W_INV_OK;
|
||||
|
||||
dprintk("svcrdma: client send_size %u, recv_size %u "
|
||||
"remote inv %ssupported\n",
|
||||
rpcrdma_decode_buffer_size(pmsg->cp_send_size),
|
||||
rpcrdma_decode_buffer_size(pmsg->cp_recv_size),
|
||||
newxprt->sc_snd_w_inv ? "" : "un");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* This function handles the CONNECT_REQUEST event on a listening
|
||||
* endpoint. It is passed the cma_id for the _new_ connection. The context in
|
||||
|
|
@ -653,7 +679,8 @@ int svc_rdma_repost_recv(struct svcxprt_rdma *xprt, gfp_t flags)
|
|||
* will call the recvfrom method on the listen xprt which will accept the new
|
||||
* connection.
|
||||
*/
|
||||
static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird)
|
||||
static void handle_connect_req(struct rdma_cm_id *new_cma_id,
|
||||
struct rdma_conn_param *param)
|
||||
{
|
||||
struct svcxprt_rdma *listen_xprt = new_cma_id->context;
|
||||
struct svcxprt_rdma *newxprt;
|
||||
|
|
@ -669,9 +696,10 @@ static void handle_connect_req(struct rdma_cm_id *new_cma_id, size_t client_ird)
|
|||
new_cma_id->context = newxprt;
|
||||
dprintk("svcrdma: Creating newxprt=%p, cm_id=%p, listenxprt=%p\n",
|
||||
newxprt, newxprt->sc_cm_id, listen_xprt);
|
||||
svc_rdma_parse_connect_private(newxprt, param);
|
||||
|
||||
/* Save client advertised inbound read limit for use later in accept. */
|
||||
newxprt->sc_ord = client_ird;
|
||||
newxprt->sc_ord = param->initiator_depth;
|
||||
|
||||
/* Set the local and remote addresses in the transport */
|
||||
sa = (struct sockaddr *)&newxprt->sc_cm_id->route.addr.dst_addr;
|
||||
|
|
@ -706,8 +734,7 @@ static int rdma_listen_handler(struct rdma_cm_id *cma_id,
|
|||
dprintk("svcrdma: Connect request on cma_id=%p, xprt = %p, "
|
||||
"event = %s (%d)\n", cma_id, cma_id->context,
|
||||
rdma_event_msg(event->event), event->event);
|
||||
handle_connect_req(cma_id,
|
||||
event->param.conn.initiator_depth);
|
||||
handle_connect_req(cma_id, &event->param.conn);
|
||||
break;
|
||||
|
||||
case RDMA_CM_EVENT_ESTABLISHED:
|
||||
|
|
@ -941,6 +968,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
|
|||
struct svcxprt_rdma *listen_rdma;
|
||||
struct svcxprt_rdma *newxprt = NULL;
|
||||
struct rdma_conn_param conn_param;
|
||||
struct rpcrdma_connect_private pmsg;
|
||||
struct ib_qp_init_attr qp_attr;
|
||||
struct ib_device *dev;
|
||||
unsigned int i;
|
||||
|
|
@ -1070,7 +1098,8 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
|
|||
dev->attrs.max_fast_reg_page_list_len;
|
||||
newxprt->sc_dev_caps |= SVCRDMA_DEVCAP_FAST_REG;
|
||||
newxprt->sc_reader = rdma_read_chunk_frmr;
|
||||
}
|
||||
} else
|
||||
newxprt->sc_snd_w_inv = false;
|
||||
|
||||
/*
|
||||
* Determine if a DMA MR is required and if so, what privs are required
|
||||
|
|
@ -1094,11 +1123,20 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt)
|
|||
/* Swap out the handler */
|
||||
newxprt->sc_cm_id->event_handler = rdma_cma_handler;
|
||||
|
||||
/* Construct RDMA-CM private message */
|
||||
pmsg.cp_magic = rpcrdma_cmp_magic;
|
||||
pmsg.cp_version = RPCRDMA_CMP_VERSION;
|
||||
pmsg.cp_flags = 0;
|
||||
pmsg.cp_send_size = pmsg.cp_recv_size =
|
||||
rpcrdma_encode_buffer_size(newxprt->sc_max_req_size);
|
||||
|
||||
/* Accept Connection */
|
||||
set_bit(RDMAXPRT_CONN_PENDING, &newxprt->sc_flags);
|
||||
memset(&conn_param, 0, sizeof conn_param);
|
||||
conn_param.responder_resources = 0;
|
||||
conn_param.initiator_depth = newxprt->sc_ord;
|
||||
conn_param.private_data = &pmsg;
|
||||
conn_param.private_data_len = sizeof(pmsg);
|
||||
ret = rdma_accept(newxprt->sc_cm_id, &conn_param);
|
||||
if (ret) {
|
||||
dprintk("svcrdma: failed to accept new connection, ret=%d\n",
|
||||
|
|
|
|||
Loading…
Reference in a new issue