diff -Nurp linux-2.6.7.orig/fs/autofs4/autofs_i.h linux-2.6.7/fs/autofs4/autofs_i.h --- linux-2.6.7.orig/fs/autofs4/autofs_i.h 2004-06-16 13:19:42.000000000 +0800 +++ linux-2.6.7/fs/autofs4/autofs_i.h 2005-04-04 23:09:59.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.7.orig/fs/autofs4/expire.c linux-2.6.7/fs/autofs4/expire.c --- linux-2.6.7.orig/fs/autofs4/expire.c 2004-06-16 13:19:42.000000000 +0800 +++ linux-2.6.7/fs/autofs4/expire.c 2005-04-04 23:09:59.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; @@ -146,10 +150,10 @@ resume: return 1; } -struct dentry *autofs4_check_leaves(struct vfsmount *mnt, - struct dentry *parent, - unsigned long timeout, - int do_now) +static struct dentry *autofs4_check_leaves(struct vfsmount *mnt, + struct dentry *parent, + unsigned long timeout, + int do_now) { struct dentry *this_parent = parent; struct list_head *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.7.orig/fs/autofs4/inode.c linux-2.6.7/fs/autofs4/inode.c --- linux-2.6.7.orig/fs/autofs4/inode.c 2004-06-16 13:19:43.000000000 +0800 +++ linux-2.6.7/fs/autofs4/inode.c 2005-04-04 23:09:59.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.7.orig/fs/autofs4/root.c linux-2.6.7/fs/autofs4/root.c --- linux-2.6.7.orig/fs/autofs4/root.c 2004-06-16 13:18:52.000000000 +0800 +++ linux-2.6.7/fs/autofs4/root.c 2005-04-04 23:08:29.000000000 +0800 @@ -19,7 +19,6 @@ #include #include "autofs_i.h" -static struct dentry *autofs4_dir_lookup(struct inode *,struct dentry *, struct nameidata *); static int autofs4_dir_symlink(struct inode *,struct dentry *,const char *); static int autofs4_dir_unlink(struct inode *,struct dentry *); static int autofs4_dir_rmdir(struct inode *,struct dentry *); @@ -29,7 +28,7 @@ static int autofs4_dir_open(struct inode static int autofs4_dir_close(struct inode *inode, struct file *file); static int autofs4_dir_readdir(struct file * filp, void * dirent, filldir_t filldir); static int autofs4_root_readdir(struct file * filp, void * dirent, filldir_t filldir); -static struct dentry *autofs4_root_lookup(struct inode *,struct dentry *, struct nameidata *); +static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *); static int autofs4_dcache_readdir(struct file *, void *, filldir_t); struct file_operations autofs4_root_operations = { @@ -48,7 +47,7 @@ struct file_operations autofs4_dir_opera }; struct inode_operations autofs4_root_inode_operations = { - .lookup = autofs4_root_lookup, + .lookup = autofs4_lookup, .unlink = autofs4_dir_unlink, .symlink = autofs4_dir_symlink, .mkdir = autofs4_dir_mkdir, @@ -56,7 +55,7 @@ struct inode_operations autofs4_root_ino }; struct inode_operations autofs4_dir_inode_operations = { - .lookup = autofs4_dir_lookup, + .lookup = autofs4_lookup, .unlink = autofs4_dir_unlink, .symlink = autofs4_dir_symlink, .mkdir = autofs4_dir_mkdir, @@ -361,6 +360,7 @@ static int try_to_fill_dentry(struct den spin_lock(&dentry->d_lock); dentry->d_flags &= ~DCACHE_AUTOFS_PENDING; spin_unlock(&dentry->d_lock); + return 1; } @@ -439,23 +439,8 @@ static struct dentry_operations autofs4_ .d_release = autofs4_dentry_release, }; -/* Lookups in non-root dirs never find anything - if it's there, it's - already in the dcache */ -static struct dentry *autofs4_dir_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) -{ -#if 0 - DPRINTK("ignoring lookup of %.*s/%.*s", - dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, - dentry->d_name.len, dentry->d_name.name); -#endif - - dentry->d_fsdata = NULL; - d_add(dentry, NULL); - return NULL; -} - /* Lookups in the root directory */ -static struct dentry *autofs4_root_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) +static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) { struct autofs_sb_info *sbi; int oz_mode; diff -Nurp linux-2.6.7.orig/fs/autofs4/waitq.c linux-2.6.7/fs/autofs4/waitq.c --- linux-2.6.7.orig/fs/autofs4/waitq.c 2004-06-16 13:20:04.000000000 +0800 +++ linux-2.6.7/fs/autofs4/waitq.c 2005-04-04 23:12:29.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.7.orig/include/linux/auto_fs4.h linux-2.6.7/include/linux/auto_fs4.h --- linux-2.6.7.orig/include/linux/auto_fs4.h 2004-06-16 13:18:56.000000000 +0800 +++ linux-2.6.7/include/linux/auto_fs4.h 2005-04-04 23:10:08.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