]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/namespace.c
Use struct path in struct svc_expkey
[net-next-2.6.git] / fs / namespace.c
index 860752998fb3172d725a642ed94221b2ac455f27..eef57635ee07c551a79ab2ad30b9438897379ba4 100644 (file)
 #include <linux/security.h>
 #include <linux/mount.h>
 #include <linux/ramfs.h>
+#include <linux/log2.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 #include "pnode.h"
 #include "internal.h"
 
+#define HASH_SHIFT ilog2(PAGE_SIZE / sizeof(struct list_head))
+#define HASH_SIZE (1UL << HASH_SHIFT)
+
 /* spinlock for vfsmount related operations, inplace of dcache_lock */
 __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
 
 static int event;
 
 static struct list_head *mount_hashtable __read_mostly;
-static int hash_mask __read_mostly, hash_bits __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
 static struct rw_semaphore namespace_sem;
 
 /* /sys/fs */
-decl_subsys(fs, NULL, NULL);
-EXPORT_SYMBOL_GPL(fs_subsys);
+struct kobject *fs_kobj;
+EXPORT_SYMBOL_GPL(fs_kobj);
 
 static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry)
 {
        unsigned long tmp = ((unsigned long)mnt / L1_CACHE_BYTES);
        tmp += ((unsigned long)dentry / L1_CACHE_BYTES);
-       tmp = tmp + (tmp >> hash_bits);
-       return tmp & hash_mask;
+       tmp = tmp + (tmp >> HASH_SHIFT);
+       return tmp & (HASH_SIZE - 1);
 }
 
 struct vfsmount *alloc_vfsmnt(const char *name)
@@ -154,13 +157,13 @@ static void __touch_mnt_namespace(struct mnt_namespace *ns)
 
 static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd)
 {
-       old_nd->dentry = mnt->mnt_mountpoint;
-       old_nd->mnt = mnt->mnt_parent;
+       old_nd->path.dentry = mnt->mnt_mountpoint;
+       old_nd->path.mnt = mnt->mnt_parent;
        mnt->mnt_parent = mnt;
        mnt->mnt_mountpoint = mnt->mnt_root;
        list_del_init(&mnt->mnt_child);
        list_del_init(&mnt->mnt_hash);
-       old_nd->dentry->d_mounted--;
+       old_nd->path.dentry->d_mounted--;
 }
 
 void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
