diff options
Diffstat (limited to 'fs')
-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 |
4 files changed, 58 insertions, 30 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c index c1c9e035d4a4..b73baba3fb97 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) | |||
1320 | return exp; | 1320 | return exp; |
1321 | } | 1321 | } |
1322 | 1322 | ||
1323 | static struct svc_export *find_fsidzero_export(struct svc_rqst *rqstp) | ||
1324 | { | ||
1325 | struct svc_export *exp; | ||
1326 | u32 fsidv[2]; | ||
1327 | |||
1328 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); | ||
1329 | |||
1330 | exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); | ||
1331 | /* | ||
1332 | * We shouldn't have accepting an nfsv4 request at all if we | ||
1333 | * don't have a pseudoexport!: | ||
1334 | */ | ||
1335 | if (IS_ERR(exp) && PTR_ERR(exp) == -ENOENT) | ||
1336 | exp = ERR_PTR(-ESERVERFAULT); | ||
1337 | return exp; | ||
1338 | } | ||
1339 | |||
1323 | /* | 1340 | /* |
1324 | * Called when we need the filehandle for the root of the pseudofs, | 1341 | * Called when we need the filehandle for the root of the pseudofs, |
1325 | * for a given NFSv4 client. The root is defined to be the | 1342 | * 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) | |||
1330 | { | 1347 | { |
1331 | struct svc_export *exp; | 1348 | struct svc_export *exp; |
1332 | __be32 rv; | 1349 | __be32 rv; |
1333 | u32 fsidv[2]; | ||
1334 | |||
1335 | mk_fsid(FSID_NUM, fsidv, 0, 0, 0, NULL); | ||
1336 | 1350 | ||
1337 | exp = rqst_exp_find(rqstp, FSID_NUM, fsidv); | 1351 | exp = find_fsidzero_export(rqstp); |
1338 | if (IS_ERR(exp)) | 1352 | if (IS_ERR(exp)) |
1339 | return nfserrno(PTR_ERR(exp)); | 1353 | return nfserrno(PTR_ERR(exp)); |
1340 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); | 1354 | rv = fh_compose(fhp, exp, exp->ex_path.dentry, NULL); |
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 2153f9bdbebd..fcb9817881a1 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) | |||
477 | 477 | ||
478 | /* | 478 | /* |
479 | * fchan holds the client values on input, and the server values on output | 479 | * fchan holds the client values on input, and the server values on output |
480 | * sv_max_mesg is the maximum payload plus one page for overhead. | ||
480 | */ | 481 | */ |
481 | static int init_forechannel_attrs(struct svc_rqst *rqstp, | 482 | static int init_forechannel_attrs(struct svc_rqst *rqstp, |
482 | struct nfsd4_channel_attrs *session_fchan, | 483 | struct nfsd4_channel_attrs *session_fchan, |
483 | struct nfsd4_channel_attrs *fchan) | 484 | struct nfsd4_channel_attrs *fchan) |
484 | { | 485 | { |
485 | int status = 0; | 486 | int status = 0; |
486 | __u32 maxcount = svc_max_payload(rqstp); | 487 | __u32 maxcount = nfsd_serv->sv_max_mesg; |
487 | 488 | ||
488 | /* headerpadsz set to zero in encode routine */ | 489 | /* headerpadsz set to zero in encode routine */ |
489 | 490 | ||
diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index 0eb9c820b7a6..c5393d1b8955 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c | |||
@@ -758,6 +758,7 @@ nfserrno (int errno) | |||
758 | { nfserr_io, -ETXTBSY }, | 758 | { nfserr_io, -ETXTBSY }, |
759 | { nfserr_notsupp, -EOPNOTSUPP }, | 759 | { nfserr_notsupp, -EOPNOTSUPP }, |
760 | { nfserr_toosmall, -ETOOSMALL }, | 760 | { nfserr_toosmall, -ETOOSMALL }, |
761 | { nfserr_serverfault, -ESERVERFAULT }, | ||
761 | }; | 762 | }; |
762 | int i; | 763 | int i; |
763 | 764 | ||
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index a293f0273263..638573968dcf 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -141,6 +141,40 @@ out: | |||
141 | return err; | 141 | return err; |
142 | } | 142 | } |
143 | 143 | ||
144 | static void follow_to_parent(struct path *path) | ||
145 | { | ||
146 | struct dentry *dp; | ||
147 | |||
148 | while (path->dentry == path->mnt->mnt_root && follow_up(path)) | ||
149 | ; | ||
150 | dp = dget_parent(path->dentry); | ||
151 | dput(path->dentry); | ||
152 | path->dentry = dp; | ||
153 | } | ||
154 | |||
155 | static int nfsd_lookup_parent(struct svc_rqst *rqstp, struct dentry *dparent, struct svc_export **exp, struct dentry **dentryp) | ||
156 | { | ||
157 | struct svc_export *exp2; | ||
158 | struct path path = {.mnt = mntget((*exp)->ex_path.mnt), | ||
159 | .dentry = dget(dparent)}; | ||
160 | |||
161 | follow_to_parent(&path); | ||
162 | |||
163 | exp2 = rqst_exp_parent(rqstp, &path); | ||
164 | if (PTR_ERR(exp2) == -ENOENT) { | ||
165 | *dentryp = dget(dparent); | ||
166 | } else if (IS_ERR(exp2)) { | ||
167 | path_put(&path); | ||
168 | return PTR_ERR(exp2); | ||
169 | } else { | ||
170 | *dentryp = dget(path.dentry); | ||
171 | exp_put(*exp); | ||
172 | *exp = exp2; | ||
173 | } | ||
174 | path_put(&path); | ||
175 | return 0; | ||
176 | } | ||
177 | |||
144 | __be32 | 178 | __be32 |
145 | nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | 179 | nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, |
146 | const char *name, unsigned int len, | 180 | const char *name, unsigned int len, |
@@ -169,35 +203,13 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, | |||
169 | dentry = dget(dparent); | 203 | dentry = dget(dparent); |
170 | else if (dparent != exp->ex_path.dentry) | 204 | else if (dparent != exp->ex_path.dentry) |
171 | dentry = dget_parent(dparent); | 205 | dentry = dget_parent(dparent); |
172 | else if (!EX_NOHIDE(exp)) | 206 | else if (!EX_NOHIDE(exp) && !nfsd_v4client(rqstp)) |
173 | dentry = dget(dparent); /* .. == . just like at / */ | 207 | dentry = dget(dparent); /* .. == . just like at / */ |
174 | else { | 208 | else { |
175 | /* checking mountpoint crossing is very different when stepping up */ | 209 | /* checking mountpoint crossing is very different when stepping up */ |
176 | struct svc_export *exp2 = NULL; | 210 | host_err = nfsd_lookup_parent(rqstp, dparent, &exp, &dentry); |
177 | struct dentry *dp; | 211 | if (host_err) |
178 | struct path path = {.mnt = mntget(exp->ex_path.mnt), | ||
179 | .dentry = dget(dparent)}; | ||
180 | |||
181 | while (path.dentry == path.mnt->mnt_root && | ||
182 | follow_up(&path)) | ||
183 | ; | ||
184 | dp = dget_parent(path.dentry); | ||
185 | dput(path.dentry); | ||
186 | path.dentry = dp; | ||
187 | |||
188 | exp2 = rqst_exp_parent(rqstp, &path); | ||
189 | if (PTR_ERR(exp2) == -ENOENT) { | ||
190 | dentry = dget(dparent); | ||
191 | } else if (IS_ERR(exp2)) { | ||
192 | host_err = PTR_ERR(exp2); | ||
193 | path_put(&path); | ||
194 | goto out_nfserr; | 212 | goto out_nfserr; |
195 | } else { | ||
196 | dentry = dget(path.dentry); | ||
197 | exp_put(exp); | ||
198 | exp = exp2; | ||
199 | } | ||
200 | path_put(&path); | ||
201 | } | 213 | } |
202 | } else { | 214 | } else { |
203 | fh_lock(fhp); | 215 | fh_lock(fhp); |