]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.4-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Aug 2012 20:19:26 +0000 (13:19 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Aug 2012 20:19:26 +0000 (13:19 -0700)
added patches:
nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch
nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch
nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch
nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch
pnfs-defer-release-of-pages-in-layoutget.patch

queue-3.4/nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch [new file with mode: 0644]
queue-3.4/nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch [new file with mode: 0644]
queue-3.4/nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch [new file with mode: 0644]
queue-3.4/nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch [new file with mode: 0644]
queue-3.4/pnfs-defer-release-of-pages-in-layoutget.patch [new file with mode: 0644]
queue-3.4/series

diff --git a/queue-3.4/nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch b/queue-3.4/nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch
new file mode 100644 (file)
index 0000000..3196288
--- /dev/null
@@ -0,0 +1,151 @@
+From c5066945b7ea346a11424dbeb7830b7d7d00c206 Mon Sep 17 00:00:00 2001
+From: Bryan Schumaker <bjschuma@netapp.com>
+Date: Thu, 9 Aug 2012 14:05:49 -0400
+Subject: NFS: Clear key construction data if the idmap upcall fails
+
+From: Bryan Schumaker <bjschuma@netapp.com>
+
+commit c5066945b7ea346a11424dbeb7830b7d7d00c206 upstream.
+
+idmap_pipe_downcall already clears this field if the upcall succeeds,
+but if it fails (rpc.idmapd isn't running) the field will still be set
+on the next call triggering a BUG_ON().  This patch tries to handle all
+possible ways that the upcall could fail and clear the idmap key data
+for each one.
+
+Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
+Tested-by: William Dauchy <wdauchy@gmail.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/idmap.c |   56 ++++++++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 42 insertions(+), 14 deletions(-)
+
+--- a/fs/nfs/idmap.c
++++ b/fs/nfs/idmap.c
+@@ -63,6 +63,12 @@ struct idmap {
+       struct mutex            idmap_mutex;
+ };
++struct idmap_legacy_upcalldata {
++      struct rpc_pipe_msg pipe_msg;
++      struct idmap_msg idmap_msg;
++      struct idmap *idmap;
++};
++
+ /**
+  * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
+  * @fattr: fully initialised struct nfs_fattr
+@@ -326,6 +332,7 @@ static ssize_t nfs_idmap_get_key(const c
+               ret = nfs_idmap_request_key(&key_type_id_resolver_legacy,
+                                           name, namelen, type, data,
+                                           data_size, idmap);
++              idmap->idmap_key_cons = NULL;
+               mutex_unlock(&idmap->idmap_mutex);
+       }
+       return ret;
+@@ -383,11 +390,13 @@ static const match_table_t nfs_idmap_tok
+ static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
+ static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
+                                  size_t);
++static void idmap_release_pipe(struct inode *);
+ static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
+ static const struct rpc_pipe_ops idmap_upcall_ops = {
+       .upcall         = rpc_pipe_generic_upcall,
+       .downcall       = idmap_pipe_downcall,
++      .release_pipe   = idmap_release_pipe,
+       .destroy_msg    = idmap_pipe_destroy_msg,
+ };
+@@ -603,7 +612,8 @@ void nfs_idmap_quit(void)
+       nfs_idmap_quit_keyring();
+ }
+-static int nfs_idmap_prepare_message(char *desc, struct idmap_msg *im,
++static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
++                                   struct idmap_msg *im,
+                                    struct rpc_pipe_msg *msg)
+ {
+       substring_t substr;
+@@ -646,6 +656,7 @@ static int nfs_idmap_legacy_upcall(struc
+                                  const char *op,
+                                  void *aux)
+ {
++      struct idmap_legacy_upcalldata *data;
+       struct rpc_pipe_msg *msg;
+       struct idmap_msg *im;
+       struct idmap *idmap = (struct idmap *)aux;
+@@ -653,15 +664,15 @@ static int nfs_idmap_legacy_upcall(struc
+       int ret = -ENOMEM;
+       /* msg and im are freed in idmap_pipe_destroy_msg */
+-      msg = kmalloc(sizeof(*msg), GFP_KERNEL);
+-      if (!msg)
+-              goto out0;
+-
+-      im = kmalloc(sizeof(*im), GFP_KERNEL);
+-      if (!im)
++      data = kmalloc(sizeof(*data), GFP_KERNEL);
++      if (!data)
+               goto out1;
+-      ret = nfs_idmap_prepare_message(key->description, im, msg);
++      msg = &data->pipe_msg;
++      im = &data->idmap_msg;
++      data->idmap = idmap;
++
++      ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
+       if (ret < 0)
+               goto out2;
+@@ -670,15 +681,15 @@ static int nfs_idmap_legacy_upcall(struc
+       ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
+       if (ret < 0)
+-              goto out2;
++              goto out3;
+       return ret;
++out3:
++      idmap->idmap_key_cons = NULL;
+ out2:
+-      kfree(im);
++      kfree(data);
+ out1:
+-      kfree(msg);
+-out0:
+       complete_request_key(cons, ret);
+       return ret;
+ }
+@@ -762,9 +773,26 @@ out_incomplete:
+ static void
+ idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
+ {
++      struct idmap_legacy_upcalldata *data = container_of(msg,
++                      struct idmap_legacy_upcalldata,
++                      pipe_msg);
++      struct idmap *idmap = data->idmap;
++      struct key_construction *cons;
++      if (msg->errno) {
++              cons = ACCESS_ONCE(idmap->idmap_key_cons);
++              idmap->idmap_key_cons = NULL;
++              complete_request_key(cons, msg->errno);
++      }
+       /* Free memory allocated in nfs_idmap_legacy_upcall() */
+-      kfree(msg->data);
+-      kfree(msg);
++      kfree(data);
++}
++
++static void
++idmap_release_pipe(struct inode *inode)
++{
++      struct rpc_inode *rpci = RPC_I(inode);
++      struct idmap *idmap = (struct idmap *)rpci->private;
++      idmap->idmap_key_cons = NULL;
+ }
+ int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, __u32 *uid)
diff --git a/queue-3.4/nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch b/queue-3.4/nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch
new file mode 100644 (file)
index 0000000..0cb85a6
--- /dev/null
@@ -0,0 +1,43 @@
+From 12dfd080556124088ed61a292184947711b46cbe Mon Sep 17 00:00:00 2001
+From: Bryan Schumaker <bjschuma@netapp.com>
+Date: Thu, 9 Aug 2012 14:05:50 -0400
+Subject: NFS: return -ENOKEY when the upcall fails to map the name
+
+From: Bryan Schumaker <bjschuma@netapp.com>
+
+commit 12dfd080556124088ed61a292184947711b46cbe upstream.
+
+This allows the normal error-paths to handle the error, rather than
+making a special call to complete_request_key() just for this instance.
+
+Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
+Tested-by: William Dauchy <wdauchy@gmail.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/idmap.c |    6 ++----
+ 1 file changed, 2 insertions(+), 4 deletions(-)
+
+--- a/fs/nfs/idmap.c
++++ b/fs/nfs/idmap.c
+@@ -747,9 +747,8 @@ idmap_pipe_downcall(struct file *filp, c
+       }
+       if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
+-              ret = mlen;
+-              complete_request_key(cons, -ENOKEY);
+-              goto out_incomplete;
++              ret = -ENOKEY;
++              goto out;
+       }
+       namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
+@@ -766,7 +765,6 @@ idmap_pipe_downcall(struct file *filp, c
+ out:
+       complete_request_key(cons, ret);
+-out_incomplete:
+       return ret;
+ }
diff --git a/queue-3.4/nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch b/queue-3.4/nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch
new file mode 100644 (file)
index 0000000..eb70d67
--- /dev/null
@@ -0,0 +1,33 @@
+From 086600430493e04b802bee6e5b3ce0458e4eb77f Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+Date: Mon, 20 Aug 2012 12:42:15 -0400
+Subject: NFSv3: Ensure that do_proc_get_root() reports errors correctly
+
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+
+commit 086600430493e04b802bee6e5b3ce0458e4eb77f upstream.
+
+If the rpc call to NFS3PROC_FSINFO fails, then we need to report that
+error so that the mount fails. Otherwise we can end up with a
+superblock with completely unusable values for block sizes, maxfilesize,
+etc.
+
+Reported-by: Yuanming Chen <hikvision_linux@163.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs3proc.c |    2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/fs/nfs/nfs3proc.c
++++ b/fs/nfs/nfs3proc.c
+@@ -69,7 +69,7 @@ do_proc_get_root(struct rpc_clnt *client
+       nfs_fattr_init(info->fattr);
+       status = rpc_call_sync(client, &msg, 0);
+       dprintk("%s: reply fsinfo: %d\n", __func__, status);
+-      if (!(info->fattr->valid & NFS_ATTR_FATTR)) {
++      if (status == 0 && !(info->fattr->valid & NFS_ATTR_FATTR)) {
+               msg.rpc_proc = &nfs3_procedures[NFS3PROC_GETATTR];
+               msg.rpc_resp = info->fattr;
+               status = rpc_call_sync(client, &msg, 0);
diff --git a/queue-3.4/nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch b/queue-3.4/nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch
new file mode 100644 (file)
index 0000000..b5b2070
--- /dev/null
@@ -0,0 +1,47 @@
+From 47fbf7976e0b7d9dcdd799e2a1baba19064d9631 Mon Sep 17 00:00:00 2001
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+Date: Wed, 8 Aug 2012 16:03:13 -0400
+Subject: NFSv4.1: Remove a bogus BUG_ON() in nfs4_layoutreturn_done
+
+From: Trond Myklebust <Trond.Myklebust@netapp.com>
+
+commit 47fbf7976e0b7d9dcdd799e2a1baba19064d9631 upstream.
+
+Ever since commit 0a57cdac3f (NFSv4.1 send layoutreturn to fence
+disconnected data server) we've been sending layoutreturn calls
+while there is potentially still outstanding I/O to the data
+servers. The reason we do this is to avoid races between replayed
+writes to the MDS and the original writes to the DS.
+
+When this happens, the BUG_ON() in nfs4_layoutreturn_done can
+be triggered because it assumes that we would never call
+layoutreturn without knowing that all I/O to the DS is
+finished. The fix is to remove the BUG_ON() now that the
+assumptions behind the test are obsolete.
+
+Reported-by: Boaz Harrosh <bharrosh@panasas.com>
+Reported-by: Tigran Mkrtchyan <tigran.mkrtchyan@desy.de>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs4proc.c |    8 ++------
+ 1 file changed, 2 insertions(+), 6 deletions(-)
+
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -6102,12 +6102,8 @@ static void nfs4_layoutreturn_done(struc
+               return;
+       }
+       spin_lock(&lo->plh_inode->i_lock);
+-      if (task->tk_status == 0) {
+-              if (lrp->res.lrs_present) {
+-                      pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+-              } else
+-                      BUG_ON(!list_empty(&lo->plh_segs));
+-      }
++      if (task->tk_status == 0 && lrp->res.lrs_present)
++              pnfs_set_layout_stateid(lo, &lrp->res.stateid, true);
+       lo->plh_block_lgets--;
+       spin_unlock(&lo->plh_inode->i_lock);
+       dprintk("<-- %s\n", __func__);
diff --git a/queue-3.4/pnfs-defer-release-of-pages-in-layoutget.patch b/queue-3.4/pnfs-defer-release-of-pages-in-layoutget.patch
new file mode 100644 (file)
index 0000000..cce74ce
--- /dev/null
@@ -0,0 +1,204 @@
+From 8554116e17eef055d9dd58a94b3427cb2ad1c317 Mon Sep 17 00:00:00 2001
+From: Idan Kedar <idank@tonian.com>
+Date: Thu, 2 Aug 2012 11:47:10 +0300
+Subject: pnfs: defer release of pages in layoutget
+
+From: Idan Kedar <idank@tonian.com>
+
+commit 8554116e17eef055d9dd58a94b3427cb2ad1c317 upstream.
+
+we have encountered a bug whereby reading a lot of files (copying
+fedora's /bin) from a pNFS mount and hitting Ctrl+C in the middle caused
+a general protection fault in xdr_shrink_bufhead. this function is
+called when decoding the response from LAYOUTGET. the decoding is done
+by a worker thread, and the caller of LAYOUTGET waits for the worker
+thread to complete.
+
+hitting Ctrl+C caused the synchronous wait to end and the next thing the
+caller does is to free the pages, so when the worker thread calls
+xdr_shrink_bufhead, the pages are gone. therefore, the cleanup of these
+pages has been moved to nfs4_layoutget_release.
+
+Signed-off-by: Idan Kedar <idank@tonian.com>
+Signed-off-by: Benny Halevy <bhalevy@tonian.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/nfs4proc.c |   57 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
+ fs/nfs/pnfs.c     |   39 ------------------------------------
+ fs/nfs/pnfs.h     |    2 -
+ 3 files changed, 58 insertions(+), 40 deletions(-)
+
+--- a/fs/nfs/nfs4proc.c
++++ b/fs/nfs/nfs4proc.c
+@@ -5966,11 +5966,58 @@ static void nfs4_layoutget_done(struct r
+       dprintk("<-- %s\n", __func__);
+ }
++static size_t max_response_pages(struct nfs_server *server)
++{
++      u32 max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
++      return nfs_page_array_len(0, max_resp_sz);
++}
++
++static void nfs4_free_pages(struct page **pages, size_t size)
++{
++      int i;
++
++      if (!pages)
++              return;
++
++      for (i = 0; i < size; i++) {
++              if (!pages[i])
++                      break;
++              __free_page(pages[i]);
++      }
++      kfree(pages);
++}
++
++static struct page **nfs4_alloc_pages(size_t size, gfp_t gfp_flags)
++{
++      struct page **pages;
++      int i;
++
++      pages = kcalloc(size, sizeof(struct page *), gfp_flags);
++      if (!pages) {
++              dprintk("%s: can't alloc array of %zu pages\n", __func__, size);
++              return NULL;
++      }
++
++      for (i = 0; i < size; i++) {
++              pages[i] = alloc_page(gfp_flags);
++              if (!pages[i]) {
++                      dprintk("%s: failed to allocate page\n", __func__);
++                      nfs4_free_pages(pages, size);
++                      return NULL;
++              }
++      }
++
++      return pages;
++}
++
+ static void nfs4_layoutget_release(void *calldata)
+ {
+       struct nfs4_layoutget *lgp = calldata;
++      struct nfs_server *server = NFS_SERVER(lgp->args.inode);
++      size_t max_pages = max_response_pages(server);
+       dprintk("--> %s\n", __func__);
++      nfs4_free_pages(lgp->args.layout.pages, max_pages);
+       put_nfs_open_context(lgp->args.ctx);
+       kfree(calldata);
+       dprintk("<-- %s\n", __func__);
+@@ -5982,9 +6029,10 @@ static const struct rpc_call_ops nfs4_la
+       .rpc_release = nfs4_layoutget_release,
+ };
+-int nfs4_proc_layoutget(struct nfs4_layoutget *lgp)
++int nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
+ {
+       struct nfs_server *server = NFS_SERVER(lgp->args.inode);
++      size_t max_pages = max_response_pages(server);
+       struct rpc_task *task;
+       struct rpc_message msg = {
+               .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LAYOUTGET],
+@@ -6002,6 +6050,13 @@ int nfs4_proc_layoutget(struct nfs4_layo
+       dprintk("--> %s\n", __func__);
++      lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
++      if (!lgp->args.layout.pages) {
++              nfs4_layoutget_release(lgp);
++              return -ENOMEM;
++      }
++      lgp->args.layout.pglen = max_pages * PAGE_SIZE;
++
+       lgp->res.layoutp = &lgp->args.layout;
+       lgp->res.seq_res.sr_slot = NULL;
+       nfs41_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
+--- a/fs/nfs/pnfs.c
++++ b/fs/nfs/pnfs.c
+@@ -574,9 +574,6 @@ send_layoutget(struct pnfs_layout_hdr *l
+       struct nfs_server *server = NFS_SERVER(ino);
+       struct nfs4_layoutget *lgp;
+       struct pnfs_layout_segment *lseg = NULL;
+-      struct page **pages = NULL;
+-      int i;
+-      u32 max_resp_sz, max_pages;
+       dprintk("--> %s\n", __func__);
+@@ -585,20 +582,6 @@ send_layoutget(struct pnfs_layout_hdr *l
+       if (lgp == NULL)
+               return NULL;
+-      /* allocate pages for xdr post processing */
+-      max_resp_sz = server->nfs_client->cl_session->fc_attrs.max_resp_sz;
+-      max_pages = nfs_page_array_len(0, max_resp_sz);
+-
+-      pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags);
+-      if (!pages)
+-              goto out_err_free;
+-
+-      for (i = 0; i < max_pages; i++) {
+-              pages[i] = alloc_page(gfp_flags);
+-              if (!pages[i])
+-                      goto out_err_free;
+-      }
+-
+       lgp->args.minlength = PAGE_CACHE_SIZE;
+       if (lgp->args.minlength > range->length)
+               lgp->args.minlength = range->length;
+@@ -607,39 +590,19 @@ send_layoutget(struct pnfs_layout_hdr *l
+       lgp->args.type = server->pnfs_curr_ld->id;
+       lgp->args.inode = ino;
+       lgp->args.ctx = get_nfs_open_context(ctx);
+-      lgp->args.layout.pages = pages;
+-      lgp->args.layout.pglen = max_pages * PAGE_SIZE;
+       lgp->lsegpp = &lseg;
+       lgp->gfp_flags = gfp_flags;
+       /* Synchronously retrieve layout information from server and
+        * store in lseg.
+        */
+-      nfs4_proc_layoutget(lgp);
++      nfs4_proc_layoutget(lgp, gfp_flags);
+       if (!lseg) {
+               /* remember that LAYOUTGET failed and suspend trying */
+               set_bit(lo_fail_bit(range->iomode), &lo->plh_flags);
+       }
+-      /* free xdr pages */
+-      for (i = 0; i < max_pages; i++)
+-              __free_page(pages[i]);
+-      kfree(pages);
+-
+       return lseg;
+-
+-out_err_free:
+-      /* free any allocated xdr pages, lgp as it's not used */
+-      if (pages) {
+-              for (i = 0; i < max_pages; i++) {
+-                      if (!pages[i])
+-                              break;
+-                      __free_page(pages[i]);
+-              }
+-              kfree(pages);
+-      }
+-      kfree(lgp);
+-      return NULL;
+ }
+ /* Initiates a LAYOUTRETURN(FILE) */
+--- a/fs/nfs/pnfs.h
++++ b/fs/nfs/pnfs.h
+@@ -161,7 +161,7 @@ extern int nfs4_proc_getdevicelist(struc
+                                  struct pnfs_devicelist *devlist);
+ extern int nfs4_proc_getdeviceinfo(struct nfs_server *server,
+                                  struct pnfs_device *dev);
+-extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp);
++extern int nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags);
+ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp);
+ /* pnfs.c */
index 1b6ff4496215712a9938a213fa72a70c8ab30188..76ac10f30756db3c22e21c461cb112949d7f34b7 100644 (file)
@@ -22,3 +22,8 @@ usb-winbond-remove-__devinit-from-the-struct-usb_device_id-table.patch
 mm-hugetlbfs-correctly-populate-shared-pmd.patch
 alsa-hda-don-t-create-dysfunctional-mixer-controls-for-ca0132.patch
 target-fix-null-pointer-dereference-bug-alloc_page-fails-to-get-memory.patch
+nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch
+pnfs-defer-release-of-pages-in-layoutget.patch
+nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch
+nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch
+nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch