diff options
-rw-r--r-- | fs/sysfs/dir.c | 92 | ||||
-rw-r--r-- | fs/sysfs/mount.c | 24 | ||||
-rw-r--r-- | fs/sysfs/symlink.c | 26 | ||||
-rw-r--r-- | fs/sysfs/sysfs.h | 25 | ||||
-rw-r--r-- | include/linux/sysfs.h | 6 | ||||
-rw-r--r-- | lib/kobject.c | 27 |
6 files changed, 83 insertions, 117 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 5e73d6626e50..b3cf61dc57c1 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c | |||
@@ -279,7 +279,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry) | |||
279 | static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) | 279 | static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) |
280 | { | 280 | { |
281 | struct sysfs_dirent *sd; | 281 | struct sysfs_dirent *sd; |
282 | int type; | ||
283 | 282 | ||
284 | if (flags & LOOKUP_RCU) | 283 | if (flags & LOOKUP_RCU) |
285 | return -ECHILD; | 284 | return -ECHILD; |
@@ -300,13 +299,9 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) | |||
300 | goto out_bad; | 299 | goto out_bad; |
301 | 300 | ||
302 | /* The sysfs dirent has been moved to a different namespace */ | 301 | /* The sysfs dirent has been moved to a different namespace */ |
303 | type = KOBJ_NS_TYPE_NONE; | 302 | if (sd->s_parent && (sd->s_parent->s_flags & SYSFS_FLAG_NS) && |
304 | if (sd->s_parent) { | 303 | sysfs_info(dentry->d_sb)->ns != sd->s_ns) |
305 | type = sysfs_ns_type(sd->s_parent); | 304 | goto out_bad; |
306 | if (type != KOBJ_NS_TYPE_NONE && | ||
307 | sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns) | ||
308 | goto out_bad; | ||
309 | } | ||
310 | 305 | ||
311 | mutex_unlock(&sysfs_mutex); | 306 | mutex_unlock(&sysfs_mutex); |
312 | out_valid: | 307 | out_valid: |
@@ -423,13 +418,14 @@ void sysfs_addrm_start(struct sysfs_addrm_cxt *acxt) | |||
423 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, | 418 | int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd, |
424 | struct sysfs_dirent *parent_sd) | 419 | struct sysfs_dirent *parent_sd) |
425 | { | 420 | { |
421 | bool has_ns = parent_sd->s_flags & SYSFS_FLAG_NS; | ||
426 | struct sysfs_inode_attrs *ps_iattr; | 422 | struct sysfs_inode_attrs *ps_iattr; |
427 | int ret; | 423 | int ret; |
428 | 424 | ||
429 | if (!!sysfs_ns_type(parent_sd) != !!sd->s_ns) { | 425 | if (has_ns != (bool)sd->s_ns) { |
430 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 426 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", |
431 | sysfs_ns_type(parent_sd) ? "required" : "invalid", | 427 | has_ns ? "required" : "invalid", |
432 | parent_sd->s_name, sd->s_name); | 428 | parent_sd->s_name, sd->s_name); |
433 | return -EINVAL; | 429 | return -EINVAL; |
434 | } | 430 | } |
435 | 431 | ||
@@ -610,12 +606,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | |||
610 | const void *ns) | 606 | const void *ns) |
611 | { | 607 | { |
612 | struct rb_node *node = parent_sd->s_dir.children.rb_node; | 608 | struct rb_node *node = parent_sd->s_dir.children.rb_node; |
609 | bool has_ns = parent_sd->s_flags & SYSFS_FLAG_NS; | ||
613 | unsigned int hash; | 610 | unsigned int hash; |
614 | 611 | ||
615 | if (!!sysfs_ns_type(parent_sd) != !!ns) { | 612 | if (has_ns != (bool)ns) { |
616 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", | 613 | WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", |
617 | sysfs_ns_type(parent_sd) ? "required" : "invalid", | 614 | has_ns ? "required" : "invalid", |
618 | parent_sd->s_name, name); | 615 | parent_sd->s_name, name); |
619 | return NULL; | 616 | return NULL; |
620 | } | 617 | } |
621 | 618 | ||
@@ -667,7 +664,6 @@ struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd, | |||
667 | EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); | 664 | EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); |
668 | 665 | ||
669 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | 666 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, |
670 | enum kobj_ns_type type, | ||
671 | const char *name, const void *ns, | 667 | const char *name, const void *ns, |
672 | struct sysfs_dirent **p_sd) | 668 | struct sysfs_dirent **p_sd) |
673 | { | 669 | { |
@@ -681,7 +677,6 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
681 | if (!sd) | 677 | if (!sd) |
682 | return -ENOMEM; | 678 | return -ENOMEM; |
683 | 679 | ||
684 | sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT); | ||
685 | sd->s_ns = ns; | 680 | sd->s_ns = ns; |
686 | sd->s_dir.kobj = kobj; | 681 | sd->s_dir.kobj = kobj; |
687 | 682 | ||
@@ -701,33 +696,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | |||
701 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | 696 | int sysfs_create_subdir(struct kobject *kobj, const char *name, |
702 | struct sysfs_dirent **p_sd) | 697 | struct sysfs_dirent **p_sd) |
703 | { | 698 | { |
704 | return create_dir(kobj, kobj->sd, | 699 | return create_dir(kobj, kobj->sd, name, NULL, p_sd); |
705 | KOBJ_NS_TYPE_NONE, name, NULL, p_sd); | ||
706 | } | ||
707 | |||
708 | /** | ||
709 | * sysfs_read_ns_type: return associated ns_type | ||
710 | * @kobj: the kobject being queried | ||
711 | * | ||
712 | * Each kobject can be tagged with exactly one namespace type | ||
713 | * (i.e. network or user). Return the ns_type associated with | ||
714 | * this object if any | ||
715 | */ | ||
716 | static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) | ||
717 | { | ||
718 | const struct kobj_ns_type_operations *ops; | ||
719 | enum kobj_ns_type type; | ||
720 | |||
721 | ops = kobj_child_ns_ops(kobj); | ||
722 | if (!ops) | ||
723 | return KOBJ_NS_TYPE_NONE; | ||
724 | |||
725 | type = ops->type; | ||
726 | BUG_ON(type <= KOBJ_NS_TYPE_NONE); | ||
727 | BUG_ON(type >= KOBJ_NS_TYPES); | ||
728 | BUG_ON(!kobj_ns_type_registered(type)); | ||
729 | |||
730 | return type; | ||
731 | } | 700 | } |
732 | 701 | ||
733 | /** | 702 | /** |
@@ -737,7 +706,6 @@ static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) | |||
737 | */ | 706 | */ |
738 | int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) | 707 | int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) |
739 | { | 708 | { |
740 | enum kobj_ns_type type; | ||
741 | struct sysfs_dirent *parent_sd, *sd; | 709 | struct sysfs_dirent *parent_sd, *sd; |
742 | int error = 0; | 710 | int error = 0; |
743 | 711 | ||
@@ -751,9 +719,7 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) | |||
751 | if (!parent_sd) | 719 | if (!parent_sd) |
752 | return -ENOENT; | 720 | return -ENOENT; |
753 | 721 | ||
754 | type = sysfs_read_ns_type(kobj); | 722 | error = create_dir(kobj, parent_sd, kobject_name(kobj), ns, &sd); |
755 | |||
756 | error = create_dir(kobj, parent_sd, type, kobject_name(kobj), ns, &sd); | ||
757 | if (!error) | 723 | if (!error) |
758 | kobj->sd = sd; | 724 | kobj->sd = sd; |
759 | return error; | 725 | return error; |
@@ -767,13 +733,12 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry, | |||
767 | struct sysfs_dirent *parent_sd = parent->d_fsdata; | 733 | struct sysfs_dirent *parent_sd = parent->d_fsdata; |
768 | struct sysfs_dirent *sd; | 734 | struct sysfs_dirent *sd; |
769 | struct inode *inode; | 735 | struct inode *inode; |
770 | enum kobj_ns_type type; | 736 | const void *ns = NULL; |
771 | const void *ns; | ||
772 | 737 | ||
773 | mutex_lock(&sysfs_mutex); | 738 | mutex_lock(&sysfs_mutex); |
774 | 739 | ||
775 | type = sysfs_ns_type(parent_sd); | 740 | if (parent_sd->s_flags & SYSFS_FLAG_NS) |
776 | ns = sysfs_info(dir->i_sb)->ns[type]; | 741 | ns = sysfs_info(dir->i_sb)->ns; |
777 | 742 | ||
778 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); | 743 | sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); |
779 | 744 | ||
@@ -1029,6 +994,21 @@ int sysfs_move_dir_ns(struct kobject *kobj, struct kobject *new_parent_kobj, | |||
1029 | return sysfs_rename(sd, new_parent_sd, sd->s_name, new_ns); | 994 | return sysfs_rename(sd, new_parent_sd, sd->s_name, new_ns); |
1030 | } | 995 | } |
1031 | 996 | ||
997 | /** | ||
998 | * sysfs_enable_ns - enable namespace under a directory | ||
999 | * @sd: directory of interest, should be empty | ||
1000 | * | ||
1001 | * This is to be called right after @sd is created to enable namespace | ||
1002 | * under it. All children of @sd must have non-NULL namespace tags and | ||
1003 | * only the ones which match the super_block's tag will be visible. | ||
1004 | */ | ||
1005 | void sysfs_enable_ns(struct sysfs_dirent *sd) | ||
1006 | { | ||
1007 | WARN_ON_ONCE(sysfs_type(sd) != SYSFS_DIR); | ||
1008 | WARN_ON_ONCE(!RB_EMPTY_ROOT(&sd->s_dir.children)); | ||
1009 | sd->s_flags |= SYSFS_FLAG_NS; | ||
1010 | } | ||
1011 | |||
1032 | /* Relationship between s_mode and the DT_xxx types */ | 1012 | /* Relationship between s_mode and the DT_xxx types */ |
1033 | static inline unsigned char dt_type(struct sysfs_dirent *sd) | 1013 | static inline unsigned char dt_type(struct sysfs_dirent *sd) |
1034 | { | 1014 | { |
@@ -1096,15 +1076,15 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx) | |||
1096 | struct dentry *dentry = file->f_path.dentry; | 1076 | struct dentry *dentry = file->f_path.dentry; |
1097 | struct sysfs_dirent *parent_sd = dentry->d_fsdata; | 1077 | struct sysfs_dirent *parent_sd = dentry->d_fsdata; |
1098 | struct sysfs_dirent *pos = file->private_data; | 1078 | struct sysfs_dirent *pos = file->private_data; |
1099 | enum kobj_ns_type type; | 1079 | const void *ns = NULL; |
1100 | const void *ns; | ||
1101 | |||
1102 | type = sysfs_ns_type(parent_sd); | ||
1103 | ns = sysfs_info(dentry->d_sb)->ns[type]; | ||
1104 | 1080 | ||
1105 | if (!dir_emit_dots(file, ctx)) | 1081 | if (!dir_emit_dots(file, ctx)) |
1106 | return 0; | 1082 | return 0; |
1107 | mutex_lock(&sysfs_mutex); | 1083 | mutex_lock(&sysfs_mutex); |
1084 | |||
1085 | if (parent_sd->s_flags & SYSFS_FLAG_NS) | ||
1086 | ns = sysfs_info(dentry->d_sb)->ns; | ||
1087 | |||
1108 | for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); | 1088 | for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); |
1109 | pos; | 1089 | pos; |
1110 | pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { | 1090 | pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { |
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index 834ec2cdb7a3..8c24bce2f4ae 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c | |||
@@ -36,7 +36,7 @@ static const struct super_operations sysfs_ops = { | |||
36 | struct sysfs_dirent sysfs_root = { | 36 | struct sysfs_dirent sysfs_root = { |
37 | .s_name = "", | 37 | .s_name = "", |
38 | .s_count = ATOMIC_INIT(1), | 38 | .s_count = ATOMIC_INIT(1), |
39 | .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), | 39 | .s_flags = SYSFS_DIR, |
40 | .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, | 40 | .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, |
41 | .s_ino = 1, | 41 | .s_ino = 1, |
42 | }; | 42 | }; |
@@ -77,14 +77,8 @@ static int sysfs_test_super(struct super_block *sb, void *data) | |||
77 | { | 77 | { |
78 | struct sysfs_super_info *sb_info = sysfs_info(sb); | 78 | struct sysfs_super_info *sb_info = sysfs_info(sb); |
79 | struct sysfs_super_info *info = data; | 79 | struct sysfs_super_info *info = data; |
80 | enum kobj_ns_type type; | ||
81 | int found = 1; | ||
82 | 80 | ||
83 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { | 81 | return sb_info->ns == info->ns; |
84 | if (sb_info->ns[type] != info->ns[type]) | ||
85 | found = 0; | ||
86 | } | ||
87 | return found; | ||
88 | } | 82 | } |
89 | 83 | ||
90 | static int sysfs_set_super(struct super_block *sb, void *data) | 84 | static int sysfs_set_super(struct super_block *sb, void *data) |
@@ -98,9 +92,7 @@ static int sysfs_set_super(struct super_block *sb, void *data) | |||
98 | 92 | ||
99 | static void free_sysfs_super_info(struct sysfs_super_info *info) | 93 | static void free_sysfs_super_info(struct sysfs_super_info *info) |
100 | { | 94 | { |
101 | int type; | 95 | kobj_ns_drop(KOBJ_NS_TYPE_NET, info->ns); |
102 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | ||
103 | kobj_ns_drop(type, info->ns[type]); | ||
104 | kfree(info); | 96 | kfree(info); |
105 | } | 97 | } |
106 | 98 | ||
@@ -108,7 +100,6 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
108 | int flags, const char *dev_name, void *data) | 100 | int flags, const char *dev_name, void *data) |
109 | { | 101 | { |
110 | struct sysfs_super_info *info; | 102 | struct sysfs_super_info *info; |
111 | enum kobj_ns_type type; | ||
112 | struct super_block *sb; | 103 | struct super_block *sb; |
113 | int error; | 104 | int error; |
114 | 105 | ||
@@ -116,18 +107,15 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type, | |||
116 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) | 107 | if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) |
117 | return ERR_PTR(-EPERM); | 108 | return ERR_PTR(-EPERM); |
118 | 109 | ||
119 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { | 110 | if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) |
120 | if (!kobj_ns_current_may_mount(type)) | 111 | return ERR_PTR(-EPERM); |
121 | return ERR_PTR(-EPERM); | ||
122 | } | ||
123 | } | 112 | } |
124 | 113 | ||
125 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 114 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
126 | if (!info) | 115 | if (!info) |
127 | return ERR_PTR(-ENOMEM); | 116 | return ERR_PTR(-ENOMEM); |
128 | 117 | ||
129 | for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) | 118 | info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); |
130 | info->ns[type] = kobj_ns_grab_current(type); | ||
131 | 119 | ||
132 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); | 120 | sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); |
133 | if (IS_ERR(sb) || sb->s_fs_info != info) | 121 | if (IS_ERR(sb) || sb->s_fs_info != info) |
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 3ae3f1bf1a09..c660363fdaea 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c | |||
@@ -28,7 +28,6 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | |||
28 | struct sysfs_dirent *target_sd = NULL; | 28 | struct sysfs_dirent *target_sd = NULL; |
29 | struct sysfs_dirent *sd = NULL; | 29 | struct sysfs_dirent *sd = NULL; |
30 | struct sysfs_addrm_cxt acxt; | 30 | struct sysfs_addrm_cxt acxt; |
31 | enum kobj_ns_type ns_type; | ||
32 | int error; | 31 | int error; |
33 | 32 | ||
34 | BUG_ON(!name || !parent_sd); | 33 | BUG_ON(!name || !parent_sd); |
@@ -52,29 +51,16 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd, | |||
52 | if (!sd) | 51 | if (!sd) |
53 | goto out_put; | 52 | goto out_put; |
54 | 53 | ||
55 | ns_type = sysfs_ns_type(parent_sd); | 54 | if (parent_sd->s_flags & SYSFS_FLAG_NS) |
56 | if (ns_type) | ||
57 | sd->s_ns = target_sd->s_ns; | 55 | sd->s_ns = target_sd->s_ns; |
58 | sd->s_symlink.target_sd = target_sd; | 56 | sd->s_symlink.target_sd = target_sd; |
59 | target_sd = NULL; /* reference is now owned by the symlink */ | 57 | target_sd = NULL; /* reference is now owned by the symlink */ |
60 | 58 | ||
61 | sysfs_addrm_start(&acxt); | 59 | sysfs_addrm_start(&acxt); |
62 | /* Symlinks must be between directories with the same ns_type */ | 60 | if (warn) |
63 | if (!ns_type || | 61 | error = sysfs_add_one(&acxt, sd, parent_sd); |
64 | (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { | 62 | else |
65 | if (warn) | 63 | error = __sysfs_add_one(&acxt, sd, parent_sd); |
66 | error = sysfs_add_one(&acxt, sd, parent_sd); | ||
67 | else | ||
68 | error = __sysfs_add_one(&acxt, sd, parent_sd); | ||
69 | } else { | ||
70 | error = -EINVAL; | ||
71 | WARN(1, KERN_WARNING | ||
72 | "sysfs: symlink across ns_types %s/%s -> %s/%s\n", | ||
73 | parent_sd->s_name, | ||
74 | sd->s_name, | ||
75 | sd->s_symlink.target_sd->s_parent->s_name, | ||
76 | sd->s_symlink.target_sd->s_name); | ||
77 | } | ||
78 | sysfs_addrm_finish(&acxt); | 64 | sysfs_addrm_finish(&acxt); |
79 | 65 | ||
80 | if (error) | 66 | if (error) |
@@ -164,7 +150,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ, | |||
164 | * sysfs_remove_dir() for details. | 150 | * sysfs_remove_dir() for details. |
165 | */ | 151 | */ |
166 | spin_lock(&sysfs_symlink_target_lock); | 152 | spin_lock(&sysfs_symlink_target_lock); |
167 | if (targ->sd && sysfs_ns_type(kobj->sd)) | 153 | if (targ->sd && (kobj->sd->s_flags & SYSFS_FLAG_NS)) |
168 | ns = targ->sd->s_ns; | 154 | ns = targ->sd->s_ns; |
169 | spin_unlock(&sysfs_symlink_target_lock); | 155 | spin_unlock(&sysfs_symlink_target_lock); |
170 | sysfs_hash_and_remove(kobj->sd, name, ns); | 156 | sysfs_hash_and_remove(kobj->sd, name, ns); |
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index 0af09fbfb3f6..e116c21a27bf 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h | |||
@@ -90,11 +90,8 @@ struct sysfs_dirent { | |||
90 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) | 90 | #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) |
91 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) | 91 | #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) |
92 | 92 | ||
93 | /* identify any namespace tag on sysfs_dirents */ | 93 | #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK |
94 | #define SYSFS_NS_TYPE_MASK 0xf00 | 94 | #define SYSFS_FLAG_NS 0x01000 |
95 | #define SYSFS_NS_TYPE_SHIFT 8 | ||
96 | |||
97 | #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) | ||
98 | #define SYSFS_FLAG_REMOVED 0x02000 | 95 | #define SYSFS_FLAG_REMOVED 0x02000 |
99 | 96 | ||
100 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | 97 | static inline unsigned int sysfs_type(struct sysfs_dirent *sd) |
@@ -102,15 +99,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd) | |||
102 | return sd->s_flags & SYSFS_TYPE_MASK; | 99 | return sd->s_flags & SYSFS_TYPE_MASK; |
103 | } | 100 | } |
104 | 101 | ||
105 | /* | ||
106 | * Return any namespace tags on this dirent. | ||
107 | * enum kobj_ns_type is defined in linux/kobject.h | ||
108 | */ | ||
109 | static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd) | ||
110 | { | ||
111 | return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT; | ||
112 | } | ||
113 | |||
114 | #ifdef CONFIG_DEBUG_LOCK_ALLOC | 102 | #ifdef CONFIG_DEBUG_LOCK_ALLOC |
115 | 103 | ||
116 | #define sysfs_dirent_init_lockdep(sd) \ | 104 | #define sysfs_dirent_init_lockdep(sd) \ |
@@ -155,12 +143,13 @@ struct sysfs_addrm_cxt { | |||
155 | */ | 143 | */ |
156 | 144 | ||
157 | /* | 145 | /* |
158 | * Each sb is associated with a set of namespace tags (i.e. | 146 | * Each sb is associated with one namespace tag, currently the network |
159 | * the network namespace of the task which mounted this sysfs | 147 | * namespace of the task which mounted this sysfs instance. If multiple |
160 | * instance). | 148 | * tags become necessary, make the following an array and compare |
149 | * sysfs_dirent tag against every entry. | ||
161 | */ | 150 | */ |
162 | struct sysfs_super_info { | 151 | struct sysfs_super_info { |
163 | void *ns[KOBJ_NS_TYPES]; | 152 | void *ns; |
164 | }; | 153 | }; |
165 | #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) | 154 | #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) |
166 | extern struct sysfs_dirent sysfs_root; | 155 | extern struct sysfs_dirent sysfs_root; |
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h index 6695040a0317..362a34d27e64 100644 --- a/include/linux/sysfs.h +++ b/include/linux/sysfs.h | |||
@@ -220,6 +220,8 @@ int sysfs_rename_link_ns(struct kobject *kobj, struct kobject *target, | |||
220 | void sysfs_delete_link(struct kobject *dir, struct kobject *targ, | 220 | void sysfs_delete_link(struct kobject *dir, struct kobject *targ, |
221 | const char *name); | 221 | const char *name); |
222 | 222 | ||
223 | void sysfs_enable_ns(struct sysfs_dirent *sd); | ||
224 | |||
223 | int __must_check sysfs_create_group(struct kobject *kobj, | 225 | int __must_check sysfs_create_group(struct kobject *kobj, |
224 | const struct attribute_group *grp); | 226 | const struct attribute_group *grp); |
225 | int __must_check sysfs_create_groups(struct kobject *kobj, | 227 | int __must_check sysfs_create_groups(struct kobject *kobj, |
@@ -353,6 +355,10 @@ static inline void sysfs_delete_link(struct kobject *k, struct kobject *t, | |||
353 | { | 355 | { |
354 | } | 356 | } |
355 | 357 | ||
358 | static inline void sysfs_enable_ns(struct sysfs_dirent *sd) | ||
359 | { | ||
360 | } | ||
361 | |||
356 | static inline int sysfs_create_group(struct kobject *kobj, | 362 | static inline int sysfs_create_group(struct kobject *kobj, |
357 | const struct attribute_group *grp) | 363 | const struct attribute_group *grp) |
358 | { | 364 | { |
diff --git a/lib/kobject.c b/lib/kobject.c index 5b4b8886435e..16e9335b32d3 100644 --- a/lib/kobject.c +++ b/lib/kobject.c | |||
@@ -65,13 +65,17 @@ static int populate_dir(struct kobject *kobj) | |||
65 | 65 | ||
66 | static int create_dir(struct kobject *kobj) | 66 | static int create_dir(struct kobject *kobj) |
67 | { | 67 | { |
68 | const struct kobj_ns_type_operations *ops; | ||
68 | int error; | 69 | int error; |
69 | 70 | ||
70 | error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); | 71 | error = sysfs_create_dir_ns(kobj, kobject_namespace(kobj)); |
71 | if (!error) { | 72 | if (error) |
72 | error = populate_dir(kobj); | 73 | return error; |
73 | if (error) | 74 | |
74 | sysfs_remove_dir(kobj); | 75 | error = populate_dir(kobj); |
76 | if (error) { | ||
77 | sysfs_remove_dir(kobj); | ||
78 | return error; | ||
75 | } | 79 | } |
76 | 80 | ||
77 | /* | 81 | /* |
@@ -80,7 +84,20 @@ static int create_dir(struct kobject *kobj) | |||
80 | */ | 84 | */ |
81 | sysfs_get(kobj->sd); | 85 | sysfs_get(kobj->sd); |
82 | 86 | ||
83 | return error; | 87 | /* |
88 | * If @kobj has ns_ops, its children need to be filtered based on | ||
89 | * their namespace tags. Enable namespace support on @kobj->sd. | ||
90 | */ | ||
91 | ops = kobj_child_ns_ops(kobj); | ||
92 | if (ops) { | ||
93 | BUG_ON(ops->type <= KOBJ_NS_TYPE_NONE); | ||
94 | BUG_ON(ops->type >= KOBJ_NS_TYPES); | ||
95 | BUG_ON(!kobj_ns_type_registered(ops->type)); | ||
96 | |||
97 | sysfs_enable_ns(kobj->sd); | ||
98 | } | ||
99 | |||
100 | return 0; | ||
84 | } | 101 | } |
85 | 102 | ||
86 | static int get_kobj_path_length(struct kobject *kobj) | 103 | static int get_kobj_path_length(struct kobject *kobj) |