[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: Ian Kent <raven@themaw.net>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
This commit is contained in:
Ian Kent 2005-05-01 08:59:17 -07:00 committed by Linus Torvalds
parent 4dcd00b181
commit 3a9720ce73
3 changed files with 27 additions and 4 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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;