diff options
Diffstat (limited to 'fs/exportfs')
-rw-r--r-- | fs/exportfs/expfs.c | 66 |
1 files changed, 13 insertions, 53 deletions
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c index b33b9c4deea0..48a359dd286e 100644 --- a/fs/exportfs/expfs.c +++ b/fs/exportfs/expfs.c | |||
@@ -69,27 +69,6 @@ find_acceptable_alias(struct dentry *result, | |||
69 | return NULL; | 69 | return NULL; |
70 | } | 70 | } |
71 | 71 | ||
72 | /* | ||
73 | * Find root of a disconnected subtree and return a reference to it. | ||
74 | */ | ||
75 | static struct dentry * | ||
76 | find_disconnected_root(struct dentry *dentry) | ||
77 | { | ||
78 | dget(dentry); | ||
79 | while (!IS_ROOT(dentry)) { | ||
80 | struct dentry *parent = dget_parent(dentry); | ||
81 | |||
82 | if (!(parent->d_flags & DCACHE_DISCONNECTED)) { | ||
83 | dput(parent); | ||
84 | break; | ||
85 | } | ||
86 | |||
87 | dput(dentry); | ||
88 | dentry = parent; | ||
89 | } | ||
90 | return dentry; | ||
91 | } | ||
92 | |||
93 | static bool dentry_connected(struct dentry *dentry) | 72 | static bool dentry_connected(struct dentry *dentry) |
94 | { | 73 | { |
95 | dget(dentry); | 74 | dget(dentry); |
@@ -225,45 +204,26 @@ out_reconnected: | |||
225 | static int | 204 | static int |
226 | reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf) | 205 | reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf) |
227 | { | 206 | { |
228 | int err = -ESTALE; | 207 | struct dentry *dentry, *parent; |
229 | 208 | ||
230 | while (target_dir->d_flags & DCACHE_DISCONNECTED) { | 209 | dentry = dget(target_dir); |
231 | struct dentry *dentry = find_disconnected_root(target_dir); | ||
232 | 210 | ||
211 | while (dentry->d_flags & DCACHE_DISCONNECTED) { | ||
233 | BUG_ON(dentry == mnt->mnt_sb->s_root); | 212 | BUG_ON(dentry == mnt->mnt_sb->s_root); |
234 | 213 | ||
235 | if (!IS_ROOT(dentry)) { | 214 | if (IS_ROOT(dentry)) |
236 | /* must have found a connected parent - great */ | 215 | parent = reconnect_one(mnt, dentry, nbuf); |
237 | clear_disconnected(target_dir); | 216 | else |
238 | dput(dentry); | 217 | parent = dget_parent(dentry); |
218 | |||
219 | if (!parent) | ||
239 | break; | 220 | break; |
240 | } else { | ||
241 | struct dentry *parent; | ||
242 | /* | ||
243 | * We have hit the top of a disconnected path, try to | ||
244 | * find parent and connect. | ||
245 | */ | ||
246 | parent = reconnect_one(mnt, dentry, nbuf); | ||
247 | if (!parent) | ||
248 | goto out_reconnected; | ||
249 | if (IS_ERR(parent)) { | ||
250 | err = PTR_ERR(parent); | ||
251 | break; | ||
252 | } | ||
253 | dput(parent); | ||
254 | } | ||
255 | dput(dentry); | 221 | dput(dentry); |
222 | if (IS_ERR(parent)) | ||
223 | return PTR_ERR(parent); | ||
224 | dentry = parent; | ||
256 | } | 225 | } |
257 | 226 | dput(dentry); | |
258 | if (target_dir->d_flags & DCACHE_DISCONNECTED) { | ||
259 | /* something went wrong - oh-well */ | ||
260 | if (!err) | ||
261 | err = -ESTALE; | ||
262 | return err; | ||
263 | } | ||
264 | |||
265 | return 0; | ||
266 | out_reconnected: | ||
267 | clear_disconnected(target_dir); | 227 | clear_disconnected(target_dir); |
268 | return 0; | 228 | return 0; |
269 | } | 229 | } |