]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-posix-acl
Reenabled linux-xen, added patches for Xen Kernel Version 2.6.27.31,
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.fixes / nfs-fix-posix-acl
diff --git a/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-posix-acl b/src/patches/suse-2.6.27.31/patches.fixes/nfs-fix-posix-acl
new file mode 100644 (file)
index 0000000..0c51076
--- /dev/null
@@ -0,0 +1,174 @@
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+Subject: NFSv3: Fix posix ACL code
+References: 465854
+Patch-mainline: 2.6.29-rc7
+    
+Upstream commit ae46141ff08f1965b17c531b571953c39ce8b9e2.
+
+    Fix a memory leak due to allocation in the XDR layer. In cases where the
+    RPC call needs to be retransmitted, we end up allocating new pages without
+    clearing the old ones. Fix this by moving the allocation into
+    nfs3_proc_setacls().
+    
+    Also fix an issue discovered by Kevin Rudd, whereby the amount of memory
+    reserved for the acls in the xdr_buf->head was miscalculated, and causing
+    corruption.
+    
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de>
+---
+
+ fs/nfs/nfs3acl.c        |   27 +++++++++++++++++++++------
+ fs/nfs/nfs3xdr.c        |   34 +++++++++++++---------------------
+ include/linux/nfs_xdr.h |    2 ++
+ include/linux/nfsacl.h  |    3 +++
+ 4 files changed, 39 insertions(+), 27 deletions(-)
+
+Index: linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3acl.c
+===================================================================
+--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/nfs3acl.c
++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3acl.c
+@@ -291,7 +291,7 @@ static int nfs3_proc_setacls(struct inod
+ {
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct nfs_fattr fattr;
+-      struct page *pages[NFSACL_MAXPAGES] = { };
++      struct page *pages[NFSACL_MAXPAGES];
+       struct nfs3_setaclargs args = {
+               .inode = inode,
+               .mask = NFS_ACL,
+@@ -302,7 +302,7 @@ static int nfs3_proc_setacls(struct inod
+               .rpc_argp       = &args,
+               .rpc_resp       = &fattr,
+       };
+-      int status, count;
++      int status;
+       status = -EOPNOTSUPP;
+       if (!nfs_server_capable(inode, NFS_CAP_ACLS))
+@@ -318,6 +318,20 @@ static int nfs3_proc_setacls(struct inod
+       if (S_ISDIR(inode->i_mode)) {
+               args.mask |= NFS_DFACL;
+               args.acl_default = dfacl;
++              args.len = nfsacl_size(acl, dfacl);
++      } else
++              args.len = nfsacl_size(acl, NULL);
++
++      if (args.len > NFS_ACL_INLINE_BUFSIZE) {
++              unsigned int npages = 1 + ((args.len - 1) >> PAGE_SHIFT);
++
++              status = -ENOMEM;
++              do {
++                      args.pages[args.npages] = alloc_page(GFP_KERNEL);
++                      if (args.pages[args.npages] == NULL)
++                              goto out_freepages;
++                      args.npages++;
++              } while (args.npages < npages);
+       }
+       dprintk("NFS call setacl\n");
+@@ -327,10 +341,6 @@ static int nfs3_proc_setacls(struct inod
+       nfs_zap_acl_cache(inode);
+       dprintk("NFS reply setacl: %d\n", status);
+-      /* pages may have been allocated at the xdr layer. */
+-      for (count = 0; count < NFSACL_MAXPAGES && args.pages[count]; count++)
+-              __free_page(args.pages[count]);
+-
+       switch (status) {
+               case 0:
+                       status = nfs_refresh_inode(inode, &fattr);
+@@ -344,6 +354,11 @@ static int nfs3_proc_setacls(struct inod
+               case -ENOTSUPP:
+                       status = -EOPNOTSUPP;
+       }
++out_freepages:
++      while (args.npages != 0) {
++              args.npages--;
++              __free_page(args.pages[args.npages]);
++      }
+ out:
+       return status;
+ }
+Index: linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3xdr.c
+===================================================================
+--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/nfs3xdr.c
++++ linux-2.6.27-SLE11_BRANCH/fs/nfs/nfs3xdr.c
+@@ -82,8 +82,10 @@
+ #define NFS3_commitres_sz     (1+NFS3_wcc_data_sz+2)
+ #define ACL3_getaclargs_sz    (NFS3_fh_sz+1)
+-#define ACL3_setaclargs_sz    (NFS3_fh_sz+1+2*(2+5*3))
+-#define ACL3_getaclres_sz     (1+NFS3_post_op_attr_sz+1+2*(2+5*3))
++#define ACL3_setaclargs_sz    (NFS3_fh_sz+1+ \
++                              XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
++#define ACL3_getaclres_sz     (1+NFS3_post_op_attr_sz+1+ \
++                              XDR_QUADLEN(NFS_ACL_INLINE_BUFSIZE))
+ #define ACL3_setaclres_sz     (1+NFS3_post_op_attr_sz)
+ /*
+@@ -703,28 +705,18 @@ nfs3_xdr_setaclargs(struct rpc_rqst *req
+                    struct nfs3_setaclargs *args)
+ {
+       struct xdr_buf *buf = &req->rq_snd_buf;
+-      unsigned int base, len_in_head, len = nfsacl_size(
+-              (args->mask & NFS_ACL)   ? args->acl_access  : NULL,
+-              (args->mask & NFS_DFACL) ? args->acl_default : NULL);
+-      int count, err;
++      unsigned int base;
++      int err;
+       p = xdr_encode_fhandle(p, NFS_FH(args->inode));
+       *p++ = htonl(args->mask);
+-      base = (char *)p - (char *)buf->head->iov_base;
+-      /* put as much of the acls into head as possible. */
+-      len_in_head = min_t(unsigned int, buf->head->iov_len - base, len);
+-      len -= len_in_head;
+-      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p + (len_in_head >> 2));
+-
+-      for (count = 0; (count << PAGE_SHIFT) < len; count++) {
+-              args->pages[count] = alloc_page(GFP_KERNEL);
+-              if (!args->pages[count]) {
+-                      while (count)
+-                              __free_page(args->pages[--count]);
+-                      return -ENOMEM;
+-              }
+-      }
+-      xdr_encode_pages(buf, args->pages, 0, len);
++      req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
++      base = req->rq_slen;
++
++      if (args->npages != 0)
++              xdr_encode_pages(buf, args->pages, 0, args->len);
++      else
++              req->rq_slen += args->len;
+       err = nfsacl_encode(buf, base, args->inode,
+                           (args->mask & NFS_ACL) ?
+Index: linux-2.6.27-SLE11_BRANCH/include/linux/nfs_xdr.h
+===================================================================
+--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/nfs_xdr.h
++++ linux-2.6.27-SLE11_BRANCH/include/linux/nfs_xdr.h
+@@ -404,6 +404,8 @@ struct nfs3_setaclargs {
+       int                     mask;
+       struct posix_acl *      acl_access;
+       struct posix_acl *      acl_default;
++      size_t                  len;
++      unsigned int            npages;
+       struct page **          pages;
+ };
+Index: linux-2.6.27-SLE11_BRANCH/include/linux/nfsacl.h
+===================================================================
+--- linux-2.6.27-SLE11_BRANCH.orig/include/linux/nfsacl.h
++++ linux-2.6.27-SLE11_BRANCH/include/linux/nfsacl.h
+@@ -37,6 +37,9 @@
+ #define NFSACL_MAXPAGES               ((2*(8+12*NFS_ACL_MAX_ENTRIES) + PAGE_SIZE-1) \
+                                >> PAGE_SHIFT)
++#define NFS_ACL_MAX_ENTRIES_INLINE    (5)
++#define NFS_ACL_INLINE_BUFSIZE        ((2*(2+3*NFS_ACL_MAX_ENTRIES_INLINE)) << 2)
++
+ static inline unsigned int
+ nfsacl_size(struct posix_acl *acl_access, struct posix_acl *acl_default)
+ {