@@ -173,10 +176,10 @@ void mnt_set_mountpoint(struct vfsmount *mnt, struct dentry *dentry,
 
 static void attach_mnt(struct vfsmount *mnt, struct nameidata *nd)
 {
-       mnt_set_mountpoint(nd->mnt, nd->dentry, mnt);
+       mnt_set_mountpoint(nd->path.mnt, nd->path.dentry, mnt);
        list_add_tail(&mnt->mnt_hash, mount_hashtable +
-                       hash(nd->mnt, nd->dentry));
-       list_add_tail(&mnt->mnt_child, &nd->mnt->mnt_mounts);
+                       hash(nd->path.mnt, nd->path.dentry));
+       list_add_tail(&mnt->mnt_child, &nd->path.mnt->mnt_mounts);
 }
 
 /*
@@ -246,7 +249,7 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
                        list_add(&mnt->mnt_slave, &old->mnt_slave_list);
                        mnt->mnt_master = old;
                        CLEAR_MNT_SHARED(mnt);
-               } else {
+               } else if (!(flag & CL_PRIVATE)) {
                        if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old))
                                list_add(&mnt->mnt_share, &old->mnt_share);
                        if (IS_MNT_SLAVE(old))
@@ -317,6 +320,50 @@ void mnt_unpin(struct vfsmount *mnt)
 
 EXPORT_SYMBOL(mnt_unpin);
 
+static inline void mangle(struct seq_file *m, const char *s)
+{
+       seq_escape(m, s, " \t\n\\");
+}
+
+/*
+ * Simple .show_options callback for filesystems which don't want to
+ * implement more complex mount option showing.
+ *
+ * See also save_mount_options().
+ */
+int generic_show_options(struct seq_file *m, struct vfsmount *mnt)
+{
+       const char *options = mnt->mnt_sb->s_options;
+
+       if (options != NULL && options[0]) {
+               seq_putc(m, ',');
+               mangle(m, options);
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL(generic_show_options);
+
+/*
+ * If filesystem uses generic_show_options(), this function should be
+ * called from the fill_super() callback.
+ *
+ * The .remount_fs callback usually needs to be handled in a special
+ * way, to make sure, that previous options are not overwritten if the
+ * remount fails.
+ *
+ * Also note, that if the filesystem's .remount_fs function doesn't
+ * reset all options to their default value, but changes only newly
+ * given options, then the displayed options will not reflect reality
+ * any more.
+ */
+void save_mount_options(struct super_block *sb, char *options)
+{
+       kfree(sb->s_options);
+       sb->s_options = kstrdup(options, GFP_KERNEL);
+}
+EXPORT_SYMBOL(save_mount_options);
+
 /* iterator */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
@@ -338,11 +385,6 @@ static void m_stop(struct seq_file *m, void *v)
        up_read(&namespace_sem);
 }
 
-static inline void mangle(struct seq_file *m, const char *s)
-{
-       seq_escape(m, s, " \t\n\\");
-}
-
 static int show_vfsmnt(struct seq_file *m, void *v)
 {
        struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
@@ -551,7 +593,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
         *  (2) the usage count == 1 [parent vfsmount] + 1 [sys_umount]
         */
        if (flags & MNT_EXPIRE) {
-               if (mnt == current->fs->rootmnt ||
+               if (mnt == current->fs->root.mnt ||
                    flags & (MNT_FORCE | MNT_DETACH))
                        return -EINVAL;
 
@@ -586,7 +628,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
         * /reboot - static binary that would close all descriptors and
         * call reboot(9). Then init(8) could umount root and exec /reboot.
         */
-       if (mnt == current->fs->rootmnt && !(flags & MNT_DETACH)) {
+       if (mnt == current->fs->root.mnt && !(flags & MNT_DETACH)) {
                /*
                 * Special case for "unmounting" root ...
                 * we just try to remount it readonly.
@@ -637,18 +679,20 @@ asmlinkage long sys_umount(char __user * name, int flags)
        if (retval)
                goto out;
        retval = -EINVAL;
-       if (nd.dentry != nd.mnt->mnt_root)
+       if (nd.path.dentry != nd.path.mnt->mnt_root)
                goto dput_and_out;
-       if (!check_mnt(nd.mnt))
+       if (!check_mnt(nd.path.mnt))
                goto dput_and_out;
 
        retval = -EPERM;
        if (!capable(CAP_SYS_ADMIN))
                goto dput_and_out;
 
-       retval = do_umount(nd.mnt, flags);
+       retval = do_umount(nd.path.mnt, flags);
 dput_and_out:
-       path_release_on_umount(&nd);
+       /* we mustn't call path_put() as that would clear mnt_expiry_mark */
+       dput(nd.path.dentry);
+       mntput_no_expire(nd.path.mnt);
 out:
        return retval;
 }
@@ -671,10 +715,10 @@ static int mount_is_safe(struct nameidata *nd)
                return 0;
        return -EPERM;
 #ifdef notyet
-       if (S_ISLNK(nd->dentry->d_inode->i_mode))
+       if (S_ISLNK(nd->path.dentry->d_inode->i_mode))
                return -EPERM;
-       if (nd->dentry->d_inode->i_mode & S_ISVTX) {
-               if (current->uid != nd->dentry->d_inode->i_uid)
+       if (nd->path.dentry->d_inode->i_mode & S_ISVTX) {
+               if (current->uid != nd->path.dentry->d_inode->i_uid)
                        return -EPERM;
        }
        if (vfs_permission(nd, MAY_WRITE))
@@ -723,8 +767,8 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
                                q = q->mnt_parent;
                        }
                        p = s;
-                       nd.mnt = q;
-                       nd.dentry = p->mnt_mountpoint;
+                       nd.path.mnt = q;
+                       nd.path.dentry = p->mnt_mountpoint;
                        q = clone_mnt(p, p->mnt_root, flag);
                        if (!q)
                                goto Enomem;
@@ -746,6 +790,26 @@ Enomem:
        return NULL;
 }
 
+struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry)
+{
+       struct vfsmount *tree;
+       down_read(&namespace_sem);
+       tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE);
+       up_read(&namespace_sem);
+       return tree;
+}
+
+void drop_collected_mounts(struct vfsmount *mnt)
+{
+       LIST_HEAD(umount_list);
+       down_read(&namespace_sem);
+       spin_lock(&vfsmount_lock);
+       umount_tree(mnt, 0, &umount_list);
+       spin_unlock(&vfsmount_lock);
+       up_read(&namespace_sem);
+       release_mounts(&umount_list);
+}
+
 /*
  *  @source_mnt : mount tree to be attached
  *  @nd         : place the mount tree @source_mnt is attached
@@ -813,8 +877,8 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
                        struct nameidata *nd, struct nameidata *parent_nd)
 {
        LIST_HEAD(tree_list);
-       struct vfsmount *dest_mnt = nd->mnt;
-       struct dentry *dest_dentry = nd->dentry;
+       struct vfsmount *dest_mnt = nd->path.mnt;
+       struct dentry *dest_dentry = nd->path.dentry;
        struct vfsmount *child, *p;
 
        if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list))
@@ -849,13 +913,13 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
        if (mnt->mnt_sb->s_flags & MS_NOUSER)
                return -EINVAL;
 
-       if (S_ISDIR(nd->dentry->d_inode->i_mode) !=
+       if (S_ISDIR(nd->path.dentry->d_inode->i_mode) !=
              S_ISDIR(mnt->mnt_root->d_inode->i_mode))
                return -ENOTDIR;
 
        err = -ENOENT;
-       mutex_lock(&nd->dentry->d_inode->i_mutex);
-       if (IS_DEADDIR(nd->dentry->d_inode))
+       mutex_lock(&nd->path.dentry->d_inode->i_mutex);
+       if (IS_DEADDIR(nd->path.dentry->d_inode))
                goto out_unlock;
 
        err = security_sb_check_sb(mnt, nd);
@@ -863,10 +927,10 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd)
                goto out_unlock;
 
        err = -ENOENT;
-       if (IS_ROOT(nd->dentry) || !d_unhashed(nd->dentry))
+       if (IS_ROOT(nd->path.dentry) || !d_unhashed(nd->path.dentry))
                err = attach_recursive_mnt(mnt, nd, NULL);
 out_unlock:
-       mutex_unlock(&nd->dentry->d_inode->i_mutex);
+       mutex_unlock(&nd->path.dentry->d_inode->i_mutex);
        if (!err)
                security_sb_post_addmount(mnt, nd);
        return err;
@@ -874,17 +938,18 @@ out_unlock:
 
 /*
  * recursively change the type of the mountpoint.
+ * noinline this do_mount helper to save do_mount stack space.
  */
-static int do_change_type(struct nameidata *nd, int flag)
+static noinline int do_change_type(struct nameidata *nd, int flag)
 {
-       struct vfsmount *m, *mnt = nd->mnt;
+       struct vfsmount *m, *mnt = nd->path.mnt;
        int recurse = flag & MS_REC;
        int type = flag & ~MS_REC;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (nd->dentry != nd->mnt->mnt_root)
+       if (nd->path.dentry != nd->path.mnt->mnt_root)
                return -EINVAL;
 
        down_write(&namespace_sem);
@@ -898,8 +963,10 @@ static int do_change_type(struct nameidata *nd, int flag)
 
 /*
  * do loopback mount.
+ * noinline this do_mount helper to save do_mount stack space.
  */
-static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
+static noinline int do_loopback(struct nameidata *nd, char *old_name,
+                               int recurse)
 {
        struct nameidata old_nd;
        struct vfsmount *mnt = NULL;
@@ -914,17 +981,17 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
 
        down_write(&namespace_sem);
        err = -EINVAL;
-       if (IS_MNT_UNBINDABLE(old_nd.mnt))
-               goto out;
+       if (IS_MNT_UNBINDABLE(old_nd.path.mnt))
+               goto out;
 
-       if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt))
+       if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt))
                goto out;
 
        err = -ENOMEM;
        if (recurse)
