aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/export.c22
-rw-r--r--fs/nfsd/nfs4state.c3
-rw-r--r--fs/nfsd/nfsproc.c1
-rw-r--r--fs/nfsd/vfs.c62
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
1323static 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 */
481static int init_forechannel_attrs(struct svc_rqst *rqstp, 482static 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
144static 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
155static 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
145nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp, 179nfsd_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);