aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/nfsd/export.c15
-rw-r--r--fs/nfsd/vfs.c32
-rw-r--r--include/linux/nfsd/export.h3
3 files changed, 23 insertions, 27 deletions
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 5149dabde555..84f5e5cb0863 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1240,18 +1240,15 @@ __be32 check_nfsd_access(struct svc_export *exp, struct svc_rqst *rqstp)
1240 * use exp_get_by_name() or exp_find(). 1240 * use exp_get_by_name() or exp_find().
1241 */ 1241 */
1242struct svc_export * 1242struct svc_export *
1243rqst_exp_get_by_name(struct svc_rqst *rqstp, struct vfsmount *mnt, 1243rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
1244 struct dentry *dentry)
1245{ 1244{
1246 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT); 1245 struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
1247 struct path path = {.mnt = mnt, .dentry = dentry};
1248 1246
1249 if (rqstp->rq_client == NULL) 1247 if (rqstp->rq_client == NULL)
1250 goto gss; 1248 goto gss;
1251 1249
1252 /* First try the auth_unix client: */ 1250 /* First try the auth_unix client: */
1253 exp = exp_get_by_name(rqstp->rq_client, &path, 1251 exp = exp_get_by_name(rqstp->rq_client, path, &rqstp->rq_chandle);
1254 &rqstp->rq_chandle);
1255 if (PTR_ERR(exp) == -ENOENT) 1252 if (PTR_ERR(exp) == -ENOENT)
1256 goto gss; 1253 goto gss;
1257 if (IS_ERR(exp)) 1254 if (IS_ERR(exp))
@@ -1263,8 +1260,7 @@ gss:
1263 /* Otherwise, try falling back on gss client */ 1260 /* Otherwise, try falling back on gss client */
1264 if (rqstp->rq_gssclient == NULL) 1261 if (rqstp->rq_gssclient == NULL)
1265 return exp; 1262 return exp;
1266 gssexp = exp_get_by_name(rqstp->rq_gssclient, &path, 1263 gssexp = exp_get_by_name(rqstp->rq_gssclient, path, &rqstp->rq_chandle);
1267 &rqstp->rq_chandle);
1268 if (PTR_ERR(gssexp) == -ENOENT) 1264 if (PTR_ERR(gssexp) == -ENOENT)
1269 return exp; 1265 return exp;
1270 if (!IS_ERR(exp)) 1266 if (!IS_ERR(exp))
@@ -1307,9 +1303,10 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
1307 struct dentry *dentry) 1303 struct dentry *dentry)
1308{ 1304{
1309 struct svc_export *exp; 1305 struct svc_export *exp;
1306 struct path path = {.mnt = mnt, .dentry = dentry};
1310 1307
1311 dget(dentry); 1308 dget(dentry);
1312 exp = rqst_exp_get_by_name(rqstp, mnt, dentry); 1309 exp = rqst_exp_get_by_name(rqstp, &path);
1313 1310
1314 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) { 1311 while (PTR_ERR(exp) == -ENOENT && !IS_ROOT(dentry)) {
1315 struct dentry *parent; 1312 struct dentry *parent;
@@ -1317,7 +1314,7 @@ rqst_exp_parent(struct svc_rqst *rqstp, struct vfsmount *mnt,
1317 parent = dget_parent(dentry); 1314 parent = dget_parent(dentry);
1318 dput(dentry); 1315 dput(dentry);
1319 dentry = parent; 1316 dentry = parent;
1320 exp = rqst_exp_get_by_name(rqstp, mnt, dentry); 1317 exp = rqst_exp_get_by_name(rqstp, &path);
1321 } 1318 }
1322 dput(dentry); 1319 dput(dentry);
1323 return exp; 1320 return exp;
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index bd584bcf1d9f..d84c4eaa526b 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -101,36 +101,36 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
101{ 101{
102 struct svc_export *exp = *expp, *exp2 = NULL; 102 struct svc_export *exp = *expp, *exp2 = NULL;
103 struct dentry *dentry = *dpp; 103 struct dentry *dentry = *dpp;
104 struct vfsmount *mnt = mntget(exp->ex_path.mnt); 104 struct path path = {.mnt = mntget(exp->ex_path.mnt),
105 struct dentry *mounts = dget(dentry); 105 .dentry = dget(dentry)};
106 int err = 0; 106 int err = 0;
107 107
108 while (follow_down(&mnt,&mounts)&&d_mountpoint(mounts)); 108 while (follow_down(&path.mnt, &path.dentry) &&
109 d_mountpoint(path.dentry))
110 ;
109 111
110 exp2 = rqst_exp_get_by_name(rqstp, mnt, mounts); 112 exp2 = rqst_exp_get_by_name(rqstp, &path);
111 if (IS_ERR(exp2)) { 113 if (IS_ERR(exp2)) {
112 if (PTR_ERR(exp2) != -ENOENT) 114 if (PTR_ERR(exp2) != -ENOENT)
113 err = PTR_ERR(exp2); 115 err = PTR_ERR(exp2);
114 dput(mounts); 116 path_put(&path);
115 mntput(mnt);
116 goto out; 117 goto out;
117 } 118 }
118 if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) { 119 if ((exp->ex_flags & NFSEXP_CROSSMOUNT) || EX_NOHIDE(exp2)) {
119 /* successfully crossed mount point */ 120 /* successfully crossed mount point */
120 /* 121 /*
121 * This is subtle: dentry is *not* under mnt at this point. 122 * This is subtle: path.dentry is *not* on path.mnt
122 * The only reason we are safe is that original mnt is pinned 123 * at this point. The only reason we are safe is that
123 * down by exp, so we should dput before putting exp. 124 * original mnt is pinned down by exp, so we should
125 * put path *before* putting exp
124 */ 126 */
125 dput(dentry); 127 *dpp = path.dentry;
126 *dpp = mounts; 128 path.dentry = dentry;
127 exp_put(exp);
128 *expp = exp2; 129 *expp = exp2;
129 } else { 130 exp2 = exp;
130 exp_put(exp2);
131 dput(mounts);
132 } 131 }
133 mntput(mnt); 132 path_put(&path);
133 exp_put(exp2);
134out: 134out:
135 return err; 135 return err;
136} 136}
diff --git a/include/linux/nfsd/export.h b/include/linux/nfsd/export.h
index bcd0201589f8..98f6fd584d53 100644
--- a/include/linux/nfsd/export.h
+++ b/include/linux/nfsd/export.h
@@ -125,8 +125,7 @@ void nfsd_export_flush(void);
125void exp_readlock(void); 125void exp_readlock(void);
126void exp_readunlock(void); 126void exp_readunlock(void);
127struct svc_export * rqst_exp_get_by_name(struct svc_rqst *, 127struct svc_export * rqst_exp_get_by_name(struct svc_rqst *,
128 struct vfsmount *, 128 struct path *);
129 struct dentry *);
130struct svc_export * rqst_exp_parent(struct svc_rqst *, 129struct svc_export * rqst_exp_parent(struct svc_rqst *,
131 struct vfsmount *mnt, 130 struct vfsmount *mnt,
132 struct dentry *dentry); 131 struct dentry *dentry);