-               mnt = copy_tree(old_nd.mnt, old_nd.dentry, 0);
+               mnt = copy_tree(old_nd.path.mnt, old_nd.path.dentry, 0);
        else
-               mnt = clone_mnt(old_nd.mnt, old_nd.dentry, 0);
+               mnt = clone_mnt(old_nd.path.mnt, old_nd.path.dentry, 0);
 
        if (!mnt)
                goto out;
@@ -940,7 +1007,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
 
 out:
        up_write(&namespace_sem);
-       path_release(&old_nd);
+       path_put(&old_nd.path);
        return err;
 }
 
@@ -948,29 +1015,30 @@ out:
  * change filesystem flags. dir should be a physical root of filesystem.
  * If you've mounted a non-root directory somewhere and want to do remount
  * on it - tough luck.
+ * noinline this do_mount helper to save do_mount stack space.
  */
-static int do_remount(struct nameidata *nd, int flags, int mnt_flags,
+static noinline int do_remount(struct nameidata *nd, int flags, int mnt_flags,
                      void *data)
 {
        int err;
-       struct super_block *sb = nd->mnt->mnt_sb;
+       struct super_block *sb = nd->path.mnt->mnt_sb;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
 
-       if (!check_mnt(nd->mnt))
+       if (!check_mnt(nd->path.mnt))
                return -EINVAL;
 
-       if (nd->dentry != nd->mnt->mnt_root)
+       if (nd->path.dentry != nd->path.mnt->mnt_root)
                return -EINVAL;
 
        down_write(&sb->s_umount);
        err = do_remount_sb(sb, flags, data, 0);
        if (!err)
-               nd->mnt->mnt_flags = mnt_flags;
+               nd->path.mnt->mnt_flags = mnt_flags;
        up_write(&sb->s_umount);
        if (!err)
-               security_sb_post_remount(nd->mnt, flags, data);
+               security_sb_post_remount(nd->path.mnt, flags, data);
        return err;
 }
 
@@ -984,7 +1052,10 @@ static inline int tree_contains_unbindable(struct vfsmount *mnt)
        return 0;
 }
 
