diff mbox

[3.19.y-ckt,stable] Patch "SUNRPC: Fix callback channel" has been added to staging queue

Message ID 1450221427-5860-1-git-send-email-kamal@canonical.com
State New
Headers show

Commit Message

Kamal Mostafa Dec. 15, 2015, 11:17 p.m. UTC
This is a note to let you know that I have just added a patch titled

    SUNRPC: Fix callback channel

to the linux-3.19.y-queue branch of the 3.19.y-ckt extended stable tree 
which can be found at:

    http://kernel.ubuntu.com/git/ubuntu/linux.git/log/?h=linux-3.19.y-queue

This patch is scheduled to be released in version 3.19.8-ckt12.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.19.y-ckt tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Kamal

------

From decffec23eee382c9fcfc0f32a0b0e939bf5c043 Mon Sep 17 00:00:00 2001
From: Trond Myklebust <trond.myklebust@primarydata.com>
Date: Mon, 7 Dec 2015 12:52:23 -0800
Subject: SUNRPC: Fix callback channel

commit 756b9b37cfb2e3dc76b2e43a8c097402ac736e07 upstream.

The NFSv4.1 callback channel is currently broken because the receive
message will keep shrinking because the backchannel receive buffer size
never gets reset.
The easiest solution to this problem is instead of changing the receive
buffer, to rather adjust the copied request.

Fixes: 38b7631fbe42 ("nfs4: limit callback decoding to received bytes")
Cc: Benjamin Coddington <bcodding@redhat.com>
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
---
 fs/nfs/callback_xdr.c         |  7 ++-----
 net/sunrpc/backchannel_rqst.c |  8 --------
 net/sunrpc/svc.c              | 12 ++++++++++++
 3 files changed, 14 insertions(+), 13 deletions(-)

--
1.9.1
diff mbox

Patch

diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c
index 1e36635..02f8d09 100644
--- a/fs/nfs/callback_xdr.c
+++ b/fs/nfs/callback_xdr.c
@@ -76,8 +76,7 @@  static __be32 *read_buf(struct xdr_stream *xdr, int nbytes)

 	p = xdr_inline_decode(xdr, nbytes);
 	if (unlikely(p == NULL))
-		printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed "
-							"or truncated request.\n");
+		printk(KERN_WARNING "NFS: NFSv4 callback reply buffer overflowed!\n");
 	return p;
 }

@@ -893,7 +892,6 @@  static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r
 	struct cb_compound_hdr_arg hdr_arg = { 0 };
 	struct cb_compound_hdr_res hdr_res = { NULL };
 	struct xdr_stream xdr_in, xdr_out;
-	struct xdr_buf *rq_arg = &rqstp->rq_arg;
 	__be32 *p, status;
 	struct cb_process_state cps = {
 		.drc_status = 0,
@@ -905,8 +903,7 @@  static __be32 nfs4_callback_compound(struct svc_rqst *rqstp, void *argp, void *r

 	dprintk("%s: start\n", __func__);

-	rq_arg->len = rq_arg->head[0].iov_len + rq_arg->page_len;
-	xdr_init_decode(&xdr_in, rq_arg, rq_arg->head[0].iov_base);
+	xdr_init_decode(&xdr_in, &rqstp->rq_arg, rqstp->rq_arg.head[0].iov_base);

 	p = (__be32*)((char *)rqstp->rq_res.head[0].iov_base + rqstp->rq_res.head[0].iov_len);
 	xdr_init_encode(&xdr_out, &rqstp->rq_res, p);
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c
index b57cee1..28504df 100644
--- a/net/sunrpc/backchannel_rqst.c
+++ b/net/sunrpc/backchannel_rqst.c
@@ -308,19 +308,11 @@  void xprt_complete_bc_request(struct rpc_rqst *req, uint32_t copied)
 {
 	struct rpc_xprt *xprt = req->rq_xprt;
 	struct svc_serv *bc_serv = xprt->bc_serv;
-	struct xdr_buf *rq_rcv_buf = &req->rq_rcv_buf;

 	spin_lock(&xprt->bc_pa_lock);
 	list_del(&req->rq_bc_pa_list);
 	spin_unlock(&xprt->bc_pa_lock);

-	if (copied <= rq_rcv_buf->head[0].iov_len) {
-		rq_rcv_buf->head[0].iov_len = copied;
-		rq_rcv_buf->page_len = 0;
-	} else {
-		rq_rcv_buf->page_len = copied - rq_rcv_buf->head[0].iov_len;
-	}
-
 	req->rq_private_buf.len = copied;
 	set_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state);

diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index b59b6a7..afb732a 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -1361,7 +1361,19 @@  bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req,
 	memcpy(&rqstp->rq_addr, &req->rq_xprt->addr, rqstp->rq_addrlen);
 	memcpy(&rqstp->rq_arg, &req->rq_rcv_buf, sizeof(rqstp->rq_arg));
 	memcpy(&rqstp->rq_res, &req->rq_snd_buf, sizeof(rqstp->rq_res));
+
+	/* Adjust the argument buffer length */
 	rqstp->rq_arg.len = req->rq_private_buf.len;
+	if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len) {
+		rqstp->rq_arg.head[0].iov_len = rqstp->rq_arg.len;
+		rqstp->rq_arg.page_len = 0;
+	} else if (rqstp->rq_arg.len <= rqstp->rq_arg.head[0].iov_len +
+			rqstp->rq_arg.page_len)
+		rqstp->rq_arg.page_len = rqstp->rq_arg.len -
+			rqstp->rq_arg.head[0].iov_len;
+	else
+		rqstp->rq_arg.len = rqstp->rq_arg.head[0].iov_len +
+			rqstp->rq_arg.page_len;

 	/* reset result send buffer "put" position */
 	resv->iov_len = 0;