X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=fs%2Fnamespace.c;h=5c68a3f459d28e4a02e855cb1d18084c73ac3c93;hb=bdeeeef70891d1ba02473622925d94cea9cb9560;hp=4bcb3ae8fe4caa30e85ae69a08e4a5d990a0062d;hpb=3944158a6d33f94668dbd6bdc32ff5c67bb53ec2;p=linux-2.6.git diff --git a/fs/namespace.c b/fs/namespace.c index 4bcb3ae8f..5c68a3f45 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -8,6 +8,7 @@ * Heavily rewritten. */ +#include #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -44,9 +46,9 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); static int event; -static struct list_head *mount_hashtable __read_mostly; +static struct list_head *mount_hashtable; static int hash_mask __read_mostly, hash_bits __read_mostly; -static kmem_cache_t *mnt_cache __read_mostly; +static kmem_cache_t *mnt_cache; static struct rw_semaphore namespace_sem; /* /sys/fs */ @@ -87,15 +89,6 @@ struct vfsmount *alloc_vfsmnt(const char *name) return mnt; } -int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb) -{ - mnt->mnt_sb = sb; - mnt->mnt_root = dget(sb->s_root); - return 0; -} - -EXPORT_SYMBOL(simple_set_mnt); - void free_vfsmnt(struct vfsmount *mnt) { kfree(mnt->mnt_devname); @@ -452,54 +445,6 @@ struct seq_operations mounts_op = { .show = show_vfsmnt }; -static int show_vfsstat(struct seq_file *m, void *v) -{ - struct vfsmount *mnt = v; - int err = 0; - - if (vx_flags(VXF_HIDE_MOUNT, 0)) - return 0; - if (!mnt_is_reachable(mnt) && !vx_check(0, VX_WATCH)) - return 0; - - if (!vx_check(0, VX_ADMIN|VX_WATCH) && - mnt == current->fs->rootmnt) { - seq_puts(m, "device /dev/root mounted on / "); - } else { - /* device */ - if (mnt->mnt_devname) { - seq_puts(m, "device "); - mangle(m, mnt->mnt_devname); - } else - seq_puts(m, "no device"); - - /* mount point */ - seq_puts(m, " mounted on "); - seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); - seq_putc(m, ' '); - } - - /* file system type */ - seq_puts(m, "with fstype "); - mangle(m, mnt->mnt_sb->s_type->name); - - /* optional statistics */ - if (mnt->mnt_sb->s_op->show_stats) { - seq_putc(m, ' '); - err = mnt->mnt_sb->s_op->show_stats(m, mnt); - } - - seq_putc(m, '\n'); - return err; -} - -struct seq_operations mountstats_op = { - .start = m_start, - .next = m_next, - .stop = m_stop, - .show = show_vfsstat, -}; - /** * may_umount_tree - check if a mount tree is busy * @mnt: root of mount tree @@ -522,9 +467,9 @@ int may_umount_tree(struct vfsmount *mnt) spin_unlock(&vfsmount_lock); if (actual_refs > minimum_refs) - return 0; + return -EBUSY; - return 1; + return 0; } EXPORT_SYMBOL(may_umount_tree); @@ -544,10 +489,10 @@ EXPORT_SYMBOL(may_umount_tree); */ int may_umount(struct vfsmount *mnt) { - int ret = 1; + int ret = 0; spin_lock(&vfsmount_lock); if (propagate_mount_busy(mnt, 2)) - ret = 0; + ret = -EBUSY; spin_unlock(&vfsmount_lock); return ret; } @@ -580,8 +525,10 @@ void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill) { struct vfsmount *p; - for (p = mnt; p; p = next_mnt(p, mnt)) - list_move(&p->mnt_hash, kill); + for (p = mnt; p; p = next_mnt(p, mnt)) { + list_del(&p->mnt_hash); + list_add(&p->mnt_hash, kill); + } if (propagate) propagate_umount(kill); @@ -637,8 +584,8 @@ static int do_umount(struct vfsmount *mnt, int flags) */ lock_kernel(); - if (sb->s_op->umount_begin) - sb->s_op->umount_begin(mnt, flags); + if ((flags & MNT_FORCE) && sb->s_op->umount_begin) + sb->s_op->umount_begin(sb); unlock_kernel(); /* @@ -1232,40 +1179,6 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts, } } -/* - * go through the vfsmounts we've just consigned to the graveyard to - * - check that they're still dead - * - delete the vfsmount from the appropriate namespace under lock - * - dispose of the corpse - */ -static void expire_mount_list(struct list_head *graveyard, struct list_head *mounts) -{ - struct namespace *namespace; - struct vfsmount *mnt; - - while (!list_empty(graveyard)) { - LIST_HEAD(umounts); - mnt = list_entry(graveyard->next, struct vfsmount, mnt_expire); - list_del_init(&mnt->mnt_expire); - - /* don't do anything if the namespace is dead - all the - * vfsmounts from it are going away anyway */ - namespace = mnt->mnt_namespace; - if (!namespace || !namespace->root) - continue; - get_namespace(namespace); - - spin_unlock(&vfsmount_lock); - down_write(&namespace_sem); - expire_mount(mnt, mounts, &umounts); - up_write(&namespace_sem); - release_mounts(&umounts); - mntput(mnt); - put_namespace(namespace); - spin_lock(&vfsmount_lock); - } -} - /* * process a list of expirable mountpoints with the intent of discarding any * mountpoints that aren't in use and haven't been touched since last we came @@ -1273,6 +1186,7 @@ static void expire_mount_list(struct list_head *graveyard, struct list_head *mou */ void mark_mounts_for_expiry(struct list_head *mounts) { + struct namespace *namespace; struct vfsmount *mnt, *next; LIST_HEAD(graveyard); @@ -1296,79 +1210,38 @@ void mark_mounts_for_expiry(struct list_head *mounts) list_move(&mnt->mnt_expire, &graveyard); } - expire_mount_list(&graveyard, mounts); - - spin_unlock(&vfsmount_lock); -} - -EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); - -/* - * Ripoff of 'select_parent()' - * - * search the list of submounts for a given mountpoint, and move any - * shrinkable submounts to the 'graveyard' list. - */ -static int select_submounts(struct vfsmount *parent, struct list_head *graveyard) -{ - struct vfsmount *this_parent = parent; - struct list_head *next; - int found = 0; - -repeat: - next = this_parent->mnt_mounts.next; -resume: - while (next != &this_parent->mnt_mounts) { - struct list_head *tmp = next; - struct vfsmount *mnt = list_entry(tmp, struct vfsmount, mnt_child); - - next = tmp->next; - if (!(mnt->mnt_flags & MNT_SHRINKABLE)) - continue; - /* - * Descend a level if the d_mounts list is non-empty. - */ - if (!list_empty(&mnt->mnt_mounts)) { - this_parent = mnt; - goto repeat; - } - - if (!propagate_mount_busy(mnt, 1)) { - mntget(mnt); - list_move_tail(&mnt->mnt_expire, graveyard); - found++; - } - } /* - * All done at this level ... ascend and resume the search + * go through the vfsmounts we've just consigned to the graveyard to + * - check that they're still dead + * - delete the vfsmount from the appropriate namespace under lock + * - dispose of the corpse */ - if (this_parent != parent) { - next = this_parent->mnt_child.next; - this_parent = this_parent->mnt_parent; - goto resume; - } - return found; -} - -/* - * process a list of expirable mountpoints with the intent of discarding any - * submounts of a specific parent mountpoint - */ -void shrink_submounts(struct vfsmount *mountpoint, struct list_head *mounts) -{ - LIST_HEAD(graveyard); - int found; + while (!list_empty(&graveyard)) { + LIST_HEAD(umounts); + mnt = list_entry(graveyard.next, struct vfsmount, mnt_expire); + list_del_init(&mnt->mnt_expire); - spin_lock(&vfsmount_lock); + /* don't do anything if the namespace is dead - all the + * vfsmounts from it are going away anyway */ + namespace = mnt->mnt_namespace; + if (!namespace || !namespace->root) + continue; + get_namespace(namespace); - /* extract submounts of 'mountpoint' from the expiration list */ - while ((found = select_submounts(mountpoint, &graveyard)) != 0) - expire_mount_list(&graveyard, mounts); + spin_unlock(&vfsmount_lock); + down_write(&namespace_sem); + expire_mount(mnt, mounts, &umounts); + up_write(&namespace_sem); + release_mounts(&umounts); + mntput(mnt); + put_namespace(namespace); + spin_lock(&vfsmount_lock); + } spin_unlock(&vfsmount_lock); } -EXPORT_SYMBOL_GPL(shrink_submounts); +EXPORT_SYMBOL_GPL(mark_mounts_for_expiry); /* * Some copy_from_user() implementations do not return the exact number of @@ -1686,8 +1559,6 @@ void set_fs_root(struct fs_struct *fs, struct vfsmount *mnt, } } -EXPORT_SYMBOL_GPL(set_fs_root); - /* * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values. * It can block. Requires the big lock held.