diff -Nurp linux-2.6.10.orig/fs/autofs4/autofs_i.h linux-2.6.10/fs/autofs4/autofs_i.h --- linux-2.6.10.orig/fs/autofs4/autofs_i.h 2004-10-19 05:54:38.000000000 +0800 +++ linux-2.6.10/fs/autofs4/autofs_i.h 2005-04-05 20:12:00.000000000 +0800 @@ -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 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 -Nurp linux-2.6.10.orig/fs/autofs4/expire.c linux-2.6.10/fs/autofs4/expire.c --- linux-2.6.10.orig/fs/autofs4/expire.c 2004-10-19 05:54:39.000000000 +0800 +++ linux-2.6.10/fs/autofs4/expire.c 2005-04-05 20:12:00.000000000 +0800 @@ -99,6 +99,10 @@ static int autofs4_check_tree(struct vfs 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(str /* 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 -Nurp linux-2.6.10.orig/fs/autofs4/inode.c linux-2.6.10/fs/autofs4/inode.c --- linux-2.6.10.orig/fs/autofs4/inode.c 2005-04-05 00:09:11.000000000 +0800 +++ linux-2.6.10/fs/autofs4/inode.c 2005-04-05 20:12:00.000000000 +0800 @@ -206,6 +206,7 @@ int autofs4_fill_super(struct super_bloc 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 -Nurp linux-2.6.10.orig/fs/autofs4/waitq.c linux-2.6.10/fs/autofs4/waitq.c --- linux-2.6.10.orig/fs/autofs4/waitq.c 2004-10-19 05:55:27.000000000 +0800 +++ linux-2.6.10/fs/autofs4/waitq.c 2005-04-05 20:11:54.000000000 +0800 @@ -210,24 +210,27 @@ int autofs4_wait(struct autofs_sb_info * 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); + kfree(name); DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d", (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 ) { diff -Nurp linux-2.6.10.orig/include/linux/auto_fs4.h linux-2.6.10/include/linux/auto_fs4.h --- linux-2.6.10.orig/include/linux/auto_fs4.h 2004-10-19 05:53:08.000000000 +0800 +++ linux-2.6.10/include/linux/auto_fs4.h 2005-04-05 20:12:06.000000000 +0800 @@ -23,7 +23,7 @@ #define AUTOFS_MIN_PROTO_VERSION 3 #define AUTOFS_MAX_PROTO_VERSION 4 -#define AUTOFS_PROTO_SUBVERSION 5 +#define AUTOFS_PROTO_SUBVERSION 6 /* Mask for expire behaviour */ #define AUTOFS_EXP_IMMEDIATE 1