aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exportfs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/exportfs')
-rw-r--r--fs/exportfs/expfs.c66
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 */
75static struct dentry *
76find_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
93static bool dentry_connected(struct dentry *dentry) 72static bool dentry_connected(struct dentry *dentry)
94{ 73{
95 dget(dentry); 74 dget(dentry);
@@ -225,45 +204,26 @@ out_reconnected:
225static int 204static int
226reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf) 205reconnect_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;
266out_reconnected:
267 clear_disconnected(target_dir); 227 clear_disconnected(target_dir);
268 return 0; 228 return 0;
269} 229}