-static int do_move_mount(struct nameidata *nd, char *old_name)
+/*
+ * noinline this do_mount helper to save do_mount stack space.
+ */
+static noinline int do_move_mount(struct nameidata *nd, char *old_name)
 {
        struct nameidata old_nd, parent_nd;
        struct vfsmount *p;
@@ -998,69 +1069,74 @@ static int do_move_mount(struct nameidata *nd, char *old_name)
                return err;
 
        down_write(&namespace_sem);
-       while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+       while (d_mountpoint(nd->path.dentry) &&
+              follow_down(&nd->path.mnt, &nd->path.dentry))
                ;
        err = -EINVAL;
-       if (!check_mnt(nd->mnt) || !check_mnt(old_nd.mnt))
+       if (!check_mnt(nd->path.mnt) || !check_mnt(old_nd.path.mnt))
                goto out;
 
        err = -ENOENT;
-       mutex_lock(&nd->dentry->d_inode->i_mutex);
-       if (IS_DEADDIR(nd->dentry->d_inode))
+       mutex_lock(&nd->path.dentry->d_inode->i_mutex);
+       if (IS_DEADDIR(nd->path.dentry->d_inode))
                goto out1;
 
-       if (!IS_ROOT(nd->dentry) && d_unhashed(nd->dentry))
+       if (!IS_ROOT(nd->path.dentry) && d_unhashed(nd->path.dentry))
                goto out1;
 
        err = -EINVAL;
-       if (old_nd.dentry != old_nd.mnt->mnt_root)
+       if (old_nd.path.dentry != old_nd.path.mnt->mnt_root)
                goto out1;
 
-       if (old_nd.mnt == old_nd.mnt->mnt_parent)
+       if (old_nd.path.mnt == old_nd.path.mnt->mnt_parent)
                goto out1;
 
-       if (S_ISDIR(nd->dentry->d_inode->i_mode) !=
-             S_ISDIR(old_nd.dentry->d_inode->i_mode))
+       if (S_ISDIR(nd->path.dentry->d_inode->i_mode) !=
+             S_ISDIR(old_nd.path.dentry->d_inode->i_mode))
                goto out1;
        /*
         * Don't move a mount residing in a shared parent.
         */
-       if (old_nd.mnt->mnt_parent && IS_MNT_SHARED(old_nd.mnt->mnt_parent))
+       if (old_nd.path.mnt->mnt_parent &&
+           IS_MNT_SHARED(old_nd.path.mnt->mnt_parent))
                goto out1;
        /*
         * Don't move a mount tree containing unbindable mounts to a destination
         * mount which is shared.
         */
-       if (IS_MNT_SHARED(nd->mnt) && tree_contains_unbindable(old_nd.mnt))
+       if (IS_MNT_SHARED(nd->path.mnt) &&
+           tree_contains_unbindable(old_nd.path.mnt))
                goto out1;
        err = -ELOOP;
-       for (p = nd->mnt; p->mnt_parent != p; p = p->mnt_parent)
-               if (p == old_nd.mnt)
+       for (p = nd->path.mnt; p->mnt_parent != p; p = p->mnt_parent)
+               if (p == old_nd.path.mnt)
                        goto out1;
 
-       if ((err = attach_recursive_mnt(old_nd.mnt, nd, &parent_nd)))
+       err = attach_recursive_mnt(old_nd.path.mnt, nd, &parent_nd);
+       if (err)
                goto out1;
 
        spin_lock(&vfsmount_lock);
        /* if the mount is moved, it should no longer be expire
         * automatically */
-       list_del_init(&old_nd.mnt->mnt_expire);
+       list_del_init(&old_nd.path.mnt->mnt_expire);
        spin_unlock(&vfsmount_lock);
 out1:
-       mutex_unlock(&nd->dentry->d_inode->i_mutex);
+       mutex_unlock(&nd->path.dentry->d_inode->i_mutex);
 out:
        up_write(&namespace_sem);
        if (!err)
-               path_release(&parent_nd);
-       path_release(&old_nd);
+               path_put(&parent_nd.path);
+       path_put(&old_nd.path);
        return err;
 }
 
 /*
  * create a new mount for userspace and request it to be added into the
  * namespace's tree
+ * noinline this do_mount helper to save do_mount stack space.
  */
