aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-07 06:47:28 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-07 06:47:28 -0500
commita1212d278c05ca0a38f5cbd7ae90ac2e367228a8 (patch)
tree230f8bad53644f1bdd25e5c0fd892475742e7783 /fs/sysfs
parent0b1e73ed225d8f7aeef96b74147215ca8b990dce (diff)
Revert "sysfs: drop kobj_ns_type handling"
This reverts commit cb26a311578e67769e92a39a0a63476533cb7e12. It mysteriously causes NetworkManager to not find the wireless device for me. As far as I can tell, Tejun *meant* for this commit to not make any semantic changes, but there clearly are some. So revert it, taking into account some of the calling convention changes that happened in this area in subsequent commits. Cc: Tejun Heo <tj@kernel.org> Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/sysfs')
-rw-r--r--fs/sysfs/dir.c88
-rw-r--r--fs/sysfs/mount.c24
-rw-r--r--fs/sysfs/symlink.c27
-rw-r--r--fs/sysfs/sysfs.h25
4 files changed, 121 insertions, 43 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 08c66969d52a..5e73d6626e50 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -111,11 +111,6 @@ static int sysfs_link_sibling(struct sysfs_dirent *sd)
111 /* add new node and rebalance the tree */ 111 /* add new node and rebalance the tree */
112 rb_link_node(&sd->s_rb, parent, node); 112 rb_link_node(&sd->s_rb, parent, node);
113 rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children); 113 rb_insert_color(&sd->s_rb, &sd->s_parent->s_dir.children);
114
115 /* if @sd has ns tag, mark the parent to enable ns filtering */
116 if (sd->s_ns)
117 sd->s_parent->s_flags |= SYSFS_FLAG_HAS_NS;
118
119 return 0; 114 return 0;
120} 115}
121 116
@@ -135,13 +130,6 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
135 sd->s_parent->s_dir.subdirs--; 130 sd->s_parent->s_dir.subdirs--;
136 131
137 rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); 132 rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children);
138
139 /*
140 * Either all or none of the children have tags. Clearing HAS_NS
141 * when there's no child left is enough to keep the flag synced.
142 */
143 if (RB_EMPTY_ROOT(&sd->s_parent->s_dir.children))
144 sd->s_parent->s_flags &= ~SYSFS_FLAG_HAS_NS;
145} 133}
146 134
147/** 135/**
@@ -291,6 +279,7 @@ static int sysfs_dentry_delete(const struct dentry *dentry)
291static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) 279static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
292{ 280{
293 struct sysfs_dirent *sd; 281 struct sysfs_dirent *sd;
282 int type;
294 283
295 if (flags & LOOKUP_RCU) 284 if (flags & LOOKUP_RCU)
296 return -ECHILD; 285 return -ECHILD;
@@ -311,8 +300,13 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
311 goto out_bad; 300 goto out_bad;
312 301
313 /* The sysfs dirent has been moved to a different namespace */ 302 /* The sysfs dirent has been moved to a different namespace */
314 if (sd->s_ns && sd->s_ns != sysfs_info(dentry->d_sb)->ns) 303 type = KOBJ_NS_TYPE_NONE;
315 goto out_bad; 304 if (sd->s_parent) {
305 type = sysfs_ns_type(sd->s_parent);
306 if (type != KOBJ_NS_TYPE_NONE &&
307 sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns)
308 goto out_bad;
309 }
316 310
317 mutex_unlock(&sysfs_mutex); 311 mutex_unlock(&sysfs_mutex);
318out_valid: 312out_valid:
@@ -432,6 +426,13 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd,
432 struct sysfs_inode_attrs *ps_iattr; 426 struct sysfs_inode_attrs *ps_iattr;
433 int ret; 427 int ret;
434 428
429 if (!!sysfs_ns_type(parent_sd) != !!sd->s_ns) {
430 WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
431 sysfs_ns_type(parent_sd) ? "required" : "invalid",
432 parent_sd->s_name, sd->s_name);
433 return -EINVAL;
434 }
435
435 sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); 436 sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns);
436 sd->s_parent = sysfs_get(parent_sd); 437 sd->s_parent = sysfs_get(parent_sd);
437 438
@@ -611,6 +612,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
611 struct rb_node *node = parent_sd->s_dir.children.rb_node; 612 struct rb_node *node = parent_sd->s_dir.children.rb_node;
612 unsigned int hash; 613 unsigned int hash;
613 614
615 if (!!sysfs_ns_type(parent_sd) != !!ns) {
616 WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
617 sysfs_ns_type(parent_sd) ? "required" : "invalid",
618 parent_sd->s_name, name);
619 return NULL;
620 }
621
614 hash = sysfs_name_hash(name, ns); 622 hash = sysfs_name_hash(name, ns);
615 while (node) { 623 while (node) {
616 struct sysfs_dirent *sd; 624 struct sysfs_dirent *sd;
@@ -659,6 +667,7 @@ struct sysfs_dirent *sysfs_get_dirent_ns(struct sysfs_dirent *parent_sd,
659EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); 667EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns);
660 668
661static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, 669static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
670 enum kobj_ns_type type,
662 const char *name, const void *ns, 671 const char *name, const void *ns,
663 struct sysfs_dirent **p_sd) 672 struct sysfs_dirent **p_sd)
664{ 673{
@@ -672,6 +681,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
672 if (!sd) 681 if (!sd)
673 return -ENOMEM; 682 return -ENOMEM;
674 683
684 sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
675 sd->s_ns = ns; 685 sd->s_ns = ns;
676 sd->s_dir.kobj = kobj; 686 sd->s_dir.kobj = kobj;
677 687
@@ -691,7 +701,33 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
691int sysfs_create_subdir(struct kobject *kobj, const char *name, 701int sysfs_create_subdir(struct kobject *kobj, const char *name,
692 struct sysfs_dirent **p_sd) 702 struct sysfs_dirent **p_sd)
693{ 703{
694 return create_dir(kobj, kobj->sd, name, NULL, p_sd); 704 return create_dir(kobj, kobj->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 */
716static 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;
695} 731}
696 732
697/** 733/**
@@ -701,6 +737,7 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
701 */ 737 */
702int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) 738int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
703{ 739{
740 enum kobj_ns_type type;
704 struct sysfs_dirent *parent_sd, *sd; 741 struct sysfs_dirent *parent_sd, *sd;
705 int error = 0; 742 int error = 0;
706 743
@@ -714,7 +751,9 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
714 if (!parent_sd) 751 if (!parent_sd)
715 return -ENOENT; 752 return -ENOENT;
716 753
717 error = create_dir(kobj, parent_sd, kobject_name(kobj), ns, &sd); 754 type = sysfs_read_ns_type(kobj);
755
756 error = create_dir(kobj, parent_sd, type, kobject_name(kobj), ns, &sd);
718 if (!error) 757 if (!error)
719 kobj->sd = sd; 758 kobj->sd = sd;
720 return error; 759 return error;
@@ -728,12 +767,13 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry,
728 struct sysfs_dirent *parent_sd = parent->d_fsdata; 767 struct sysfs_dirent *parent_sd = parent->d_fsdata;
729 struct sysfs_dirent *sd; 768 struct sysfs_dirent *sd;
730 struct inode *inode; 769 struct inode *inode;
731 const void *ns = NULL; 770 enum kobj_ns_type type;
771 const void *ns;
732 772
733 mutex_lock(&sysfs_mutex); 773 mutex_lock(&sysfs_mutex);
734 774
735 if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS) 775 type = sysfs_ns_type(parent_sd);
736 ns = sysfs_info(dir->i_sb)->ns; 776 ns = sysfs_info(dir->i_sb)->ns[type];
737 777
738 sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); 778 sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns);
739 779
@@ -1056,15 +1096,15 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx)
1056 struct dentry *dentry = file->f_path.dentry; 1096 struct dentry *dentry = file->f_path.dentry;
1057 struct sysfs_dirent *parent_sd = dentry->d_fsdata; 1097 struct sysfs_dirent *parent_sd = dentry->d_fsdata;
1058 struct sysfs_dirent *pos = file->private_data; 1098 struct sysfs_dirent *pos = file->private_data;
1059 const void *ns = NULL; 1099 enum kobj_ns_type type;
1100 const void *ns;
1101
1102 type = sysfs_ns_type(parent_sd);
1103 ns = sysfs_info(dentry->d_sb)->ns[type];
1060 1104
1061 if (!dir_emit_dots(file, ctx)) 1105 if (!dir_emit_dots(file, ctx))
1062 return 0; 1106 return 0;
1063 mutex_lock(&sysfs_mutex); 1107 mutex_lock(&sysfs_mutex);
1064
1065 if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS)
1066 ns = sysfs_info(dentry->d_sb)->ns;
1067
1068 for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); 1108 for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos);
1069 pos; 1109 pos;
1070 pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { 1110 pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) {
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 8c24bce2f4ae..834ec2cdb7a3 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -36,7 +36,7 @@ static const struct super_operations sysfs_ops = {
36struct sysfs_dirent sysfs_root = { 36struct 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, 39 .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
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,8 +77,14 @@ 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;
80 82
81 return sb_info->ns == info->ns; 83 for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
84 if (sb_info->ns[type] != info->ns[type])
85 found = 0;
86 }
87 return found;
82} 88}
83 89
84static int sysfs_set_super(struct super_block *sb, void *data) 90static int sysfs_set_super(struct super_block *sb, void *data)
@@ -92,7 +98,9 @@ static int sysfs_set_super(struct super_block *sb, void *data)
92 98
93static void free_sysfs_super_info(struct sysfs_super_info *info) 99static void free_sysfs_super_info(struct sysfs_super_info *info)
94{ 100{
95 kobj_ns_drop(KOBJ_NS_TYPE_NET, info->ns); 101 int type;
102 for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
103 kobj_ns_drop(type, info->ns[type]);
96 kfree(info); 104 kfree(info);
97} 105}
98 106
@@ -100,6 +108,7 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
100 int flags, const char *dev_name, void *data) 108 int flags, const char *dev_name, void *data)
101{ 109{
102 struct sysfs_super_info *info; 110 struct sysfs_super_info *info;
111 enum kobj_ns_type type;
103 struct super_block *sb; 112 struct super_block *sb;
104 int error; 113 int error;
105 114
@@ -107,15 +116,18 @@ static struct dentry *sysfs_mount(struct file_system_type *fs_type,
107 if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) 116 if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type))
108 return ERR_PTR(-EPERM); 117 return ERR_PTR(-EPERM);
109 118
110 if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) 119 for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
111 return ERR_PTR(-EPERM); 120 if (!kobj_ns_current_may_mount(type))
121 return ERR_PTR(-EPERM);
122 }
112 } 123 }
113 124
114 info = kzalloc(sizeof(*info), GFP_KERNEL); 125 info = kzalloc(sizeof(*info), GFP_KERNEL);
115 if (!info) 126 if (!info)
116 return ERR_PTR(-ENOMEM); 127 return ERR_PTR(-ENOMEM);
117 128
118 info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 129 for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
130 info->ns[type] = kobj_ns_grab_current(type);
119 131
120 sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); 132 sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info);
121 if (IS_ERR(sb) || sb->s_fs_info != info) 133 if (IS_ERR(sb) || sb->s_fs_info != info)
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 1a23681b8179..3ae3f1bf1a09 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -28,6 +28,7 @@ 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;
31 int error; 32 int error;
32 33
33 BUG_ON(!name || !parent_sd); 34 BUG_ON(!name || !parent_sd);
@@ -51,15 +52,29 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd,
51 if (!sd) 52 if (!sd)
52 goto out_put; 53 goto out_put;
53 54
54 sd->s_ns = target_sd->s_ns; 55 ns_type = sysfs_ns_type(parent_sd);
56 if (ns_type)
57 sd->s_ns = target_sd->s_ns;
55 sd->s_symlink.target_sd = target_sd; 58 sd->s_symlink.target_sd = target_sd;
56 target_sd = NULL; /* reference is now owned by the symlink */ 59 target_sd = NULL; /* reference is now owned by the symlink */
57 60
58 sysfs_addrm_start(&acxt); 61 sysfs_addrm_start(&acxt);
59 if (warn) 62 /* Symlinks must be between directories with the same ns_type */
60 error = sysfs_add_one(&acxt, sd, parent_sd); 63 if (!ns_type ||
61 else 64 (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) {
62 error = __sysfs_add_one(&acxt, sd, parent_sd); 65 if (warn)
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 }
63 sysfs_addrm_finish(&acxt); 78 sysfs_addrm_finish(&acxt);
64 79
65 if (error) 80 if (error)
@@ -149,7 +164,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
149 * sysfs_remove_dir() for details. 164 * sysfs_remove_dir() for details.
150 */ 165 */
151 spin_lock(&sysfs_symlink_target_lock); 166 spin_lock(&sysfs_symlink_target_lock);
152 if (targ->sd) 167 if (targ->sd && sysfs_ns_type(kobj->sd))
153 ns = targ->sd->s_ns; 168 ns = targ->sd->s_ns;
154 spin_unlock(&sysfs_symlink_target_lock); 169 spin_unlock(&sysfs_symlink_target_lock);
155 sysfs_hash_and_remove(kobj->sd, name, ns); 170 sysfs_hash_and_remove(kobj->sd, name, ns);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index e3aea92ebfa3..0af09fbfb3f6 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -90,8 +90,11 @@ 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#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK 93/* identify any namespace tag on sysfs_dirents */
94#define SYSFS_FLAG_HAS_NS 0x01000 94#define SYSFS_NS_TYPE_MASK 0xf00
95#define SYSFS_NS_TYPE_SHIFT 8
96
97#define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK)
95#define SYSFS_FLAG_REMOVED 0x02000 98#define SYSFS_FLAG_REMOVED 0x02000
96 99
97static inline unsigned int sysfs_type(struct sysfs_dirent *sd) 100static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
@@ -99,6 +102,15 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
99 return sd->s_flags & SYSFS_TYPE_MASK; 102 return sd->s_flags & SYSFS_TYPE_MASK;
100} 103}
101 104
105/*
106 * Return any namespace tags on this dirent.
107 * enum kobj_ns_type is defined in linux/kobject.h
108 */
109static 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
102#ifdef CONFIG_DEBUG_LOCK_ALLOC 114#ifdef CONFIG_DEBUG_LOCK_ALLOC
103 115
104#define sysfs_dirent_init_lockdep(sd) \ 116#define sysfs_dirent_init_lockdep(sd) \
@@ -143,13 +155,12 @@ struct sysfs_addrm_cxt {
143 */ 155 */
144 156
145/* 157/*
146 * Each sb is associated with one namespace tag, currently the network 158 * Each sb is associated with a set of namespace tags (i.e.
147 * namespace of the task which mounted this sysfs instance. If multiple 159 * the network namespace of the task which mounted this sysfs
148 * tags become necessary, make the following an array and compare 160 * instance).
149 * sysfs_dirent tag against every entry.
150 */ 161 */
151struct sysfs_super_info { 162struct sysfs_super_info {
152 void *ns; 163 void *ns[KOBJ_NS_TYPES];
153}; 164};
154#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) 165#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
155extern struct sysfs_dirent sysfs_root; 166extern struct sysfs_dirent sysfs_root;