Commit 3a9720ce authored by Ian Kent's avatar Ian Kent Committed by Linus Torvalds

[PATCH] autofs4: tree race fix

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: default avatarIan Kent <raven@themaw.net>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent 4dcd00b1
...@@ -102,6 +102,7 @@ struct autofs_sb_info { ...@@ -102,6 +102,7 @@ struct autofs_sb_info {
int needs_reghost; int needs_reghost;
struct super_block *sb; struct super_block *sb;
struct semaphore wq_sem; struct semaphore wq_sem;
spinlock_t fs_lock;
struct autofs_wait_queue *queues; /* Wait queue pointer */ struct autofs_wait_queue *queues; /* Wait queue pointer */
}; };
...@@ -127,9 +128,18 @@ static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) { ...@@ -127,9 +128,18 @@ static inline int autofs4_oz_mode(struct autofs_sb_info *sbi) {
static inline int autofs4_ispending(struct dentry *dentry) static inline int autofs4_ispending(struct dentry *dentry)
{ {
struct autofs_info *inf = autofs4_dentry_ino(dentry); struct autofs_info *inf = autofs4_dentry_ino(dentry);
int pending = 0;
return (dentry->d_flags & DCACHE_AUTOFS_PENDING) || if (dentry->d_flags & DCACHE_AUTOFS_PENDING)
(inf != NULL && inf->flags & AUTOFS_INF_EXPIRING); 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) static inline void autofs4_copy_atime(struct file *src, struct file *dst)
......
...@@ -99,6 +99,10 @@ static int autofs4_check_tree(struct vfsmount *mnt, ...@@ -99,6 +99,10 @@ static int autofs4_check_tree(struct vfsmount *mnt,
if (!autofs4_can_expire(top, timeout, do_now)) if (!autofs4_can_expire(top, timeout, do_now))
return 0; return 0;
/* Is someone visiting anywhere in the tree ? */
if (may_umount_tree(mnt))
return 0;
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
repeat: repeat:
next = this_parent->d_subdirs.next; next = this_parent->d_subdirs.next;
...@@ -270,10 +274,18 @@ static struct dentry *autofs4_expire(struct super_block *sb, ...@@ -270,10 +274,18 @@ static struct dentry *autofs4_expire(struct super_block *sb,
/* Case 2: tree mount, expire iff entire tree is not busy */ /* Case 2: tree mount, expire iff entire tree is not busy */
if (!exp_leaves) { 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)) { if (autofs4_check_tree(mnt, dentry, timeout, do_now)) {
expired = dentry; struct autofs_info *inf = autofs4_dentry_ino(dentry);
break;
/* 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 */ /* Case 3: direct mount, expire individual leaves */
} else { } else {
expired = autofs4_check_leaves(mnt, dentry, timeout, do_now); expired = autofs4_check_leaves(mnt, dentry, timeout, do_now);
......
...@@ -206,6 +206,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent) ...@@ -206,6 +206,7 @@ int autofs4_fill_super(struct super_block *s, void *data, int silent)
sbi->version = 0; sbi->version = 0;
sbi->sub_version = 0; sbi->sub_version = 0;
init_MUTEX(&sbi->wq_sem); init_MUTEX(&sbi->wq_sem);
spin_lock_init(&sbi->fs_lock);
sbi->queues = NULL; sbi->queues = NULL;
s->s_blocksize = 1024; s->s_blocksize = 1024;
s->s_blocksize_bits = 10; s->s_blocksize_bits = 10;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment