diff options
author | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-05-03 08:14:09 +0100 |
---|---|---|
committer | David Woodhouse <dwmw2@shinybook.infradead.org> | 2005-05-03 08:14:09 +0100 |
commit | 27b030d58c8e72fc7a95187a791bd9406e350f02 (patch) | |
tree | ab3bab7f39a5ce5bab65578a7e08fa4dfdeb198c /fs/autofs4 | |
parent | 79d20b14a0d651f15b0ef9a22b6cf12d284a6d38 (diff) | |
parent | 6628465e33ca694bd8fd5c3cf4eb7ff9177bc694 (diff) |
Merge with master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/autofs_i.h | 15 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 16 | ||||
-rw-r--r-- | fs/autofs4/inode.c | 1 | ||||
-rw-r--r-- | fs/autofs4/waitq.c | 22 |
4 files changed, 40 insertions, 14 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index f5a52c87172..c7b2b889018 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -84,6 +84,7 @@ struct autofs_wait_queue { char *name; /* This is for status reporting upon return */ int status; + atomic_t notified; atomic_t wait_ctr; }; @@ -101,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 */ }; @@ -126,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) diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index 31540a6404d..500425e24fb 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -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)) { - 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); diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index a5256074662..4bb14cc6804 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -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; diff --git a/fs/autofs4/waitq.c b/fs/autofs4/waitq.c index 1ab24a662e0..5a40d36e5a5 100644 --- a/fs/autofs4/waitq.c +++ b/fs/autofs4/waitq.c @@ -210,17 +210,8 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, wq->len = len; wq->status = -EINTR; /* Status return if interrupted */ atomic_set(&wq->wait_ctr, 2); + atomic_set(&wq->notified, 1); up(&sbi->wq_sem); - - DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d", - (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); - /* autofs4_notify_daemon() may block */ - if (notify != NFY_NONE) { - autofs4_notify_daemon(sbi,wq, - notify == NFY_MOUNT ? - autofs_ptype_missing : - autofs_ptype_expire_multi); - } } else { atomic_inc(&wq->wait_ctr); up(&sbi->wq_sem); @@ -229,6 +220,17 @@ int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry, (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify); } + if (notify != NFY_NONE && atomic_dec_and_test(&wq->notified)) { + int type = (notify == NFY_MOUNT ? + autofs_ptype_missing : autofs_ptype_expire_multi); + + DPRINTK(("new wait id = 0x%08lx, name = %.*s, nfy=%d\n", + (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify)); + + /* autofs4_notify_daemon() may block */ + autofs4_notify_daemon(sbi, wq, type); + } + /* wq->name is NULL if and only if the lock is already released */ if ( sbi->catatonic ) { |