linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / fs / namespace.c
index 4bcb3ae..d9fbad9 100644 (file)
@@ -8,6 +8,7 @@
  * Heavily rewritten.
  */
 
+#include <linux/config.h>
 #include <linux/syscalls.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
@@ -44,9 +45,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 +88,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 +444,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 +466,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 +488,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 +524,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 +583,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 +1178,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 +1185,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 +1209,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 +1558,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.