Skip to content

Commit

Permalink
[PATCH] autofs4: tree race fix
Browse files Browse the repository at this point in the history
For tree mount maps, a call to chdir or chroot, to a directory above the
moint point directories at a certain time during the expire results in the
expire incorrectly thinking the tree is not busy.  This patch adds a check
to see if the filesystem above the tree mount points is busy and also locks
the filesystem during the tree mount expire to prevent the race.

Signed-off-by: Ian Kent <raven@themaw.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
  • Loading branch information
raven-au authored and Linus Torvalds committed May 1, 2005
1 parent 4dcd00b commit 3a9720c
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 4 deletions.
14 changes: 12 additions & 2 deletions fs/autofs4/autofs_i.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ struct autofs_sb_info {
int needs_reghost;
struct super_block *sb;
struct semaphore wq_sem;
spinlock_t fs_lock;
struct autofs_wait_queue *queues; /* Wait queue pointer */
};

Expand All @@ -127,9 +128,18 @@ static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) {
static inline int autofs4_ispending(struct dentry *dentry)
{
struct autofs_info *inf = autofs4_dentry_ino(dentry);
int pending = 0;

return (dentry->d_flags & DCACHE_AUTOFS_PENDING) ||
(inf != NULL && inf->flags & AUTOFS_INF_EXPIRING);
if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
return 1;

if (inf) {
spin_lock(&inf->sbi->fs_lock);
pending = inf->flags & AUTOFS_INF_EXPIRING;
spin_unlock(&inf->sbi->fs_lock);
}

return pending;
}

static inline void autofs4_copy_atime(struct file *src, struct file *dst)
Expand Down
16 changes: 14 additions & 2 deletions fs/autofs4/expire.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ static int autofs4_check_tree(struct vfsmount *mnt,
if (!autofs4_can_expire(top, timeout, do_now))
return 0;

/* Is someone visiting anywhere in the tree ? */
if (may_umount_tree(mnt))
return 0;

spin_lock(&dcache_lock);
repeat:
next = this_parent->d_subdirs.next;
Expand Down Expand Up @@ -270,10 +274,18 @@ static struct dentry *autofs4_expire(struct super_block *sb,

/* Case 2: tree mount, expire iff entire tree is not busy */
if (!exp_leaves) {
/* Lock the tree as we must expire as a whole */
spin_lock(&sbi->fs_lock);
if (autofs4_check_tree(mnt, dentry, timeout, do_now)) {
expired = dentry;
break;
struct autofs_info *inf = autofs4_dentry_ino(dentry);

/* Set this flag early to catch sys_chdir and the like */
inf->flags |= AUTOFS_INF_EXPIRING;
spin_unlock(&sbi->fs_lock);
expired = dentry;
break;
}
spin_unlock(&sbi->fs_lock);
/* Case 3: direct mount, expire individual leaves */
} else {
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
Expand Down
1 change: 1 addition & 0 deletions fs/autofs4/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
sbi->version = 0;
sbi->sub_version = 0;
init_MUTEX(&sbi->wq_sem);
spin_lock_init(&sbi->fs_lock);
sbi->queues = NULL;
s->s_blocksize = 1024;
s->s_blocksize_bits = 10;
Expand Down

0 comments on commit 3a9720c

Please sign in to comment.