]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/namespace.c
switch follow_down()
[net-next-2.6.git] / fs / namespace.c
index 41196209a9062d5ed62d520b1b77a910751e6fb9..ba5237be1cf982e1953ffe829d79742a3e73c30e 100644 (file)
@@ -695,12 +695,16 @@ static inline void mangle(struct seq_file *m, const char *s)
  */
 int generic_show_options(struct seq_file *m, struct vfsmount *mnt)
 {
-       const char *options = mnt->mnt_sb->s_options;
+       const char *options;
+
+       rcu_read_lock();
+       options = rcu_dereference(mnt->mnt_sb->s_options);
 
        if (options != NULL && options[0]) {
                seq_putc(m, ',');
                mangle(m, options);
        }
+       rcu_read_unlock();
 
        return 0;
 }
@@ -721,11 +725,22 @@ EXPORT_SYMBOL(generic_show_options);
  */
 void save_mount_options(struct super_block *sb, char *options)
 {
-       kfree(sb->s_options);
-       sb->s_options = kstrdup(options, GFP_KERNEL);
+       BUG_ON(sb->s_options);
+       rcu_assign_pointer(sb->s_options, kstrdup(options, GFP_KERNEL));
 }
 EXPORT_SYMBOL(save_mount_options);
 
+void replace_mount_options(struct super_block *sb, char *options)
+{
+       char *old = sb->s_options;
+       rcu_assign_pointer(sb->s_options, options);
+       if (old) {
+               synchronize_rcu();
+               kfree(old);
+       }
+}
+EXPORT_SYMBOL(replace_mount_options);
+
 #ifdef CONFIG_PROC_FS
 /* iterator */
 static void *m_start(struct seq_file *m, loff_t *pos)
@@ -1073,9 +1088,7 @@ static int do_umount(struct vfsmount *mnt, int flags)
         */
 
        if (flags & MNT_FORCE && sb->s_op->umount_begin) {
-               lock_kernel();
                sb->s_op->umount_begin(sb);
-               unlock_kernel();
        }
 
        /*
@@ -1240,11 +1253,11 @@ Enomem:
        return NULL;
 }
 
-struct vfsmount *collect_mounts(struct vfsmount *mnt, struct dentry *dentry)
+struct vfsmount *collect_mounts(struct path *path)
 {
        struct vfsmount *tree;
        down_write(&namespace_sem);
-       tree = copy_tree(mnt, dentry, CL_COPY_ALL | CL_PRIVATE);
+       tree = copy_tree(path->mnt, path->dentry, CL_COPY_ALL | CL_PRIVATE);
        up_write(&namespace_sem);
        return tree;
 }
@@ -1588,7 +1601,7 @@ static int do_move_mount(struct path *path, char *old_name)
 
        down_write(&namespace_sem);
        while (d_mountpoint(path->dentry) &&
-              follow_down(&path->mnt, &path->dentry))
+              follow_down(path))
                ;
        err = -EINVAL;
        if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
@@ -1682,10 +1695,10 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
        down_write(&namespace_sem);
        /* Something was mounted here while we slept */
        while (d_mountpoint(path->dentry) &&
-              follow_down(&path->mnt, &path->dentry))
+              follow_down(path))
                ;
        err = -EINVAL;
-       if (!check_mnt(path->mnt))
+       if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
                goto unlock;
 
        /* Refuse the same filesystem on the same mount point */