-static int do_new_mount(struct nameidata *nd, char *type, int flags,
+static noinline int do_new_mount(struct nameidata *nd, char *type, int flags,
                        int mnt_flags, char *name, void *data)
 {
        struct vfsmount *mnt;
@@ -1090,16 +1166,17 @@ int do_add_mount(struct vfsmount *newmnt, struct nameidata *nd,
 
        down_write(&namespace_sem);
        /* Something was mounted here while we slept */
-       while (d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
+       while (d_mountpoint(nd->path.dentry) &&
+              follow_down(&nd->path.mnt, &nd->path.dentry))
                ;
        err = -EINVAL;
-       if (!check_mnt(nd->mnt))
+       if (!check_mnt(nd->path.mnt))
                goto unlock;
 
        /* Refuse the same filesystem on the same mount point */
        err = -EBUSY;
-       if (nd->mnt->mnt_sb == newmnt->mnt_sb &&
-           nd->mnt->mnt_root == nd->dentry)
+       if (nd->path.mnt->mnt_sb == newmnt->mnt_sb &&
+           nd->path.mnt->mnt_root == nd->path.dentry)
                goto unlock;
 
        err = -EINVAL;
@@ -1435,7 +1512,7 @@ long do_mount(char *dev_name, char *dir_name, char *type_page,
                retval = do_new_mount(&nd, type_page, flags, mnt_flags,
                                      dev_name, data_page);
 dput_out:
-       path_release(&nd);
+       path_put(&nd.path);
        return retval;
 }
 
@@ -1482,17 +1559,17 @@ static struct mnt_namespace *dup_mnt_ns(struct mnt_namespace *mnt_ns,
        while (p) {
                q->mnt_ns = new_ns;
                if (fs) {
-                       if (p == fs->rootmnt) {
+                       if (p == fs->root.mnt) {
                                rootmnt = p;
-                               fs->rootmnt = mntget(q);
+                               fs->root.mnt = mntget(q);
                        }
-                       if (p == fs->pwdmnt) {
+                       if (p == fs->pwd.mnt) {
                                pwdmnt = p;
-                               fs->pwdmnt = mntget(q);
+                               fs->pwd.mnt = mntget(q);
                        }
-                       if (p == fs->altrootmnt) {
+                       if (p == fs->altroot.mnt) {
                                altrootmnt = p;
-                               fs->altrootmnt = mntget(q);
+                               fs->altroot.mnt = mntget(q);
                        }
                }
                p = next_mnt(p, mnt_ns->root);
@@ -1573,44 +1650,35 @@ out1:
  * Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
  * It can block. Requires the big lock held.
  */
-void set_fs_root(struct fs_struct *fs, struct vfsmount *mnt,
-                struct dentry *dentry)
+void set_fs_root(struct fs_struct *fs, struct path *path)
 {
-       struct dentry *old_root;
-       struct vfsmount *old_rootmnt;
+       struct path old_root;
+
        write_lock(&fs->lock);
        old_root = fs->root;
-       old_rootmnt = fs->rootmnt;
-       fs->rootmnt = mntget(mnt);
-       fs->root = dget(dentry);
+       fs->root = *path;
+       path_get(path);
        write_unlock(&fs->lock);
-       if (old_root) {
-               dput(old_root);
-               mntput(old_rootmnt);
-       }
+       if (old_root.dentry)
+               path_put(&old_root);
 }
 
 /*
  * Replace the fs->{pwdmnt,pwd} with {mnt,dentry}. Put the old values.
  * It can block. Requires the big lock held.
  */
-void set_fs_pwd(struct fs_struct *fs, struct vfsmount *mnt,
-               struct dentry *dentry)
+void set_fs_pwd(struct fs_struct *fs, struct path *path)
 {
-       struct dentry *old_pwd;
-       struct vfsmount *old_pwdmnt;
+       struct path old_pwd;
 
        write_lock(&fs->lock);
        old_pwd = fs->pwd;
-       old_pwdmnt = fs->pwdmnt;
-       fs->pwdmnt = mntget(mnt);
-       fs->pwd = dget(dentry);
+       fs->pwd = *path;
+       path_get(path);
        write_unlock(&fs->lock);
 
-       if (old_pwd) {
-               dput(old_pwd);
-               mntput(old_pwdmnt);
-       }
+       if (old_pwd.dentry)
+               path_put(&old_pwd);
 }
 
 static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd)
@@ -1625,12 +1693,12 @@ static void chroot_fs_refs(struct nameidata *old_nd, struct nameidata *new_nd)
                if (fs) {
                        atomic_inc(&fs->count);
                        task_unlock(p);
-                       if (fs->root == old_nd->dentry
-                           && fs->rootmnt == old_nd->mnt)
-                               set_fs_root(fs, new_nd->mnt, new_nd->dentry);
-                       if (fs->pwd == old_nd->dentry
-                           && fs->pwdmnt == old_nd->mnt)
-                               set_fs_pwd(fs, new_nd->mnt, new_nd->dentry);
+                       if (fs->root.dentry == old_nd->path.dentry
+                           && fs->root.mnt == old_nd->path.mnt)
+                               set_fs_root(fs, &new_nd->path);
+                       if (fs->pwd.dentry == old_nd->path.dentry
+                           && fs->pwd.mnt == old_nd->path.mnt)
+                               set_fs_pwd(fs, &new_nd->path);
                        put_fs_struct(fs);
                } else
                        task_unlock(p);
@@ -1680,7 +1748,7 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
        if (error)
                goto out0;
        error = -EINVAL;
-       if (!check_mnt(new_nd.mnt))
+       if (!check_mnt(new_nd.path.mnt))
                goto out1;
 
        error = __user_walk(put_old, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &old_nd);
@@ -1689,74 +1757,78 @@ asmlinkage long sys_pivot_root(const char __user * new_root,
 
        error = security_sb_pivotroot(&old_nd, &new_nd);
        if (error) {
-               path_release(&old_nd);
+               path_put(&old_nd.path);
                goto out1;
        }
 
        read_lock(&current->fs->lock);
-       user_nd.mnt = mntget(current->fs->rootmnt);
-       user_nd.dentry = dget(current->fs->root);
+       user_nd.path = current->fs->root;
+       path_get(&current->fs->root);
        read_unlock(&current->fs->lock);
        down_write(&namespace_sem);
-       mutex_lock(&old_nd.dentry->d_inode->i_mutex);
+       mutex_lock(&old_nd.path.dentry->d_inode->i_mutex);
        error = -EINVAL;
-       if (IS_MNT_SHARED(old_nd.mnt) ||
-               IS_MNT_SHARED(new_nd.mnt->mnt_parent) ||
-               IS_MNT_SHARED(user_nd.mnt->mnt_parent))
+       if (IS_MNT_SHARED(old_nd.path.mnt) ||
+               IS_MNT_SHARED(new_nd.path.mnt->mnt_parent) ||
+               IS_MNT_SHARED(user_nd.path.mnt->mnt_parent))
                goto out2;
-       if (!check_mnt(user_nd.mnt))
+       if (!check_mnt(user_nd.path.mnt))
                goto out2;
        error = -ENOENT;
-       if (IS_DEADDIR(new_nd.dentry->d_inode))
+       if (IS_DEADDIR(new_nd.path.dentry->d_inode))
                goto out2;
-       if (d_unhashed(new_nd.dentry) && !IS_ROOT(new_nd.dentry))
+       if (d_unhashed(new_nd.path.dentry) && !IS_ROOT(new_nd.path.dentry))
                goto out2;
-       if (d_unhashed(old_nd.dentry) && !IS_ROOT(old_nd.dentry))
+       if (d_unhashed(old_nd.path.dentry) && !IS_ROOT(old_nd.path.dentry))
                goto out2;
        error = -EBUSY;
-       if (new_nd.mnt == user_nd.mnt || old_nd.mnt == user_nd.mnt)
+       if (new_nd.path.mnt == user_nd.path.mnt ||
+           old_nd.path.mnt == user_nd.path.mnt)
                goto out2; /* loop, on the same file system  */
        error = -EINVAL;
-       if (user_nd.mnt->mnt_root != user_nd.dentry)
+       if (user_nd.path.mnt->mnt_root != user_nd.path.dentry)
                goto out2; /* not a mountpoint */
-       if (user_nd.mnt->mnt_parent == user_nd.mnt)
+       if (user_nd.path.mnt->mnt_parent == user_nd.path.mnt)
                goto out2; /* not attached */
-       if (new_nd.mnt->mnt_root != new_nd.dentry)
+       if (new_nd.path.mnt->mnt_root != new_nd.path.dentry)
                goto out2; /* not a mountpoint */
-       if (new_nd.mnt->mnt_parent == new_nd.mnt)
+       if (new_nd.path.mnt->mnt_parent == new_nd.path.mnt)
                goto out2; /* not attached */
-       tmp = old_nd.mnt; /* make sure we can reach put_old from new_root */
+       /* make sure we can reach put_old from new_root */
+       tmp = old_nd.path.mnt;
        spin_lock(&vfsmount_lock);
-       if (tmp != new_nd.mnt) {
+       if (tmp != new_nd.path.mnt) {
                for (;;) {
                        if (tmp->mnt_parent == tmp)
                                goto out3; /* already mounted on put_old */
-                       if (tmp->mnt_parent == new_nd.mnt)
+                       if (tmp->mnt_parent == new_nd.path.mnt)
                                break;
                        tmp = tmp->mnt_parent;
                }
-               if (!is_subdir(tmp->mnt_mountpoint, new_nd.dentry))
+               if (!is_subdir(tmp->mnt_mountpoint, new_nd.path.dentry))
                        goto out3;
-       } else if (!is_subdir(old_nd.dentry, new_nd.dentry))
+       } else if (!is_subdir(old_nd.path.dentry, new_nd.path.dentry))
                goto out3;
-       detach_mnt(new_nd.mnt, &parent_nd);
-       detach_mnt(user_nd.mnt, &root_parent);
-       attach_mnt(user_nd.mnt, &old_nd);     /* mount old root on put_old */
-       attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */
+       detach_mnt(new_nd.path.mnt, &parent_nd);
+       detach_mnt(user_nd.path.mnt, &root_parent);
+       /* mount old root on put_old */
+       attach_mnt(user_nd.path.mnt, &old_nd);
+       /* mount new_root on / */
+       attach_mnt(new_nd.path.mnt, &root_parent);
        touch_mnt_namespace(current->nsproxy->mnt_ns);
        spin_unlock(&vfsmount_lock);
        chroot_fs_refs(&user_nd, &new_nd);
        security_sb_post_pivotroot(&user_nd, &new_nd);
        error = 0;
-       path_release(&root_parent);
-       path_release(&parent_nd);
+       path_put(&root_parent.path);
+       path_put(&parent_nd.path);
 out2:
-       mutex_unlock(&old_nd.dentry->d_inode->i_mutex);
+       mutex_unlock(&old_nd.path.dentry->d_inode->i_mutex);
        up_write(&namespace_sem);
-       path_release(&user_nd);
-       path_release(&old_nd);
+       path_put(&user_nd.path);
+       path_put(&old_nd.path);
 out1:
-       path_release(&new_nd);
+       path_put(&new_nd.path);
 out0:
        unlock_kernel();
        return error;
@@ -1769,6 +1841,7 @@ static void __init init_mount_tree(void)
 {
        struct vfsmount *mnt;
        struct mnt_namespace *ns;
+       struct path root;
 
        mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
        if (IS_ERR(mnt))
@@ -1787,15 +1860,16 @@ static void __init init_mount_tree(void)
        init_task.nsproxy->mnt_ns = ns;
        get_mnt_ns(ns);
 
-       set_fs_pwd(current->fs, ns->root, ns->root->mnt_root);
-       set_fs_root(current->fs, ns->root, ns->root->mnt_root);
+       root.mnt = ns->root;
+       root.dentry = ns->root->mnt_root;
+
+       set_fs_pwd(current->fs, &root);
+       set_fs_root(current->fs, &root);
 }
 
 void __init mnt_init(void)
 {
-       struct list_head *d;
-       unsigned int nr_hash;
-       int i;
+       unsigned u;
        int err;
 
        init_rwsem(&namespace_sem);
@@ -1808,43 +1882,18 @@ void __init mnt_init(void)
        if (!mount_hashtable)
                panic("Failed to allocate mount hash table\n");
 
-       /*
-        * Find the power-of-two list-heads that can fit into the allocation..
-        * We don't guarantee that "sizeof(struct list_head)" is necessarily
-        * a power-of-two.
-        */
-       nr_hash = PAGE_SIZE / sizeof(struct list_head);
-       hash_bits = 0;
-       do {
-               hash_bits++;
-       } while ((nr_hash >> hash_bits) != 0);
-       hash_bits--;
+       printk("Mount-cache hash table entries: %lu\n", HASH_SIZE);
+
+       for (u = 0; u < HASH_SIZE; u++)
+               INIT_LIST_HEAD(&mount_hashtable[u]);
 
-       /*
-        * Re-calculate the actual number of entries and the mask
-        * from the number of bits we can fit.
-        */
-       nr_hash = 1UL << hash_bits;
-       hash_mask = nr_hash - 1;
-
-       printk("Mount-cache hash table entries: %d\n", nr_hash);
-
-       /* And initialize the newly allocated array */
-       d = mount_hashtable;
-       i = nr_hash;
-       do {
-               INIT_LIST_HEAD(d);
-               d++;
-               i--;
-       } while (i);
        err = sysfs_init();
        if (err)
                printk(KERN_WARNING "%s: sysfs_init error: %d\n",
                        __FUNCTION__, err);
-       err = subsystem_register(&fs_subsys);
-       if (err)
-               printk(KERN_WARNING "%s: subsystem_register error: %d\n",
-                       __FUNCTION__, err);
+       fs_kobj = kobject_create_and_add("fs", NULL);
+       if (!fs_kobj)
+               printk(KERN_WARNING "%s: kobj create error\n", __FUNCTION__);
        init_rootfs();
        init_mount_tree();
 }