aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfsd
diff options
context:
space:
mode:
Diffstat (limited to 'fs/nfsd')
-rw-r--r--fs/nfsd/vfs.c60
1 files changed, 36 insertions, 24 deletions
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index b8ed58bab8b1..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,
@@ -173,31 +207,9 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
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);