]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - fs/sysfs/mount.c
Delay struct net freeing while there's a sysfs instance refering to it
[linux-2.6.git] / fs / sysfs / mount.c
index db0b1f2138af94e58dd6e8796863c08d1955b52d..e34f0d99ea4ec5a7b3361b1fc0cd02fad2d23410 100644 (file)
 #include "sysfs.h"
 
 
-static struct vfsmount *sysfs_mount;
+static struct vfsmount *sysfs_mnt;
 struct kmem_cache *sysfs_dir_cachep;
 
 static const struct super_operations sysfs_ops = {
        .statfs         = simple_statfs,
        .drop_inode     = generic_delete_inode,
-       .delete_inode   = sysfs_delete_inode,
+       .evict_inode    = sysfs_evict_inode,
 };
 
 struct sysfs_dirent sysfs_root = {
        .s_name         = "",
        .s_count        = ATOMIC_INIT(1),
-       .s_flags        = SYSFS_DIR,
+       .s_flags        = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
        .s_mode         = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
        .s_ino          = 1,
 };
@@ -76,7 +76,13 @@ static int sysfs_test_super(struct super_block *sb, void *data)
 {
        struct sysfs_super_info *sb_info = sysfs_info(sb);
        struct sysfs_super_info *info = data;
+       enum kobj_ns_type type;
        int found = 1;
+
+       for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
+               if (sb_info->ns[type] != info->ns[type])
+                       found = 0;
+       }
        return found;
 }
 
@@ -89,52 +95,60 @@ static int sysfs_set_super(struct super_block *sb, void *data)
        return error;
 }
 
-static int sysfs_get_sb(struct file_system_type *fs_type,
-       int flags, const char *dev_name, void *data, struct vfsmount *mnt)
+static void free_sysfs_super_info(struct sysfs_super_info *info)
+{
+       int type;
+       for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
+               kobj_ns_drop(type, info->ns[type]);
+       kfree(info);
+}
+
+static struct dentry *sysfs_mount(struct file_system_type *fs_type,
+       int flags, const char *dev_name, void *data)
 {
        struct sysfs_super_info *info;
+       enum kobj_ns_type type;
        struct super_block *sb;
        int error;
 
-       error = -ENOMEM;
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (!info)
-               goto out;
+               return ERR_PTR(-ENOMEM);
+
+       for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
+               info->ns[type] = kobj_ns_grab_current(type);
+
        sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);
        if (IS_ERR(sb) || sb->s_fs_info != info)
-               kfree(info);
-       if (IS_ERR(sb)) {
-               kfree(info);
-               error = PTR_ERR(sb);
-               goto out;
-       }
+               free_sysfs_super_info(info);
+       if (IS_ERR(sb))
+               return ERR_CAST(sb);
        if (!sb->s_root) {
                sb->s_flags = flags;
                error = sysfs_fill_super(sb, data, flags & MS_SILENT ? 1 : 0);
                if (error) {
                        deactivate_locked_super(sb);
-                       goto out;
+                       return ERR_PTR(error);
                }
                sb->s_flags |= MS_ACTIVE;
        }
 
-       simple_set_mnt(mnt, sb);
-       error = 0;
-out:
-       return error;
+       return dget(sb->s_root);
 }
 
 static void sysfs_kill_sb(struct super_block *sb)
 {
        struct sysfs_super_info *info = sysfs_info(sb);
-
+       /* Remove the superblock from fs_supers/s_instances
+        * so we can't find it, before freeing sysfs_super_info.
+        */
        kill_anon_super(sb);
-       kfree(info);
+       free_sysfs_super_info(info);
 }
 
 static struct file_system_type sysfs_fs_type = {
        .name           = "sysfs",
-       .get_sb         = sysfs_get_sb,
+       .mount          = sysfs_mount,
        .kill_sb        = sysfs_kill_sb,
 };
 
@@ -154,11 +168,11 @@ int __init sysfs_init(void)
 
        err = register_filesystem(&sysfs_fs_type);
        if (!err) {
-               sysfs_mount = kern_mount(&sysfs_fs_type);
-               if (IS_ERR(sysfs_mount)) {
+               sysfs_mnt = kern_mount(&sysfs_fs_type);
+               if (IS_ERR(sysfs_mnt)) {
                        printk(KERN_ERR "sysfs: could not mount!\n");
-                       err = PTR_ERR(sysfs_mount);
-                       sysfs_mount = NULL;
+                       err = PTR_ERR(sysfs_mnt);
+                       sysfs_mnt = NULL;
                        unregister_filesystem(&sysfs_fs_type);
                        goto out_err;
                }