]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.5-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Aug 2012 20:18:52 +0000 (13:18 -0700)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 27 Aug 2012 20:18:52 +0000 (13:18 -0700)
added patches:
nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch
nfsd4-fix-security-flavor-of-nfsv4.0-callback.patch
nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch
nfs-tear-down-caches-in-nfs_init_writepagecache-when-allocation-fails.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.5/nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch [new file with mode: 0644]
queue-3.5/nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch [new file with mode: 0644]
queue-3.5/nfs-tear-down-caches-in-nfs_init_writepagecache-when-allocation-fails.patch [new file with mode: 0644]
queue-3.5/nfsd4-fix-security-flavor-of-nfsv4.0-callback.patch [new file with mode: 0644]
queue-3.5/nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch [new file with mode: 0644]
queue-3.5/nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch [new file with mode: 0644]
queue-3.5/pnfs-defer-release-of-pages-in-layoutget.patch [new file with mode: 0644]
queue-3.5/series

diff --git a/queue-3.5/nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch b/queue-3.5/nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch
new file mode 100644 (file)
index 0000000..e63cf13
--- /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,
+ };
+@@ -619,7 +628,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;
+@@ -662,6 +672,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;
+@@ -669,15 +680,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;
+@@ -686,15 +697,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;
+ }
+@@ -778,9 +789,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.5/nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch b/queue-3.5/nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch
new file mode 100644 (file)
index 0000000..b62f923
--- /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
+@@ -763,9 +763,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);
+@@ -782,7 +781,6 @@ idmap_pipe_downcall(struct file *filp, c
+ out:
+       complete_request_key(cons, ret);
+-out_incomplete:
+       return ret;
+ }
diff --git a/queue-3.5/nfs-tear-down-caches-in-nfs_init_writepagecache-when-allocation-fails.patch b/queue-3.5/nfs-tear-down-caches-in-nfs_init_writepagecache-when-allocation-fails.patch
new file mode 100644 (file)
index 0000000..103f9e5
--- /dev/null
@@ -0,0 +1,67 @@
+From 3dd4765fce04c0b4af1e0bc4c0b10f906f95fabc Mon Sep 17 00:00:00 2001
+From: Jeff Layton <jlayton@redhat.com>
+Date: Thu, 2 Aug 2012 14:30:56 -0400
+Subject: nfs: tear down caches in nfs_init_writepagecache when allocation fails
+
+From: Jeff Layton <jlayton@redhat.com>
+
+commit 3dd4765fce04c0b4af1e0bc4c0b10f906f95fabc upstream.
+
+...and ensure that we tear down the nfs_commit_data cache too when
+unloading the module.
+
+Cc: Bryan Schumaker <bjschuma@netapp.com>
+Signed-off-by: Jeff Layton <jlayton@redhat.com>
+Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfs/write.c |   15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+--- a/fs/nfs/write.c
++++ b/fs/nfs/write.c
+@@ -1806,19 +1806,19 @@ int __init nfs_init_writepagecache(void)
+       nfs_wdata_mempool = mempool_create_slab_pool(MIN_POOL_WRITE,
+                                                    nfs_wdata_cachep);
+       if (nfs_wdata_mempool == NULL)
+-              return -ENOMEM;
++              goto out_destroy_write_cache;
+       nfs_cdata_cachep = kmem_cache_create("nfs_commit_data",
+                                            sizeof(struct nfs_commit_data),
+                                            0, SLAB_HWCACHE_ALIGN,
+                                            NULL);
+       if (nfs_cdata_cachep == NULL)
+-              return -ENOMEM;
++              goto out_destroy_write_mempool;
+       nfs_commit_mempool = mempool_create_slab_pool(MIN_POOL_COMMIT,
+                                                     nfs_wdata_cachep);
+       if (nfs_commit_mempool == NULL)
+-              return -ENOMEM;
++              goto out_destroy_commit_cache;
+       /*
+        * NFS congestion size, scale with available memory.
+@@ -1841,11 +1841,20 @@ int __init nfs_init_writepagecache(void)
+               nfs_congestion_kb = 256*1024;
+       return 0;
++
++out_destroy_commit_cache:
++      kmem_cache_destroy(nfs_cdata_cachep);
++out_destroy_write_mempool:
++      mempool_destroy(nfs_wdata_mempool);
++out_destroy_write_cache:
++      kmem_cache_destroy(nfs_wdata_cachep);
++      return -ENOMEM;
+ }
+ void nfs_destroy_writepagecache(void)
+ {
+       mempool_destroy(nfs_commit_mempool);
++      kmem_cache_destroy(nfs_cdata_cachep);
+       mempool_destroy(nfs_wdata_mempool);
+       kmem_cache_destroy(nfs_wdata_cachep);
+ }
diff --git a/queue-3.5/nfsd4-fix-security-flavor-of-nfsv4.0-callback.patch b/queue-3.5/nfsd4-fix-security-flavor-of-nfsv4.0-callback.patch
new file mode 100644 (file)
index 0000000..1d5acc0
--- /dev/null
@@ -0,0 +1,56 @@
+From 39307655a1effa8d913bba054c0e985bfaca808c Mon Sep 17 00:00:00 2001
+From: "J. Bruce Fields" <bfields@redhat.com>
+Date: Thu, 16 Aug 2012 17:01:21 -0400
+Subject: nfsd4: fix security flavor of NFSv4.0 callback
+
+From: "J. Bruce Fields" <bfields@redhat.com>
+
+commit 39307655a1effa8d913bba054c0e985bfaca808c upstream.
+
+Commit d5497fc693a446ce9100fcf4117c3f795ddfd0d2 "nfsd4: move rq_flavor
+into svc_cred" forgot to remove cl_flavor from the client, leaving two
+places (cl_flavor and cl_cred.cr_flavor) for the flavor to be stored.
+After that patch, the latter was the one that was updated, but the
+former was the one that the callback used.
+
+Symptoms were a long delay on utime().  This is because the utime()
+generated a setattr which recalled a delegation, but the cb_recall was
+ignored by the client because it had the wrong security flavor.
+
+Tested-by: Jamie Heilman <jamie@audible.transient.net>
+Reported-by: Jamie Heilman <jamie@audible.transient.net>
+Signed-off-by: J. Bruce Fields <bfields@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ fs/nfsd/nfs4callback.c |    4 ++--
+ fs/nfsd/state.h        |    1 -
+ 2 files changed, 2 insertions(+), 3 deletions(-)
+
+--- a/fs/nfsd/nfs4callback.c
++++ b/fs/nfsd/nfs4callback.c
+@@ -651,12 +651,12 @@ static int setup_callback_client(struct
+       if (clp->cl_minorversion == 0) {
+               if (!clp->cl_cred.cr_principal &&
+-                              (clp->cl_flavor >= RPC_AUTH_GSS_KRB5))
++                              (clp->cl_cred.cr_flavor >= RPC_AUTH_GSS_KRB5))
+                       return -EINVAL;
+               args.client_name = clp->cl_cred.cr_principal;
+               args.prognumber = conn->cb_prog,
+               args.protocol = XPRT_TRANSPORT_TCP;
+-              args.authflavor = clp->cl_flavor;
++              args.authflavor = clp->cl_cred.cr_flavor;
+               clp->cl_cb_ident = conn->cb_ident;
+       } else {
+               if (!conn->cb_xprt)
+--- a/fs/nfsd/state.h
++++ b/fs/nfsd/state.h
+@@ -231,7 +231,6 @@ struct nfs4_client {
+       nfs4_verifier           cl_verifier;    /* generated by client */
+       time_t                  cl_time;        /* time of last lease renewal */
+       struct sockaddr_storage cl_addr;        /* client ipaddress */
+-      u32                     cl_flavor;      /* setclientid pseudoflavor */
+       struct svc_cred         cl_cred;        /* setclientid principal */
+       clientid_t              cl_clientid;    /* generated by server */
+       nfs4_verifier           cl_confirm;     /* generated by server */
diff --git a/queue-3.5/nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch b/queue-3.5/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.5/nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch b/queue-3.5/nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch
new file mode 100644 (file)
index 0000000..d8db886
--- /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
+@@ -6300,12 +6300,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.5/pnfs-defer-release-of-pages-in-layoutget.patch b/queue-3.5/pnfs-defer-release-of-pages-in-layoutget.patch
new file mode 100644 (file)
index 0000000..7649b15
--- /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
+@@ -6164,11 +6164,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__);
+@@ -6180,9 +6227,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],
+@@ -6200,6 +6248,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
+@@ -583,9 +583,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__);
+@@ -594,20 +591,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;
+@@ -616,39 +599,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
+@@ -171,7 +171,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 7b4b489b84c74917dd25038505aa71a8dc8fbad8..daca5a8828177484b57c7b00bdea23c3e54212c0 100644 (file)
@@ -26,3 +26,10 @@ mm-hugetlbfs-correctly-populate-shared-pmd.patch
 alsa-hda-don-t-create-dysfunctional-mixer-controls-for-ca0132.patch
 alsa-hda-fix-leftover-codec-power_transition.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
+nfs-tear-down-caches-in-nfs_init_writepagecache-when-allocation-fails.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
+nfsd4-fix-security-flavor-of-nfsv4.0-callback.patch