aboutsummaryrefslogtreecommitdiff
path: root/fs/sysfs/mount.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 10:48:32 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2010-05-21 10:48:32 -0700
commitd6fb1db02e02aea98f2d7e121fd30e24c84639d6 (patch)
tree865546f0388c40d52cf98febe2c6d21039915ea2 /fs/sysfs/mount.c
parentb4e6b09738fde057ce885703705f71cc953d0512 (diff)
parenta1b3f594dc5faab91d3a218c7019e9b5edd9fe1a (diff)
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core-2.6: (38 commits) net: Expose all network devices in a namespaces in sysfs hotplug: netns aware uevent_helper kobj: Send hotplug events in the proper namespace. netlink: Implment netlink_broadcast_filtered net/sysfs: Fix the bitrot in network device kobject namespace support netns: Teach network device kobjects which namespace they are in. kobject: Send hotplug events in all network namespaces driver-core: fix Typo in drivers/base/core.c for CONFIG_MODULE pci: check caps from sysfs file open to read device dependent config space sysfs: add struct file* to bin_attr callbacks sysfs: Remove usage of S_BIAS to avoid merge conflict with the vfs tree sysfs: Don't use enums in inline function declaration. sysfs-namespaces: add a high-level Documentation file sysfs: Comment sysfs directory tagging logic driver core: Implement ns directory support for device classes. sysfs: Implement sysfs_delete_link sysfs: Add support for tagged directories with untagged members. sysfs: Implement sysfs tagged directory support. kobj: Add basic infrastructure for dealing with namespaces. sysfs: Remove double free sysfs_get_sb ...
Diffstat (limited to 'fs/sysfs/mount.c')
-rw-r--r--fs/sysfs/mount.c95
1 files changed, 92 insertions, 3 deletions
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 776137828dc..281c0c9bc39 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -35,7 +35,7 @@ static const struct super_operations sysfs_ops = {
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,
};
@@ -72,18 +72,107 @@ static int sysfs_fill_super(struct super_block *sb, void *data, int silent)
return 0;
}
+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;
+}
+
+static int sysfs_set_super(struct super_block *sb, void *data)
+{
+ int error;
+ error = set_anon_super(sb, data);
+ if (!error)
+ sb->s_fs_info = 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)
{
- return get_sb_single(fs_type, flags, data, sysfs_fill_super, mnt);
+ 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;
+
+ for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
+ info->ns[type] = kobj_ns_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)) {
+ error = PTR_ERR(sb);
+ goto out;
+ }
+ 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;
+ }
+ sb->s_flags |= MS_ACTIVE;
+ }
+
+ simple_set_mnt(mnt, sb);
+ error = 0;
+out:
+ return error;
+}
+
+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);
}
static struct file_system_type sysfs_fs_type = {
.name = "sysfs",
.get_sb = sysfs_get_sb,
- .kill_sb = kill_anon_super,
+ .kill_sb = sysfs_kill_sb,
};
+void sysfs_exit_ns(enum kobj_ns_type type, const void *ns)
+{
+ struct super_block *sb;
+
+ mutex_lock(&sysfs_mutex);
+ spin_lock(&sb_lock);
+ list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) {
+ struct sysfs_super_info *info = sysfs_info(sb);
+ /*
+ * If we see a superblock on the fs_supers/s_instances
+ * list the unmount has not completed and sb->s_fs_info
+ * points to a valid struct sysfs_super_info.
+ */
+ /* Ignore superblocks with the wrong ns */
+ if (info->ns[type] != ns)
+ continue;
+ info->ns[type] = NULL;
+ }
+ spin_unlock(&sb_lock);
+ mutex_unlock(&sysfs_mutex);
+}
+
int __init sysfs_init(void)
{
int err = -ENOMEM;