diff options
-rw-r--r-- | Documentation/filesystems/nfs41-server.txt | 9 | ||||
-rw-r--r-- | fs/nfsd/export.c | 22 | ||||
-rw-r--r-- | fs/nfsd/nfs4state.c | 3 | ||||
-rw-r--r-- | fs/nfsd/nfsproc.c | 1 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 62 |
5 files changed, 66 insertions, 31 deletions
diff --git a/Documentation/filesystems/nfs41-server.txt b/Documentation/filesystems/nfs41-server.txt index 5920fe26e6f..1bd0d0c0517 100644 --- a/Documentation/filesystems/nfs41-server.txt +++ b/Documentation/filesystems/nfs41-server.txt @@ -41,7 +41,7 @@ interoperability problems with future clients. Known issues: conformant with the spec (for example, we don't use kerberos on the backchannel correctly). - no trunking support: no clients currently take advantage of - trunking, but this is a mandatory failure, and its use is + trunking, but this is a mandatory feature, and its use is recommended to clients in a number of places. (E.g. to ensure timely renewal in case an existing connection's retry timeouts have gotten too long; see section 8.3 of the draft.) @@ -213,3 +213,10 @@ The following cases aren't supported yet: DESTROY_CLIENTID, DESTROY_SESSION, EXCHANGE_ID. * DESTROY_SESSION MUST be the final operation in the COMPOUND request. +Nonstandard compound limitations: +* No support for a sessions fore channel RPC compound that requires both a + ca_maxrequestsize request and a ca_maxresponsesize reply, so we may + fail to live up to the promise we made in CREATE_SESSION fore channel + negotiation. +* No more than one IO operation (read, write, readdir) allowed per + compound. diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index c1c9e035d4a..b73baba3fb9 100644 --- a/fs/nfsd/export.c +++ b/fs/nfsd/export.c @@ -1320,6 +1320,23 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct path *path) return exp; } +static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp) +{ + struct svc_export *exp; + u32 fsidv[2]; + + mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); + + exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); + /* + * We shouldn't have accepting an nfsv4 request at all if we + * don't have a pseudoexport!: + */ + if (IS_ERR(exp) && PTR_ERR(exp) == -ENOENT) + exp = ERR_PTR(-ESERVERFAULT); + return exp; +} + /* * Called when we need the filehandle for the root of the pseudofs, * for a given NFSv4 client. The root is defined to be the @@ -1330,11 +1347,8 @@ exp_pseudoroot(struct svc_rqst *rqstp, struct svc_fh *fhp) { struct svc_export *exp; __be32 rv; - u32 fsidv[2]; - - mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); - exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); + exp = find_fsidzero_export(rqstp); if (IS_ERR(exp)) return nfserrno(PTR_ERR(exp)); rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2153f9bdbeb..fcb9817881a 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -477,13 +477,14 @@ static int set_forechannel_drc_size(struct nfsd4_channel_attrs *fchan) /* * fchan holds the client values on input, and the server values on output + * sv_max_mesg is the maximum payload plus one page for overhead. */ static int init_forechannel_attrs(struct svc_rqst *rqstp, struct nfsd4_channel_attrs *session_fchan, struct nfsd4_channel_attrs *fchan) { int status = 0; - __u32 maxcount = svc_max_payload(rqstp); + __u32 maxcount = nfsd_serv->sv_max_mesg; /* headerpadsz set to zero in encode routine */ diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 0eb9c820b7a..c5393d1b895 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -758,6 +758,7 @@ nfserrno (int errno) { nfserr_io, -ETXTBSY }, { nfserr_notsupp, -EOPNOTSUPP }, { nfserr_toosmall, -ETOOSMALL }, + { nfserr_serverfault, -ESERVERFAULT }, }; int i; diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a293f027326..638573968dc 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c @@ -141,6 +141,40 @@ out: return err; } +static void follow_to_parent(struct path *path) +{ + struct dentry *dp; + + while (path->dentry == path->mnt->mnt_root && follow_up(path)) + ; + dp = dget_parent(path->dentry); + dput(path->dentry); + path->dentry = dp; +} + +static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp) +{ + struct svc_export *exp2; + struct path path = {.mnt = mntget((*exp)->ex_path.mnt), + .dentry = dget(dparent)}; + + follow_to_parent(&path); + + exp2 = rqst_exp_parent(rqstp, &path); + if (PTR_ERR(exp2) == -ENOENT) { + *dentryp = dget(dparent); + } else if (IS_ERR(exp2)) { + path_put(&path); + return PTR_ERR(exp2); + } else { + *dentryp = dget(path.dentry); + exp_put(*exp); + *exp = exp2; + } + path_put(&path); + return 0; +} + __be32 nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name, unsigned int len, @@ -169,35 +203,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, dentry = dget(dparent); else if (dparent != exp->ex_path.dentry) dentry = dget_parent(dparent); - else if (!EX_NOHIDE(exp)) + else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp)) dentry = dget(dparent); /* .. == . just like at / */ else { /* checking mountpoint crossing is very different when stepping up */ - struct svc_export *exp2 = NULL; - struct dentry *dp; - struct path path = {.mnt = mntget(exp->ex_path.mnt), - .dentry = dget(dparent)}; - - while (path.dentry == path.mnt->mnt_root && - follow_up(&path)) - ; - dp = dget_parent(path.dentry); - dput(path.dentry); - path.dentry = dp; - - exp2 = rqst_exp_parent(rqstp, &path); - if (PTR_ERR(exp2) == -ENOENT) { - dentry = dget(dparent); - } else if (IS_ERR(exp2)) { - host_err = PTR_ERR(exp2); - path_put(&path); + host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry); + if (host_err) goto out_nfserr; - } else { - dentry = dget(path.dentry); - exp_put(exp); - exp = exp2; - } - path_put(&path); } } else { fh_lock(fhp); |