diff options
author | Ian Kent <raven@themaw.net> | 2008-07-24 00:30:27 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-24 13:47:32 -0400 |
commit | 6e60a9ab5f5d314735467752f623072f5b75157a (patch) | |
tree | 1a42df40e6fad52bd6be74970af8eb56870fe6ba /fs/autofs4/expire.c | |
parent | 97e7449a7ad883bf9f516fc970778d75999c7843 (diff) |
autofs4: fix direct mount pending expire race
For direct and offset type mounts that are covered by another mount we
cannot check the AUTOFS_INF_EXPIRING flag during a path walk which leads
to lookups walking into an expiring mount while it is being expired.
For example, for the direct multi-mount map entry with a couple of
offsets:
/race/mm1 / <server1>:/<path1>
/om1 <server2>:/<path2>
/om2 <server1>:/<path3>
an autofs trigger mount is mounted on /race/mm1 and when accessed it is
over mounted and trigger mounts made for /race/mm1/om1 and /race/mm1/om2.
So it isn't possible for path walks to see the expiring flag at all and
they happily walk into the file system while it is expiring.
When expiring these mounts follow_down() must stop at the autofs mount and
all processes must block in the ->follow_link() method (except the daemon)
until the expire is complete. This is done by decrementing the d_mounted
field of the autofs trigger mount root dentry until the expire is
completed. In ->follow_link() all processes wait on the expire and the
mount following is completed for the daemon until the expire is complete.
Signed-off-by: Ian Kent <raven@themaw.net>
Cc: Jeff Moyer <jmoyer@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/autofs4/expire.c')
-rw-r--r-- | fs/autofs4/expire.c | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 19f5bea2704f..705b9f057fb3 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c | |||
@@ -259,13 +259,15 @@ static struct dentry *autofs4_expire_direct(struct super_block *sb, | |||
259 | now = jiffies; | 259 | now = jiffies; |
260 | timeout = sbi->exp_timeout; | 260 | timeout = sbi->exp_timeout; |
261 | 261 | ||
262 | /* Lock the tree as we must expire as a whole */ | ||
263 | spin_lock(&sbi->fs_lock); | 262 | spin_lock(&sbi->fs_lock); |
264 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { | 263 | if (!autofs4_direct_busy(mnt, root, timeout, do_now)) { |
265 | struct autofs_info *ino = autofs4_dentry_ino(root); | 264 | struct autofs_info *ino = autofs4_dentry_ino(root); |
266 | 265 | if (d_mountpoint(root)) { | |
267 | /* Set this flag early to catch sys_chdir and the like */ | 266 | ino->flags |= AUTOFS_INF_MOUNTPOINT; |
267 | root->d_mounted--; | ||
268 | } | ||
268 | ino->flags |= AUTOFS_INF_EXPIRING; | 269 | ino->flags |= AUTOFS_INF_EXPIRING; |
270 | init_completion(&ino->expire_complete); | ||
269 | spin_unlock(&sbi->fs_lock); | 271 | spin_unlock(&sbi->fs_lock); |
270 | return root; | 272 | return root; |
271 | } | 273 | } |
@@ -392,6 +394,7 @@ found: | |||
392 | expired, (int)expired->d_name.len, expired->d_name.name); | 394 | expired, (int)expired->d_name.len, expired->d_name.name); |
393 | ino = autofs4_dentry_ino(expired); | 395 | ino = autofs4_dentry_ino(expired); |
394 | ino->flags |= AUTOFS_INF_EXPIRING; | 396 | ino->flags |= AUTOFS_INF_EXPIRING; |
397 | init_completion(&ino->expire_complete); | ||
395 | spin_unlock(&sbi->fs_lock); | 398 | spin_unlock(&sbi->fs_lock); |
396 | spin_lock(&dcache_lock); | 399 | spin_lock(&dcache_lock); |
397 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); | 400 | list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child); |
@@ -429,6 +432,7 @@ int autofs4_expire_run(struct super_block *sb, | |||
429 | spin_lock(&sbi->fs_lock); | 432 | spin_lock(&sbi->fs_lock); |
430 | ino = autofs4_dentry_ino(dentry); | 433 | ino = autofs4_dentry_ino(dentry); |
431 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 434 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
435 | complete_all(&ino->expire_complete); | ||
432 | spin_unlock(&sbi->fs_lock); | 436 | spin_unlock(&sbi->fs_lock); |
433 | 437 | ||
434 | return ret; | 438 | return ret; |
@@ -457,8 +461,14 @@ int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, | |||
457 | /* This is synchronous because it makes the daemon a | 461 | /* This is synchronous because it makes the daemon a |
458 | little easier */ | 462 | little easier */ |
459 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); | 463 | ret = autofs4_wait(sbi, dentry, NFY_EXPIRE); |
464 | |||
460 | spin_lock(&sbi->fs_lock); | 465 | spin_lock(&sbi->fs_lock); |
466 | if (ino->flags & AUTOFS_INF_MOUNTPOINT) { | ||
467 | sb->s_root->d_mounted++; | ||
468 | ino->flags &= ~AUTOFS_INF_MOUNTPOINT; | ||
469 | } | ||
461 | ino->flags &= ~AUTOFS_INF_EXPIRING; | 470 | ino->flags &= ~AUTOFS_INF_EXPIRING; |
471 | complete_all(&ino->expire_complete); | ||
462 | spin_unlock(&sbi->fs_lock); | 472 | spin_unlock(&sbi->fs_lock); |
463 | dput(dentry); | 473 | dput(dentry); |
464 | } | 474 | } |