Skip to content

Commit

Permalink
svcrpc: copy cb reply instead of pages
Browse files Browse the repository at this point in the history
It's much simpler just to copy the cb reply data than to play tricks
with pages.  Callback replies will typically be very small (at least
until we implement cb_getattr, in which case files with very long ACLs
could pose a problem), so there's no loss in efficiency.

Signed-off-by: J. Bruce Fields <[email protected]>
  • Loading branch information
Trond Myklebust authored and J. Bruce Fields committed Apr 7, 2011
1 parent cc6c212 commit 586c52c
Showing 1 changed file with 56 additions and 66 deletions.
122 changes: 56 additions & 66 deletions net/sunrpc/svcsock.c
Original file line number Diff line number Diff line change
Expand Up @@ -981,57 +981,58 @@ static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
return -EAGAIN;
}

static int svc_process_calldir(struct svc_sock *svsk, struct svc_rqst *rqstp,
struct rpc_rqst **reqpp, struct kvec *vec)
static int receive_cb_reply(struct svc_sock *svsk, struct svc_rqst *rqstp)
{
struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;
struct rpc_rqst *req = NULL;
__be32 *p;
struct kvec *src, *dst;
__be32 *p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
__be32 xid;
__be32 calldir;
int len;

len = svc_recvfrom(rqstp, vec, 1, 8);
if (len < 0)
goto error;

p = (u32 *)rqstp->rq_arg.head[0].iov_base;
xid = *p++;
calldir = *p;

if (calldir == 0) {
/* REQUEST is the most common case */
vec[0] = rqstp->rq_arg.head[0];
} else {
/* REPLY */
struct rpc_xprt *bc_xprt = svsk->sk_xprt.xpt_bc_xprt;

if (bc_xprt)
req = xprt_lookup_rqst(bc_xprt, xid);

if (!req) {
printk(KERN_NOTICE
"%s: Got unrecognized reply: "
"calldir 0x%x xpt_bc_xprt %p xid %08x\n",
__func__, ntohl(calldir),
bc_xprt, xid);
vec[0] = rqstp->rq_arg.head[0];
goto out;
}
if (bc_xprt)
req = xprt_lookup_rqst(bc_xprt, xid);

memcpy(&req->rq_private_buf, &req->rq_rcv_buf,
sizeof(struct xdr_buf));
/* copy the xid and call direction */
memcpy(req->rq_private_buf.head[0].iov_base,
rqstp->rq_arg.head[0].iov_base, 8);
vec[0] = req->rq_private_buf.head[0];
if (!req) {
printk(KERN_NOTICE
"%s: Got unrecognized reply: "
"calldir 0x%x xpt_bc_xprt %p xid %08x\n",
__func__, ntohl(calldir),
bc_xprt, xid);
return -EAGAIN;
}
out:
vec[0].iov_base += 8;
vec[0].iov_len -= 8;
len = svsk->sk_reclen - 8;
error:
*reqpp = req;
return len;

memcpy(&req->rq_private_buf, &req->rq_rcv_buf, sizeof(struct xdr_buf));
/*
* XXX!: cheating for now! Only copying HEAD.
* But we know this is good enough for now (in fact, for any
* callback reply in the forseeable future).
*/
dst = &req->rq_private_buf.head[0];
src = &rqstp->rq_arg.head[0];
if (dst->iov_len < src->iov_len)
return -EAGAIN; /* whatever; just giving up. */
memcpy(dst->iov_base, src->iov_base, src->iov_len);
xprt_complete_rqst(req->rq_task, svsk->sk_reclen);
rqstp->rq_arg.len = 0;
return 0;
}

static int copy_pages_to_kvecs(struct kvec *vec, struct page **pages, int len)
{
int i = 0;
int t = 0;

while (t < len) {
vec[i].iov_base = page_address(pages[i]);
vec[i].iov_len = PAGE_SIZE;
i++;
t += PAGE_SIZE;
}
return i;
}

/*
Expand All @@ -1044,8 +1045,8 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
struct svc_serv *serv = svsk->sk_xprt.xpt_server;
int len;
struct kvec *vec;
struct rpc_rqst *req = NULL;
unsigned int vlen;
__be32 *p;
__be32 calldir;
int pnum;

dprintk("svc: tcp_recv %p data %d conn %d close %d\n",
Expand All @@ -1058,35 +1059,17 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
goto error;

vec = rqstp->rq_vec;
vec[0] = rqstp->rq_arg.head[0];
vlen = PAGE_SIZE;

len = svc_process_calldir(svsk, rqstp, &req, vec);
if (len < 0)
goto err_again;
vlen -= 8;

pnum = 1;
while (vlen < svsk->sk_reclen - 8) {
vec[pnum].iov_base = (req) ?
page_address(req->rq_private_buf.pages[pnum - 1]) :
page_address(rqstp->rq_pages[pnum]);
vec[pnum].iov_len = PAGE_SIZE;
pnum++;
vlen += PAGE_SIZE;
}
pnum = copy_pages_to_kvecs(&vec[0], &rqstp->rq_pages[0],
svsk->sk_reclen);

rqstp->rq_respages = &rqstp->rq_pages[pnum];

/* Now receive data */
len = svc_recvfrom(rqstp, vec, pnum, svsk->sk_reclen - 8);
len = svc_recvfrom(rqstp, vec, pnum, svsk->sk_reclen);
if (len < 0)
goto err_again;

if (req) {
xprt_complete_rqst(req->rq_task, svsk->sk_reclen);
rqstp->rq_arg.len = 0;
goto out;
}
dprintk("svc: TCP complete record (%d bytes)\n", svsk->sk_reclen);
rqstp->rq_arg.len = svsk->sk_reclen;
rqstp->rq_arg.page_base = 0;
Expand All @@ -1099,7 +1082,14 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
rqstp->rq_xprt_ctxt = NULL;
rqstp->rq_prot = IPPROTO_TCP;

out:
p = (__be32 *)rqstp->rq_arg.head[0].iov_base;
calldir = p[1];
if (calldir) {
len = receive_cb_reply(svsk, rqstp);
if (len < 0)
goto err_again;
}

/* Reset TCP read info */
svsk->sk_reclen = 0;
svsk->sk_tcplen = 0;
Expand Down

0 comments on commit 586c52c

Please sign in to comment.