diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 21:05:59 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-05-12 21:05:59 +0000 |
commit | ba2dacab305c598cd4c34a604f8e276bf5bab5ff (patch) | |
tree | 78670a0139bf4d5ace617b29b7eba82bbc74d602 /fs/autofs4 | |
parent | b77bf69998121e689c5e86cc5630d39a0a9ee6ca (diff) |
Merge with Linux 2.3.99-pre7 and various other bits.
Diffstat (limited to 'fs/autofs4')
-rw-r--r-- | fs/autofs4/autofs_i.h | 7 | ||||
-rw-r--r-- | fs/autofs4/expire.c | 115 | ||||
-rw-r--r-- | fs/autofs4/root.c | 7 |
3 files changed, 40 insertions, 89 deletions
diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index bc23ed145..20724eb1c 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -129,9 +129,10 @@ void autofs4_free_ino(struct autofs_info *); /* Expiration */ int is_autofs4_dentry(struct dentry *); -int autofs4_expire_run(struct super_block *, struct autofs_sb_info *, - struct autofs_packet_expire *); -int autofs4_expire_multi(struct super_block *, struct autofs_sb_info *, int *); +int autofs4_expire_run(struct super_block *, struct vfsmount *, + struct autofs_sb_info *, struct autofs_packet_expire *); +int autofs4_expire_multi(struct super_block *, struct vfsmount *, + struct autofs_sb_info *, int *); /* Operations structures */ diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c index e93557db8..98a7a0e6c 100644 --- a/fs/autofs4/expire.c +++ b/fs/autofs4/expire.c @@ -14,102 +14,39 @@ #include "autofs_i.h" /* - * Determine if a dentry tree is in use. This is much the - * same as the standard is_root_busy() function, except - * that :- - * - the extra dentry reference in autofs dentries is not - * considered to be busy - * - mountpoints within the tree are not busy - * - it traverses across mountpoints - * XXX doesn't consider children of covered dentries at mountpoints + * Determine if a subtree of the namespace is busy. */ -static int is_tree_busy(struct dentry *root) +static int is_tree_busy(struct vfsmount *mnt) { - struct dentry *this_parent; + struct vfsmount *this_parent = mnt; struct list_head *next; int count; - root = root->d_mounts; - - count = root->d_count; - this_parent = root; - - DPRINTK(("is_tree_busy: starting at %.*s/%.*s, d_count=%d\n", - root->d_covers->d_parent->d_name.len, - root->d_covers->d_parent->d_name.name, - root->d_name.len, root->d_name.name, - root->d_count)); - - /* Ignore autofs's extra reference */ - if (is_autofs4_dentry(root)) { - DPRINTK(("is_tree_busy: autofs\n")); - count--; - } - - /* Mountpoints don't count (either mountee or mounter) */ - if (d_mountpoint(root) || - root != root->d_covers) { - DPRINTK(("is_tree_busy: mountpoint\n")); - count--; - } - + count = atomic_read(&mnt->mnt_count); repeat: - next = this_parent->d_mounts->d_subdirs.next; + next = this_parent->mnt_mounts.next; resume: - while (next != &this_parent->d_mounts->d_subdirs) { - int adj = 0; + while (next != &this_parent->mnt_mounts) { struct list_head *tmp = next; - struct dentry *dentry = list_entry(tmp, struct dentry, - d_child); - + struct vfsmount *p = list_entry(tmp, struct vfsmount, + mnt_child); next = tmp->next; - - dentry = dentry->d_mounts; - - DPRINTK(("is_tree_busy: considering %.*s/%.*s, d_count=%d, count=%d\n", - this_parent->d_name.len, - this_parent->d_name.name, - dentry->d_covers->d_name.len, - dentry->d_covers->d_name.name, - dentry->d_count, count)); - /* Decrement count for unused children */ - count += (dentry->d_count - 1); - - /* Mountpoints don't count (either mountee or mounter) */ - if (d_mountpoint(dentry) || - dentry != dentry->d_covers) { - DPRINTK(("is_tree_busy: mountpoint dentry=%p covers=%p mounts=%p\n", - dentry, dentry->d_covers, dentry->d_mounts)); - adj++; - } - - /* Ignore autofs's extra reference */ - if (is_autofs4_dentry(dentry)) { - DPRINTK(("is_tree_busy: autofs\n")); - adj++; - } - - count -= adj; - - if (!list_empty(&dentry->d_mounts->d_subdirs)) { - this_parent = dentry->d_mounts; + count += atomic_read(&p->mnt_count) - 1; + if (!list_empty(&p->mnt_mounts)) { + this_parent = p; goto repeat; } - /* root is busy if any leaf is busy */ - if (dentry->d_count != adj) { - DPRINTK(("is_tree_busy: busy leaf (d_count=%d adj=%d)\n", - dentry->d_count, adj)); + if (atomic_read(&p->mnt_count) > 1) return 1; - } } /* * All done at this level ... ascend and resume the search. */ - if (this_parent != root) { - next = this_parent->d_covers->d_child.next; - this_parent = this_parent->d_covers->d_parent; + if (this_parent != mnt) { + next = this_parent->mnt_child.next; + this_parent = this_parent->mnt_parent; goto resume; } @@ -124,6 +61,7 @@ resume: * - it has been unused for exp_timeout time */ static struct dentry *autofs4_expire(struct super_block *sb, + struct vfsmount *mnt, struct autofs_sb_info *sbi, int do_now) { @@ -131,6 +69,8 @@ static struct dentry *autofs4_expire(struct super_block *sb, unsigned long timeout; struct dentry *root = sb->s_root; struct list_head *tmp; + struct dentry *d; + struct vfsmount *p; if (!sbi->exp_timeout || !root) return NULL; @@ -168,8 +108,14 @@ static struct dentry *autofs4_expire(struct super_block *sb, attempts if expire fails the first time */ ino->last_used = now; } - - if (!is_tree_busy(dentry)) { + p = mntget(mnt); + d = dget(dentry); + while(d_mountpoint(d) && follow_down(&p, &d)) + ; + + if (!is_tree_busy(p)) { + dput(d); + mntput(p); DPRINTK(("autofs_expire: returning %p %.*s\n", dentry, dentry->d_name.len, dentry->d_name.name)); /* Start from here next time */ @@ -177,6 +123,8 @@ static struct dentry *autofs4_expire(struct super_block *sb, list_add(&root->d_subdirs, &dentry->d_child); return dentry; } + dput(d); + mntput(p); } return NULL; @@ -184,6 +132,7 @@ static struct dentry *autofs4_expire(struct super_block *sb, /* Perform an expiry operation */ int autofs4_expire_run(struct super_block *sb, + struct vfsmount *mnt, struct autofs_sb_info *sbi, struct autofs_packet_expire *pkt_p) { @@ -195,7 +144,7 @@ int autofs4_expire_run(struct super_block *sb, pkt.hdr.proto_version = sbi->version; pkt.hdr.type = autofs_ptype_expire; - if ((dentry = autofs4_expire(sb, sbi, 0)) == NULL) + if ((dentry = autofs4_expire(sb, mnt, sbi, 0)) == NULL) return -EAGAIN; pkt.len = dentry->d_name.len; @@ -210,7 +159,7 @@ int autofs4_expire_run(struct super_block *sb, /* Call repeatedly until it returns -EAGAIN, meaning there's nothing more to be done */ -int autofs4_expire_multi(struct super_block *sb, +int autofs4_expire_multi(struct super_block *sb, struct vfsmount *mnt, struct autofs_sb_info *sbi, int *arg) { struct dentry *dentry; @@ -220,7 +169,7 @@ int autofs4_expire_multi(struct super_block *sb, if (arg && get_user(do_now, arg)) return -EFAULT; - if ((dentry = autofs4_expire(sb, sbi, do_now)) != NULL) { + if ((dentry = autofs4_expire(sb, mnt, sbi, do_now)) != NULL) { struct autofs_info *de_info = autofs4_dentry_ino(dentry); /* This is synchronous because it makes the daemon a diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index ab05ed7d5..7f7337802 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -120,7 +120,7 @@ static void autofs4_update_usage(struct dentry *dentry) struct dentry *top = dentry->d_sb->s_root; for(; dentry != top; dentry = dentry->d_parent) { - struct autofs_info *ino = autofs4_dentry_ino(dentry->d_covers); + struct autofs_info *ino = autofs4_dentry_ino(dentry); if (ino) { update_atime(dentry->d_inode); @@ -575,11 +575,12 @@ static int autofs4_root_ioctl(struct inode *inode, struct file *filp, /* return a single thing to expire */ case AUTOFS_IOC_EXPIRE: - return autofs4_expire_run(inode->i_sb,sbi, + return autofs4_expire_run(inode->i_sb,filp->f_vfsmnt,sbi, (struct autofs_packet_expire *)arg); /* same as above, but can send multiple expires through pipe */ case AUTOFS_IOC_EXPIRE_MULTI: - return autofs4_expire_multi(inode->i_sb, sbi, (int *)arg); + return autofs4_expire_multi(inode->i_sb,filp->f_vfsmnt,sbi, + (int *)arg); default: return -ENOSYS; |