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 {
int needs_reghost;
struct super_block *sb;
struct semaphore wq_sem;
spinlock_t fs_lock;
struct autofs_wait_queue *queues; /* Wait queue pointer */
};
......@@ -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)
......
......@@ -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;
......@@ -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)) {
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);
......
......@@ -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;
......
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