Re: oops when copying a file from a nfs mount

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, 2012-02-03 at 18:08 -0500, J. Bruce Fields wrote:
> On Fri, Feb 03, 2012 at 11:36:04PM +0100, koen@xxxxxxxxxxxx wrote:
> > Hi,
> > 
> > Since updating from kernel 3.2.1 to 3.2.2, copying a file from a nfs mount
> > using `cp` results in a kernel oops. Copying the same file with `cat
> > /nfsmount/file > /local/file` gives no problems.
> 
> Hm, the oops is in getattr encoding, and doing a
> 
> 	gitk v3.2.1..v3.2.2 fs/nfs net/sunrpc
> 
> turns up one commit that modifies that code:
> 
> 	628fc192adbaae0c6178b9015fb916ce61d72b36 "NFSv4: include bitmap
> 	in nfsv4 get acl data"
> 
> I haven't looked at that, but maybe the problem will be obvious to
> Andy....

It is obvious: firstly acl_scratch is only needed (and allocated) if the
npages > 1. Secondly, the call to xdr_set_scratch_buffer() needs to be
done in the decoder, not the encoder...

The following patch should fix it.

8<-----------------------------------------------------------------------------------
>From 074d857ded7df109ba696859964c8d5852175dad Mon Sep 17 00:00:00 2001
From: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx>
Date: Fri, 3 Feb 2012 18:30:53 -0500
Subject: [PATCH] NFSv4: Fix an Oops in the NFSv4 getacl code

Commit bf118a342f10dafe44b14451a1392c3254629a1f (NFSv4: include bitmap
in nfsv4 get acl data) introduces the 'acl_scratch' page for the case
where we may need to decode multi-page data. However it fails to take
into account the fact that the variable may be NULL (for the case where
we're not doing multi-page decode), and it also attaches it to the
encoding xdr_stream rather than the decoding one.

The immediate result is an Oops in nfs4_xdr_enc_getacl due to the
call to page_address() with a NULL page pointer.

Signed-off-by: Trond Myklebust <Trond.Myklebust@xxxxxxxxxx>
Cc: Andy Adamson <andros@xxxxxxxxxx>
Cc: stable@xxxxxxxxxxxxxxx
---
 fs/nfs/nfs4proc.c       |    8 ++++----
 fs/nfs/nfs4xdr.c        |    3 ++-
 include/linux/nfs_xdr.h |    2 +-
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index f0c849c..d202e04 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -3575,8 +3575,8 @@ static ssize_t __nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t bu
 	}
 	if (npages > 1) {
 		/* for decoding across pages */
-		args.acl_scratch = alloc_page(GFP_KERNEL);
-		if (!args.acl_scratch)
+		res.acl_scratch = alloc_page(GFP_KERNEL);
+		if (!res.acl_scratch)
 			goto out_free;
 	}
 	args.acl_len = npages * PAGE_SIZE;
@@ -3612,8 +3612,8 @@ out_free:
 	for (i = 0; i < npages; i++)
 		if (pages[i])
 			__free_page(pages[i]);
-	if (args.acl_scratch)
-		__free_page(args.acl_scratch);
+	if (res.acl_scratch)
+		__free_page(res.acl_scratch);
 	return ret;
 }
 
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 95e92e4..c047bec 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -2522,7 +2522,6 @@ static void nfs4_xdr_enc_getacl(struct rpc_rqst *req, struct xdr_stream *xdr,
 
 	xdr_inline_pages(&req->rq_rcv_buf, replen << 2,
 		args->acl_pages, args->acl_pgbase, args->acl_len);
-	xdr_set_scratch_buffer(xdr, page_address(args->acl_scratch), PAGE_SIZE);
 
 	encode_nops(&hdr);
 }
@@ -6041,6 +6040,8 @@ nfs4_xdr_dec_getacl(struct rpc_rqst *rqstp, struct xdr_stream *xdr,
 	status = decode_putfh(xdr);
 	if (status)
 		goto out;
+	if (res->acl_scratch != NULL)
+		xdr_set_scratch_buffer(xdr, page_address(res->acl_scratch), PAGE_SIZE);
 	status = decode_getacl(xdr, rqstp, res);
 
 out:
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index a764cef..d6ba9a1 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -614,7 +614,6 @@ struct nfs_getaclargs {
 	size_t				acl_len;
 	unsigned int			acl_pgbase;
 	struct page **			acl_pages;
-	struct page *			acl_scratch;
 	struct nfs4_sequence_args 	seq_args;
 };
 
@@ -624,6 +623,7 @@ struct nfs_getaclres {
 	size_t				acl_len;
 	size_t				acl_data_offset;
 	int				acl_flags;
+	struct page *			acl_scratch;
 	struct nfs4_sequence_res	seq_res;
 };
 
-- 
1.7.7.6


-- 
Trond Myklebust
Linux NFS client maintainer

NetApp
Trond.Myklebust@xxxxxxxxxx
www.netapp.com

��.n��������+%������w��{.n�����{��w���jg��������ݢj����G�������j:+v���w�m������w�������h�����٥



[Index of Archives]     [Linux Filesystem Development]     [Linux USB Development]     [Linux Media Development]     [Video for Linux]     [Linux NILFS]     [Linux Audio Users]     [Yosemite Info]     [Linux SCSI]

  Powered by Linux