From 97e47fa11deae10ae72aa1109e700565c57152f5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 16 Sep 2013 10:57:01 -0400 Subject: nfsd: switch to %p[dD] Signed-off-by: Al Viro --- fs/nfsd/nfs4recover.c | 12 ++++++------ fs/nfsd/nfs4state.c | 15 ++++++--------- fs/nfsd/nfsfh.c | 28 +++++++++++++--------------- fs/nfsd/nfsfh.h | 4 ++-- fs/nfsd/vfs.c | 9 ++++----- 5 files changed, 31 insertions(+), 37 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c index e0a65a9..9c271f4 100644 --- a/fs/nfsd/nfs4recover.c +++ b/fs/nfsd/nfs4recover.c @@ -385,8 +385,8 @@ purge_old(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) status = vfs_rmdir(parent->d_inode, child); if (status) - printk("failed to remove client recovery directory %s\n", - child->d_name.name); + printk("failed to remove client recovery directory %pd\n", + child); /* Keep trying, success or failure: */ return 0; } @@ -410,15 +410,15 @@ out: nfs4_release_reclaim(nn); if (status) printk("nfsd4: failed to purge old clients from recovery" - " directory %s\n", nn->rec_file->f_path.dentry->d_name.name); + " directory %pD\n", nn->rec_file); } static int load_recdir(struct dentry *parent, struct dentry *child, struct nfsd_net *nn) { if (child->d_name.len != HEXDIR_LEN - 1) { - printk("nfsd4: illegal name %s in recovery directory\n", - child->d_name.name); + printk("nfsd4: illegal name %pd in recovery directory\n", + child); /* Keep trying; maybe the others are OK: */ return 0; } @@ -437,7 +437,7 @@ nfsd4_recdir_load(struct net *net) { status = nfsd4_list_rec_dir(load_recdir, nn); if (status) printk("nfsd4: failed loading clients from recovery" - " directory %s\n", nn->rec_file->f_path.dentry->d_name.name); + " directory %pD\n", nn->rec_file); return status; } diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 0874998..a601fd4 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3843,9 +3843,8 @@ nfsd4_open_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfs4_ol_stateid *stp; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); - dprintk("NFSD: nfsd4_open_confirm on file %.*s\n", - (int)cstate->current_fh.fh_dentry->d_name.len, - cstate->current_fh.fh_dentry->d_name.name); + dprintk("NFSD: nfsd4_open_confirm on file %pd\n", + cstate->current_fh.fh_dentry); status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0); if (status) @@ -3922,9 +3921,8 @@ nfsd4_open_downgrade(struct svc_rqst *rqstp, struct nfs4_ol_stateid *stp; struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id); - dprintk("NFSD: nfsd4_open_downgrade on file %.*s\n", - (int)cstate->current_fh.fh_dentry->d_name.len, - cstate->current_fh.fh_dentry->d_name.name); + dprintk("NFSD: nfsd4_open_downgrade on file %pd\n", + cstate->current_fh.fh_dentry); /* We don't yet support WANT bits: */ if (od->od_deleg_want) @@ -3980,9 +3978,8 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct net *net = SVC_NET(rqstp); struct nfsd_net *nn = net_generic(net, nfsd_net_id); - dprintk("NFSD: nfsd4_close on file %.*s\n", - (int)cstate->current_fh.fh_dentry->d_name.len, - cstate->current_fh.fh_dentry->d_name.name); + dprintk("NFSD: nfsd4_close on file %pd\n", + cstate->current_fh.fh_dentry); nfs4_lock_state(); status = nfs4_preprocess_seqid_op(cstate, close->cl_seqid, diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 814afaa..3d0e15a 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -47,7 +47,7 @@ static int nfsd_acceptable(void *expv, struct dentry *dentry) tdentry = parent; } if (tdentry != exp->ex_path.dentry) - dprintk("nfsd_acceptable failed at %p %s\n", tdentry, tdentry->d_name.name); + dprintk("nfsd_acceptable failed at %p %pd\n", tdentry, tdentry); rv = (tdentry == exp->ex_path.dentry); dput(tdentry); return rv; @@ -253,8 +253,8 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp) if (S_ISDIR(dentry->d_inode->i_mode) && (dentry->d_flags & DCACHE_DISCONNECTED)) { - printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %pd2\n", + dentry); } fhp->fh_dentry = dentry; @@ -361,10 +361,9 @@ skip_pseudoflavor_check: error = nfsd_permission(rqstp, exp, dentry, access); if (error) { - dprintk("fh_verify: %s/%s permission failure, " + dprintk("fh_verify: %pd2 permission failure, " "acc=%x, error=%d\n", - dentry->d_parent->d_name.name, - dentry->d_name.name, + dentry, access, ntohl(error)); } out: @@ -514,14 +513,13 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, */ struct inode * inode = dentry->d_inode; - struct dentry *parent = dentry->d_parent; __u32 *datap; dev_t ex_dev = exp_sb(exp)->s_dev; - dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %s/%s, ino=%ld)\n", + dprintk("nfsd: fh_compose(exp %02x:%02x/%ld %pd2, ino=%ld)\n", MAJOR(ex_dev), MINOR(ex_dev), (long) exp->ex_path.dentry->d_inode->i_ino, - parent->d_name.name, dentry->d_name.name, + dentry, (inode ? inode->i_ino : 0)); /* Choose filehandle version and fsid type based on @@ -534,13 +532,13 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry, fh_put(ref_fh); if (fhp->fh_locked || fhp->fh_dentry) { - printk(KERN_ERR "fh_compose: fh %s/%s not initialized!\n", - parent->d_name.name, dentry->d_name.name); + printk(KERN_ERR "fh_compose: fh %pd2 not initialized!\n", + dentry); } if (fhp->fh_maxsize < NFS_FHSIZE) - printk(KERN_ERR "fh_compose: called with maxsize %d! %s/%s\n", + printk(KERN_ERR "fh_compose: called with maxsize %d! %pd2\n", fhp->fh_maxsize, - parent->d_name.name, dentry->d_name.name); + dentry); fhp->fh_dentry = dget(dentry); /* our internal copy */ fhp->fh_export = exp; @@ -613,8 +611,8 @@ out_bad: printk(KERN_ERR "fh_update: fh not verified!\n"); goto out; out_negative: - printk(KERN_ERR "fh_update: %s/%s still negative!\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + printk(KERN_ERR "fh_update: %pd2 still negative!\n", + dentry); goto out; } diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h index e5e6707..4775bc4 100644 --- a/fs/nfsd/nfsfh.h +++ b/fs/nfsd/nfsfh.h @@ -173,8 +173,8 @@ fh_lock_nested(struct svc_fh *fhp, unsigned int subclass) BUG_ON(!dentry); if (fhp->fh_locked) { - printk(KERN_WARNING "fh_lock: %s/%s already locked!\n", - dentry->d_parent->d_name.name, dentry->d_name.name); + printk(KERN_WARNING "fh_lock: %pd2 already locked!\n", + dentry); return; } diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index c827acb..13886f7f 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -1317,9 +1317,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, if (!fhp->fh_locked) { /* not actually possible */ printk(KERN_ERR - "nfsd_create: parent %s/%s not locked!\n", - dentry->d_parent->d_name.name, - dentry->d_name.name); + "nfsd_create: parent %pd2 not locked!\n", + dentry); err = nfserr_io; goto out; } @@ -1329,8 +1328,8 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp, */ err = nfserr_exist; if (dchild->d_inode) { - dprintk("nfsd_create: dentry %s/%s not negative!\n", - dentry->d_name.name, dchild->d_name.name); + dprintk("nfsd_create: dentry %pd/%pd not negative!\n", + dentry, dchild); goto out; } -- cgit v1.1 From cce6de908ee934fbea12d6cccc55b87dbd4b0c8a Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 15 Oct 2013 12:33:22 -0700 Subject: nfsd: fix Kconfig syntax The description text for CONFIG_NFSD_V4_SECURITY_LABEL has an unpaired quote sign which breaks syntax highlighting for the nfsd Kconfig file. Remove it. Signed-off-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/Kconfig b/fs/nfsd/Kconfig index dc8f1ef..f994e75 100644 --- a/fs/nfsd/Kconfig +++ b/fs/nfsd/Kconfig @@ -95,7 +95,7 @@ config NFSD_V4_SECURITY_LABEL Smack policies on NFSv4 files, say N. WARNING: there is still a chance of backwards-incompatible protocol changes. - For now we recommend "Y" only for developers and testers." + For now we recommend "Y" only for developers and testers. config NFSD_FAULT_INJECTION bool "NFS server manual fault injection" -- cgit v1.1 From 9857df815f17417be116f800636f460e247afb5a Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Mon, 14 Oct 2013 13:44:52 +0300 Subject: nfsd: nfs4_free_stid Make it symmetric to nfs4_alloc_stid. Signed-off-by: Benny Halevy Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a601fd4..9cb1b17 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -402,11 +402,16 @@ static void remove_stid(struct nfs4_stid *s) idr_remove(stateids, s->sc_stateid.si_opaque.so_id); } +static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s) +{ + kmem_cache_free(slab, s); +} + void nfs4_put_delegation(struct nfs4_delegation *dp) { if (atomic_dec_and_test(&dp->dl_count)) { - kmem_cache_free(deleg_slab, dp); + nfs4_free_stid(deleg_slab, &dp->dl_stid); num_delegations--; } } @@ -610,7 +615,7 @@ static void close_generic_stateid(struct nfs4_ol_stateid *stp) static void free_generic_stateid(struct nfs4_ol_stateid *stp) { remove_stid(&stp->st_stid); - kmem_cache_free(stateid_slab, stp); + nfs4_free_stid(stateid_slab, &stp->st_stid); } static void release_lock_stateid(struct nfs4_ol_stateid *stp) -- cgit v1.1 From 5d7dab83e3e55e81a88c406da71afde0ebaa6ad8 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Tue, 15 Oct 2013 09:57:55 +0300 Subject: nfsd: nfs4_open_delegation needs to remove_stid rather than unhash_stid In the out_free: path, the newly allocated stid must be removed rather than unhashed so it can never be found. Signed-off-by: Benny Halevy Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9cb1b17..3feb38e 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -3159,7 +3159,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; return; out_free: - unhash_stid(&dp->dl_stid); + remove_stid(&dp->dl_stid); nfs4_put_delegation(dp); out_no_deleg: open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; -- cgit v1.1 From 7ebe40f20372688a627ad6c754bc0d1c05df58a9 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Tue, 15 Oct 2013 09:58:00 +0300 Subject: nfsd: remove_stid can be incorporated into nfs4_put_delegation All calls to nfs4_put_delegation are preceded with remove_stid. Signed-off-by: Benny Halevy Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 3feb38e..77dfc5a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -410,6 +410,7 @@ static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s) void nfs4_put_delegation(struct nfs4_delegation *dp) { + remove_stid(&dp->dl_stid); if (atomic_dec_and_test(&dp->dl_count)) { nfs4_free_stid(deleg_slab, &dp->dl_stid); num_delegations--; @@ -450,14 +451,12 @@ unhash_delegation(struct nfs4_delegation *dp) static void destroy_revoked_delegation(struct nfs4_delegation *dp) { list_del_init(&dp->dl_recall_lru); - remove_stid(&dp->dl_stid); nfs4_put_delegation(dp); } static void destroy_delegation(struct nfs4_delegation *dp) { unhash_delegation(dp); - remove_stid(&dp->dl_stid); nfs4_put_delegation(dp); } @@ -3159,7 +3158,6 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; return; out_free: - remove_stid(&dp->dl_stid); nfs4_put_delegation(dp); out_no_deleg: open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; -- cgit v1.1 From 01a87d91fcecced2e2bdcd797794b4ede1f64b77 Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Mon, 14 Oct 2013 09:01:55 +0300 Subject: nfsd: no need to unhash_stid before free idr_remove is about to be called before kmem_cache_free so unhashing it is redundant Signed-off-by: Benny Halevy Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 77dfc5a..a90949a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -672,7 +672,6 @@ static void unhash_open_stateid(struct nfs4_ol_stateid *stp) static void release_open_stateid(struct nfs4_ol_stateid *stp) { unhash_open_stateid(stp); - unhash_stid(&stp->st_stid); free_generic_stateid(stp); } @@ -694,7 +693,6 @@ static void release_last_closed_stateid(struct nfs4_openowner *oo) struct nfs4_ol_stateid *s = oo->oo_last_closed_stid; if (s) { - unhash_stid(&s->st_stid); free_generic_stateid(s); oo->oo_last_closed_stid = NULL; } @@ -3998,10 +3996,9 @@ nfsd4_close(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, nfsd4_close_open_stateid(stp); - if (cstate->minorversion) { - unhash_stid(&stp->st_stid); + if (cstate->minorversion) free_generic_stateid(stp); - } else + else oo->oo_last_closed_stid = stp; if (list_empty(&oo->oo_owner.so_stateids)) { -- cgit v1.1 From 956c4fee446c568ad102625da931e259f22c67ee Mon Sep 17 00:00:00 2001 From: Benny Halevy Date: Tue, 29 Oct 2013 11:39:12 +0200 Subject: nfsd4: need to destroy revoked delegations in destroy_client [use list_splice_init] Signed-off-by: Benny Halevy [bfields: no need for recall_lock here] Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index a90949a..21eb678 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1129,6 +1129,11 @@ destroy_client(struct nfs4_client *clp) dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); destroy_delegation(dp); } + list_splice_init(&clp->cl_revoked, &reaplist); + while (!list_empty(&reaplist)) { + dp = list_entry(reaplist.next, struct nfs4_delegation, dl_recall_lru); + destroy_revoked_delegation(dp); + } while (!list_empty(&clp->cl_openowners)) { oo = list_entry(clp->cl_openowners.next, struct nfs4_openowner, oo_perclient); release_openowner(oo); -- cgit v1.1 From 49e7372063a220651b4f12fa46113559533cafee Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Thu, 12 Sep 2013 09:31:39 -0400 Subject: nfsd: fh_update should error out in unexpected cases MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The reporter saw a NULL dereference when a filesystem's ->mknod returned success but left the dentry negative, and then nfsd tried to dereference d_inode (in this case because the CREATE was followed by a GETATTR in the same nfsv4 compound). fh_update already checks for this and another broken case, but for some reason it returns success and leaves nfsd trying to soldier on. If it failed we'd avoid the crash. There's only so much we can do with a buggy filesystem, but it's easy enough to bail out here, so let's do that. Reported-by: Antti Tönkyrä Tested-by: Antti Tönkyrä Signed-off-by: J. Bruce Fields --- fs/nfsd/nfsfh.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index 3d0e15a..3c37b16 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -598,22 +598,20 @@ fh_update(struct svc_fh *fhp) _fh_update_old(dentry, fhp->fh_export, &fhp->fh_handle); } else { if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT) - goto out; + return 0; _fh_update(fhp, fhp->fh_export, dentry); if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) return nfserr_opnotsupp; } -out: return 0; - out_bad: printk(KERN_ERR "fh_update: fh not verified!\n"); - goto out; + return nfserr_serverfault; out_negative: printk(KERN_ERR "fh_update: %pd2 still negative!\n", dentry); - goto out; + return nfserr_serverfault; } /* -- cgit v1.1 From 427d6c6646d868fbd3094e7e2e1644d480cd9204 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 13 Sep 2013 11:08:45 -0400 Subject: nfsd: return better errors to exportfs Someone noticed exportfs happily accepted exports that would later be rejected when mountd tried to give them to the kernel. Fix this. This is a regression from 4c1e1b34d5c800ad3ac9a7e2805b0bea70ad2278 "nfsd: Store ex_anon_uid and ex_anon_gid as kuids and kgids". Cc: "Eric W. Biederman" Cc: stable@vger.kernel.org Reported-by: Yin.JianHong Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index 5f38ea3..af51cf9 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -536,16 +536,12 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) if (err) goto out3; exp.ex_anon_uid= make_kuid(&init_user_ns, an_int); - if (!uid_valid(exp.ex_anon_uid)) - goto out3; /* anon gid */ err = get_int(&mesg, &an_int); if (err) goto out3; exp.ex_anon_gid= make_kgid(&init_user_ns, an_int); - if (!gid_valid(exp.ex_anon_gid)) - goto out3; /* fsid */ err = get_int(&mesg, &an_int); @@ -583,6 +579,17 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) exp.ex_uuid); if (err) goto out4; + /* + * For some reason exportfs has been passing down an + * invalid (-1) uid & gid on the "dummy" export which it + * uses to test export support. To make sure exportfs + * sees errors from check_export we therefore need to + * delay these checks till after check_export: + */ + if (!uid_valid(exp.ex_anon_uid)) + goto out4; + if (!gid_valid(exp.ex_anon_gid)) + goto out4; } expp = svc_export_lookup(&exp); -- cgit v1.1 From 6f6cc3205c5f10129b8a10cdf8abf85d9db48a60 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 13 Sep 2013 17:50:42 -0400 Subject: nfsd: -EINVAL on invalid anonuid/gid instead of silent failure If we're going to refuse to accept these it would be polite of us to at least say so.... This introduces a slight complication since we need to grandfather in exportfs's ill-advised use of -1 uid and gid on its test_export. If it turns out there are other users passing down -1 we may need to do something else. Best might be to drop the checks entirely, but I'm not sure if other parts of the kernel might assume that a task can't run as uid or gid -1. Cc: "Eric W. Biederman" Signed-off-by: J. Bruce Fields --- fs/nfsd/export.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'fs/nfsd') diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index af51cf9..8513c59 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -580,16 +580,25 @@ static int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen) if (err) goto out4; /* + * No point caching this if it would immediately expire. + * Also, this protects exportfs's dummy export from the + * anon_uid/anon_gid checks: + */ + if (exp.h.expiry_time < seconds_since_boot()) + goto out4; + /* * For some reason exportfs has been passing down an * invalid (-1) uid & gid on the "dummy" export which it * uses to test export support. To make sure exportfs * sees errors from check_export we therefore need to * delay these checks till after check_export: */ + err = -EINVAL; if (!uid_valid(exp.ex_anon_uid)) goto out4; if (!gid_valid(exp.ex_anon_gid)) goto out4; + err = 0; } expp = svc_export_lookup(&exp); -- cgit v1.1 From e1a90ebd8b2349eb00ec22f0b8bf6ab8bbd06cc8 Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Wed, 30 Oct 2013 10:00:20 -0400 Subject: NFSD: Combine decode operations for v4 and v4.1 We were using a different array of function pointers to represent each minor version. This makes adding a new minor version tedious, since it needs a step to copy, paste and modify a new version of the same functions. This patch combines the v4 and v4.1 arrays into a single instance and will check minor version support inside each decoder function. Signed-off-by: Anna Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 98 +++++++++++++++++++++++-------------------------------- 1 file changed, 40 insertions(+), 58 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d9454fe..99bebea 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -945,13 +945,16 @@ static __be32 nfsd4_decode_open_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_open_confirm *open_conf) { DECODE_HEAD; - + + if (argp->minorversion >= 1) + return nfserr_notsupp; + status = nfsd4_decode_stateid(argp, &open_conf->oc_req_stateid); if (status) return status; READ_BUF(4); READ32(open_conf->oc_seqid); - + DECODE_TAIL; } @@ -991,6 +994,14 @@ nfsd4_decode_putfh(struct nfsd4_compoundargs *argp, struct nfsd4_putfh *putfh) } static __be32 +nfsd4_decode_putpubfh(struct nfsd4_compoundargs *argp, void *p) +{ + if (argp->minorversion == 0) + return nfs_ok; + return nfserr_notsupp; +} + +static __be32 nfsd4_decode_read(struct nfsd4_compoundargs *argp, struct nfsd4_read *read) { DECODE_HEAD; @@ -1061,6 +1072,9 @@ nfsd4_decode_renew(struct nfsd4_compoundargs *argp, clientid_t *clientid) { DECODE_HEAD; + if (argp->minorversion >= 1) + return nfserr_notsupp; + READ_BUF(sizeof(clientid_t)); COPYMEM(clientid, sizeof(clientid_t)); @@ -1111,6 +1125,9 @@ nfsd4_decode_setclientid(struct nfsd4_compoundargs *argp, struct nfsd4_setclient { DECODE_HEAD; + if (argp->minorversion >= 1) + return nfserr_notsupp; + READ_BUF(NFS4_VERIFIER_SIZE); COPYMEM(setclientid->se_verf.data, NFS4_VERIFIER_SIZE); @@ -1137,6 +1154,9 @@ nfsd4_decode_setclientid_confirm(struct nfsd4_compoundargs *argp, struct nfsd4_s { DECODE_HEAD; + if (argp->minorversion >= 1) + return nfserr_notsupp; + READ_BUF(8 + NFS4_VERIFIER_SIZE); COPYMEM(&scd_c->sc_clientid, 8); COPYMEM(&scd_c->sc_confirm, NFS4_VERIFIER_SIZE); @@ -1220,6 +1240,9 @@ nfsd4_decode_release_lockowner(struct nfsd4_compoundargs *argp, struct nfsd4_rel { DECODE_HEAD; + if (argp->minorversion >= 1) + return nfserr_notsupp; + READ_BUF(12); COPYMEM(&rlockowner->rl_clientid, sizeof(clientid_t)); READ32(rlockowner->rl_owner.len); @@ -1519,7 +1542,7 @@ static nfsd4_dec nfsd4_dec_ops[] = { [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_open_confirm, [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, - [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_noop, + [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_putpubfh, [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, [OP_READ] = (nfsd4_dec)nfsd4_decode_read, [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, @@ -1536,46 +1559,6 @@ static nfsd4_dec nfsd4_dec_ops[] = { [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_release_lockowner, -}; - -static nfsd4_dec nfsd41_dec_ops[] = { - [OP_ACCESS] = (nfsd4_dec)nfsd4_decode_access, - [OP_CLOSE] = (nfsd4_dec)nfsd4_decode_close, - [OP_COMMIT] = (nfsd4_dec)nfsd4_decode_commit, - [OP_CREATE] = (nfsd4_dec)nfsd4_decode_create, - [OP_DELEGPURGE] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_DELEGRETURN] = (nfsd4_dec)nfsd4_decode_delegreturn, - [OP_GETATTR] = (nfsd4_dec)nfsd4_decode_getattr, - [OP_GETFH] = (nfsd4_dec)nfsd4_decode_noop, - [OP_LINK] = (nfsd4_dec)nfsd4_decode_link, - [OP_LOCK] = (nfsd4_dec)nfsd4_decode_lock, - [OP_LOCKT] = (nfsd4_dec)nfsd4_decode_lockt, - [OP_LOCKU] = (nfsd4_dec)nfsd4_decode_locku, - [OP_LOOKUP] = (nfsd4_dec)nfsd4_decode_lookup, - [OP_LOOKUPP] = (nfsd4_dec)nfsd4_decode_noop, - [OP_NVERIFY] = (nfsd4_dec)nfsd4_decode_verify, - [OP_OPEN] = (nfsd4_dec)nfsd4_decode_open, - [OP_OPENATTR] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_OPEN_CONFIRM] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_OPEN_DOWNGRADE] = (nfsd4_dec)nfsd4_decode_open_downgrade, - [OP_PUTFH] = (nfsd4_dec)nfsd4_decode_putfh, - [OP_PUTPUBFH] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_PUTROOTFH] = (nfsd4_dec)nfsd4_decode_noop, - [OP_READ] = (nfsd4_dec)nfsd4_decode_read, - [OP_READDIR] = (nfsd4_dec)nfsd4_decode_readdir, - [OP_READLINK] = (nfsd4_dec)nfsd4_decode_noop, - [OP_REMOVE] = (nfsd4_dec)nfsd4_decode_remove, - [OP_RENAME] = (nfsd4_dec)nfsd4_decode_rename, - [OP_RENEW] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_RESTOREFH] = (nfsd4_dec)nfsd4_decode_noop, - [OP_SAVEFH] = (nfsd4_dec)nfsd4_decode_noop, - [OP_SECINFO] = (nfsd4_dec)nfsd4_decode_secinfo, - [OP_SETATTR] = (nfsd4_dec)nfsd4_decode_setattr, - [OP_SETCLIENTID] = (nfsd4_dec)nfsd4_decode_notsupp, - [OP_SETCLIENTID_CONFIRM]= (nfsd4_dec)nfsd4_decode_notsupp, - [OP_VERIFY] = (nfsd4_dec)nfsd4_decode_verify, - [OP_WRITE] = (nfsd4_dec)nfsd4_decode_write, - [OP_RELEASE_LOCKOWNER] = (nfsd4_dec)nfsd4_decode_notsupp, /* new operations for NFSv4.1 */ [OP_BACKCHANNEL_CTL] = (nfsd4_dec)nfsd4_decode_backchannel_ctl, @@ -1599,23 +1582,23 @@ static nfsd4_dec nfsd41_dec_ops[] = { [OP_RECLAIM_COMPLETE] = (nfsd4_dec)nfsd4_decode_reclaim_complete, }; -struct nfsd4_minorversion_ops { - nfsd4_dec *decoders; - int nops; -}; - -static struct nfsd4_minorversion_ops nfsd4_minorversion[] = { - [0] = { nfsd4_dec_ops, ARRAY_SIZE(nfsd4_dec_ops) }, - [1] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, - [2] = { nfsd41_dec_ops, ARRAY_SIZE(nfsd41_dec_ops) }, -}; +static inline bool +nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) +{ + if (op->opnum < FIRST_NFS4_OP || op->opnum > LAST_NFS4_OP) + return false; + else if (argp->minorversion == 0 && op->opnum > OP_RELEASE_LOCKOWNER) + return false; + else if (argp->minorversion == 1 && op->opnum > OP_RECLAIM_COMPLETE) + return false; + return true; +} static __be32 nfsd4_decode_compound(struct nfsd4_compoundargs *argp) { DECODE_HEAD; struct nfsd4_op *op; - struct nfsd4_minorversion_ops *ops; bool cachethis = false; int i; @@ -1640,10 +1623,9 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) } } - if (argp->minorversion >= ARRAY_SIZE(nfsd4_minorversion)) + if (argp->minorversion > NFSD_SUPPORTED_MINOR_VERSION) argp->opcnt = 0; - ops = &nfsd4_minorversion[argp->minorversion]; for (i = 0; i < argp->opcnt; i++) { op = &argp->ops[i]; op->replay = NULL; @@ -1651,8 +1633,8 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) READ_BUF(4); READ32(op->opnum); - if (op->opnum >= FIRST_NFS4_OP && op->opnum <= LAST_NFS4_OP) - op->status = ops->decoders[op->opnum](argp, &op->u); + if (nfsd4_opnum_in_range(argp, op)) + op->status = nfsd4_dec_ops[op->opnum](argp, &op->u); else { op->opnum = OP_ILLEGAL; op->status = nfserr_op_illegal; -- cgit v1.1 From e50a26dc785f12a6df1f1ac16d62faf0342b72af Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Wed, 30 Oct 2013 10:33:09 -0400 Subject: nfsd4: nfsd_shutdown_net needs state lock A comment claims the caller should take it, but that's not being done. Note we don't want it around the cancel_delayed_work_sync since that may wait on work which holds the client lock. Reported-by: Benny Halevy Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 21eb678..e03e8ef 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -5124,7 +5124,6 @@ out_recovery: return ret; } -/* should be called with the state lock held */ void nfs4_state_shutdown_net(struct net *net) { @@ -5135,6 +5134,7 @@ nfs4_state_shutdown_net(struct net *net) cancel_delayed_work_sync(&nn->laundromat_work); locks_end_grace(&nn->nfsd4_manager); + nfs4_lock_state(); INIT_LIST_HEAD(&reaplist); spin_lock(&recall_lock); list_for_each_safe(pos, next, &nn->del_recall_lru) { @@ -5149,6 +5149,7 @@ nfs4_state_shutdown_net(struct net *net) nfsd4_client_tracking_exit(net); nfs4_state_destroy_net(net); + nfs4_unlock_state(); } void -- cgit v1.1 From 8217d146ab98a1790349d79c436176658e311e3c Mon Sep 17 00:00:00 2001 From: Anna Schumaker Date: Wed, 30 Oct 2013 13:38:13 -0400 Subject: NFSD: Add support for NFS v4.2 operation checking The server does allow NFS over v4.2, even if it doesn't add any new operations yet. I also switch to using constants to represent the last operation for each minor version since this makes the code cleaner and easier to understand at a quick glance. Signed-off-by: Anna Schumaker Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 99bebea..83db5a7 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1585,11 +1585,13 @@ static nfsd4_dec nfsd4_dec_ops[] = { static inline bool nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) { - if (op->opnum < FIRST_NFS4_OP || op->opnum > LAST_NFS4_OP) + if (op->opnum < FIRST_NFS4_OP) return false; - else if (argp->minorversion == 0 && op->opnum > OP_RELEASE_LOCKOWNER) + else if (argp->minorversion == 0 && op->opnum > LAST_NFS40_OP) return false; - else if (argp->minorversion == 1 && op->opnum > OP_RECLAIM_COMPLETE) + else if (argp->minorversion == 1 && op->opnum > LAST_NFS41_OP) + return false; + else if (argp->minorversion == 2 && op->opnum > LAST_NFS42_OP) return false; return true; } -- cgit v1.1 From 3378b7f40d79930f0f447a164c7e8fcbe4480e40 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Fri, 1 Nov 2013 10:42:15 -0400 Subject: nfsd4: fix discarded security labels on setattr Security labels in setattr calls are currently ignored because we forget to set label->len. Cc: stable@vger.kernel.org Reported-by: Jeff Layton Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 1 + 1 file changed, 1 insertion(+) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 83db5a7..d9d7fa9 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -411,6 +411,7 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval, label->data = kzalloc(dummy32 + 1, GFP_KERNEL); if (!label->data) return nfserr_jukebox; + label->len = dummy32; defer_free(argp, kfree, label->data); memcpy(label->data, buf, dummy32); } -- cgit v1.1 From b78800baee494eaca1d8a9ca2d490704fcc49fa0 Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Mon, 4 Nov 2013 17:46:04 -0500 Subject: Revert "nfsd: remove_stid can be incorporated into nfs4_put_delegation" This reverts commit 7ebe40f20372688a627ad6c754bc0d1c05df58a9. We forgot the nfs4_put_delegation call in fs/nfsd/nfs4callback.c which should not be unhashing the stateid. This lead to warnings from the idr code when we tried to removed id's twice. Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4state.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index e03e8ef..0cceb99 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -410,7 +410,6 @@ static void nfs4_free_stid(struct kmem_cache *slab, struct nfs4_stid *s) void nfs4_put_delegation(struct nfs4_delegation *dp) { - remove_stid(&dp->dl_stid); if (atomic_dec_and_test(&dp->dl_count)) { nfs4_free_stid(deleg_slab, &dp->dl_stid); num_delegations--; @@ -451,12 +450,14 @@ unhash_delegation(struct nfs4_delegation *dp) static void destroy_revoked_delegation(struct nfs4_delegation *dp) { list_del_init(&dp->dl_recall_lru); + remove_stid(&dp->dl_stid); nfs4_put_delegation(dp); } static void destroy_delegation(struct nfs4_delegation *dp) { unhash_delegation(dp); + remove_stid(&dp->dl_stid); nfs4_put_delegation(dp); } @@ -3161,6 +3162,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh, open->op_delegate_type = NFS4_OPEN_DELEGATE_READ; return; out_free: + remove_stid(&dp->dl_stid); nfs4_put_delegation(dp); out_no_deleg: open->op_delegate_type = NFS4_OPEN_DELEGATE_NONE; -- cgit v1.1 From 6ff40decff0ef35a5d755ec60182d7f803356dfb Mon Sep 17 00:00:00 2001 From: "J. Bruce Fields" Date: Tue, 5 Nov 2013 15:07:16 -0500 Subject: nfsd4: improve write performance with better sendspace reservations Currently the rpc code conservatively refuses to accept rpc's from a client if the sum of its worst-case estimates of the replies it owes that client exceed the send buffer space. Unfortunately our estimate of the worst-case reply for an NFSv4 compound is always the maximum read size. This can unnecessarily limit the number of operations we handle concurrently, for example in the case most operations are writes (which have small replies). We can do a little better if we check which ops the compound contains. This is still a rough estimate, we'll need to improve on it some day. Reported-by: Shyam Kaushik Tested-by: Shyam Kaushik Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index d9d7fa9..9d76ee3 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -1597,12 +1597,39 @@ nfsd4_opnum_in_range(struct nfsd4_compoundargs *argp, struct nfsd4_op *op) return true; } +/* + * Return a rough estimate of the maximum possible reply size. Note the + * estimate includes rpc headers so is meant to be passed to + * svc_reserve, not svc_reserve_auth. + * + * Also note the current compound encoding permits only one operation to + * use pages beyond the first one, so the maximum possible length is the + * maximum over these values, not the sum. + */ +static int nfsd4_max_reply(u32 opnum) +{ + switch (opnum) { + case OP_READLINK: + case OP_READDIR: + /* + * Both of these ops take a single page for data and put + * the head and tail in another page: + */ + return 2 * PAGE_SIZE; + case OP_READ: + return INT_MAX; + default: + return PAGE_SIZE; + } +} + static __be32 nfsd4_decode_compound(struct nfsd4_compoundargs *argp) { DECODE_HEAD; struct nfsd4_op *op; bool cachethis = false; + int max_reply = PAGE_SIZE; int i; READ_BUF(4); @@ -1652,10 +1679,14 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) * op in the compound wants to be cached: */ cachethis |= nfsd4_cache_this_op(op); + + max_reply = max(max_reply, nfsd4_max_reply(op->opnum)); } /* Sessions make the DRC unnecessary: */ if (argp->minorversion) cachethis = false; + if (max_reply != INT_MAX) + svc_reserve(argp->rqstp, max_reply); argp->rqstp->rq_cachetype = cachethis ? RC_REPLBUFF : RC_NOCACHE; DECODE_TAIL; -- cgit v1.1 From aea240f4162d50e0f2d8bd5ea3ba11b5f072add8 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Thu, 14 Nov 2013 05:50:10 -0800 Subject: nfsd: export proper maximum file size to the client I noticed that we export a way to high value for the maxfilesize attribute when debugging a client issue. The issue didn't turn out to be related to it, but I think we should export it, so that clients can limit what write sizes they accept before hitting the server. Signed-off-by: Christoph Hellwig Signed-off-by: J. Bruce Fields --- fs/nfsd/nfs4xdr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'fs/nfsd') diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 9d76ee3..088de13 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c @@ -2391,7 +2391,7 @@ out_acl: if (bmval0 & FATTR4_WORD0_MAXFILESIZE) { if ((buflen -= 8) < 0) goto out_resource; - WRITE64(~(u64)0); + WRITE64(exp->ex_path.mnt->mnt_sb->s_maxbytes); } if (bmval0 & FATTR4_WORD0_MAXLINK) { if ((buflen -= 4) < 0) -- cgit v1.1