From: Greg Kroah-Hartman Date: Mon, 27 Aug 2012 20:19:26 +0000 (-0700) Subject: 3.4-stable patches X-Git-Tag: v3.5.4~48 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4db7439cca31ca634a8f960e0f01815383a54fd2;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches 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 --- 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 index 00000000000..31962880e5a --- /dev/null +++ b/queue-3.4/nfs-clear-key-construction-data-if-the-idmap-upcall-fails.patch @@ -0,0 +1,151 @@ +From c5066945b7ea346a11424dbeb7830b7d7d00c206 Mon Sep 17 00:00:00 2001 +From: Bryan Schumaker +Date: Thu, 9 Aug 2012 14:05:49 -0400 +Subject: NFS: Clear key construction data if the idmap upcall fails + +From: Bryan Schumaker + +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 +Tested-by: William Dauchy +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..0cb85a6c7e0 --- /dev/null +++ b/queue-3.4/nfs-return-enokey-when-the-upcall-fails-to-map-the-name.patch @@ -0,0 +1,43 @@ +From 12dfd080556124088ed61a292184947711b46cbe Mon Sep 17 00:00:00 2001 +From: Bryan Schumaker +Date: Thu, 9 Aug 2012 14:05:50 -0400 +Subject: NFS: return -ENOKEY when the upcall fails to map the name + +From: Bryan Schumaker + +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 +Tested-by: William Dauchy +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..eb70d677636 --- /dev/null +++ b/queue-3.4/nfsv3-ensure-that-do_proc_get_root-reports-errors-correctly.patch @@ -0,0 +1,33 @@ +From 086600430493e04b802bee6e5b3ce0458e4eb77f Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Mon, 20 Aug 2012 12:42:15 -0400 +Subject: NFSv3: Ensure that do_proc_get_root() reports errors correctly + +From: Trond Myklebust + +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 +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..b5b2070a4a9 --- /dev/null +++ b/queue-3.4/nfsv4.1-remove-a-bogus-bug_on-in-nfs4_layoutreturn_done.patch @@ -0,0 +1,47 @@ +From 47fbf7976e0b7d9dcdd799e2a1baba19064d9631 Mon Sep 17 00:00:00 2001 +From: Trond Myklebust +Date: Wed, 8 Aug 2012 16:03:13 -0400 +Subject: NFSv4.1: Remove a bogus BUG_ON() in nfs4_layoutreturn_done + +From: Trond Myklebust + +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 +Reported-by: Tigran Mkrtchyan +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + 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 index 00000000000..cce74ceca94 --- /dev/null +++ b/queue-3.4/pnfs-defer-release-of-pages-in-layoutget.patch @@ -0,0 +1,204 @@ +From 8554116e17eef055d9dd58a94b3427cb2ad1c317 Mon Sep 17 00:00:00 2001 +From: Idan Kedar +Date: Thu, 2 Aug 2012 11:47:10 +0300 +Subject: pnfs: defer release of pages in layoutget + +From: Idan Kedar + +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 +Signed-off-by: Benny Halevy +Signed-off-by: Trond Myklebust +Signed-off-by: Greg Kroah-Hartman + +--- + 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 */ diff --git a/queue-3.4/series b/queue-3.4/series index 1b6ff449621..76ac10f3075 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -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