diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/nfsd/vfs.c | 60 |
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 | ||
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, |
@@ -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); |