aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/sysfs/dir.c90
-rw-r--r--fs/sysfs/mount.c24
-rw-r--r--fs/sysfs/symlink.c27
-rw-r--r--fs/sysfs/sysfs.h25
-rw-r--r--lib/kobject.c5
5 files changed, 48 insertions, 123 deletions
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 878ac3afe1b8..1dfb4aaf9446 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -111,6 +111,11 @@ 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
114 return 0; 119 return 0;
115} 120}
116 121
@@ -130,6 +135,13 @@ static void sysfs_unlink_sibling(struct sysfs_dirent *sd)
130 sd->s_parent->s_dir.subdirs--; 135 sd->s_parent->s_dir.subdirs--;
131 136
132 rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); 137 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;
133} 145}
134 146
135#ifdef CONFIG_DEBUG_LOCK_ALLOC 147#ifdef CONFIG_DEBUG_LOCK_ALLOC
@@ -297,7 +309,6 @@ static int sysfs_dentry_delete(const struct dentry *dentry)
297static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) 309static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
298{ 310{
299 struct sysfs_dirent *sd; 311 struct sysfs_dirent *sd;
300 int type;
301 312
302 if (flags & LOOKUP_RCU) 313 if (flags & LOOKUP_RCU)
303 return -ECHILD; 314 return -ECHILD;
@@ -318,13 +329,8 @@ static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags)
318 goto out_bad; 329 goto out_bad;
319 330
320 /* The sysfs dirent has been moved to a different namespace */ 331 /* The sysfs dirent has been moved to a different namespace */
321 type = KOBJ_NS_TYPE_NONE; 332 if (sd->s_ns && sd->s_ns != sysfs_info(dentry->d_sb)->ns)
322 if (sd->s_parent) { 333 goto out_bad;
323 type = sysfs_ns_type(sd->s_parent);
324 if (type != KOBJ_NS_TYPE_NONE &&
325 sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns)
326 goto out_bad;
327 }
328 334
329 mutex_unlock(&sysfs_mutex); 335 mutex_unlock(&sysfs_mutex);
330out_valid: 336out_valid:
@@ -445,13 +451,6 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
445 struct sysfs_inode_attrs *ps_iattr; 451 struct sysfs_inode_attrs *ps_iattr;
446 int ret; 452 int ret;
447 453
448 if (!!sysfs_ns_type(acxt->parent_sd) != !!sd->s_ns) {
449 WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
450 sysfs_ns_type(acxt->parent_sd) ? "required" : "invalid",
451 acxt->parent_sd->s_name, sd->s_name);
452 return -EINVAL;
453 }
454
455 sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name); 454 sd->s_hash = sysfs_name_hash(sd->s_ns, sd->s_name);
456 sd->s_parent = sysfs_get(acxt->parent_sd); 455 sd->s_parent = sysfs_get(acxt->parent_sd);
457 456
@@ -613,13 +612,6 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
613 struct rb_node *node = parent_sd->s_dir.children.rb_node; 612 struct rb_node *node = parent_sd->s_dir.children.rb_node;
614 unsigned int hash; 613 unsigned int hash;
615 614
616 if (!!sysfs_ns_type(parent_sd) != !!ns) {
617 WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n",
618 sysfs_ns_type(parent_sd) ? "required" : "invalid",
619 parent_sd->s_name, name);
620 return NULL;
621 }
622
623 hash = sysfs_name_hash(ns, name); 615 hash = sysfs_name_hash(ns, name);
624 while (node) { 616 while (node) {
625 struct sysfs_dirent *sd; 617 struct sysfs_dirent *sd;
@@ -667,8 +659,7 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
667EXPORT_SYMBOL_GPL(sysfs_get_dirent); 659EXPORT_SYMBOL_GPL(sysfs_get_dirent);
668 660
669static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, 661static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
670 enum kobj_ns_type type, const void *ns, const char *name, 662 const void *ns, const char *name, struct sysfs_dirent **p_sd)
671 struct sysfs_dirent **p_sd)
672{ 663{
673 umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; 664 umode_t mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO;
674 struct sysfs_addrm_cxt acxt; 665 struct sysfs_addrm_cxt acxt;
@@ -680,7 +671,6 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
680 if (!sd) 671 if (!sd)
681 return -ENOMEM; 672 return -ENOMEM;
682 673
683 sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
684 sd->s_ns = ns; 674 sd->s_ns = ns;
685 sd->s_dir.kobj = kobj; 675 sd->s_dir.kobj = kobj;
686 676
@@ -700,33 +690,7 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
700int sysfs_create_subdir(struct kobject *kobj, const char *name, 690int sysfs_create_subdir(struct kobject *kobj, const char *name,
701 struct sysfs_dirent **p_sd) 691 struct sysfs_dirent **p_sd)
702{ 692{
703 return create_dir(kobj, kobj->sd, 693 return create_dir(kobj, kobj->sd, NULL, name, p_sd);
704 KOBJ_NS_TYPE_NONE, NULL, name, p_sd);
705}
706
707/**
708 * sysfs_read_ns_type: return associated ns_type
709 * @kobj: the kobject being queried
710 *
711 * Each kobject can be tagged with exactly one namespace type
712 * (i.e. network or user). Return the ns_type associated with
713 * this object if any
714 */
715static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj)
716{
717 const struct kobj_ns_type_operations *ops;
718 enum kobj_ns_type type;
719
720 ops = kobj_child_ns_ops(kobj);
721 if (!ops)
722 return KOBJ_NS_TYPE_NONE;
723
724 type = ops->type;
725 BUG_ON(type <= KOBJ_NS_TYPE_NONE);
726 BUG_ON(type >= KOBJ_NS_TYPES);
727 BUG_ON(!kobj_ns_type_registered(type));
728
729 return type;
730} 694}
731 695
732/** 696/**
@@ -736,7 +700,6 @@ static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj)
736 */ 700 */
737int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) 701int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
738{ 702{
739 enum kobj_ns_type type;
740 struct sysfs_dirent *parent_sd, *sd; 703 struct sysfs_dirent *parent_sd, *sd;
741 int error = 0; 704 int error = 0;
742 705
@@ -750,9 +713,7 @@ int sysfs_create_dir_ns(struct kobject *kobj, const void *ns)
750 if (!parent_sd) 713 if (!parent_sd)
751 return -ENOENT; 714 return -ENOENT;
752 715
753 type = sysfs_read_ns_type(kobj); 716 error = create_dir(kobj, parent_sd, ns, kobject_name(kobj), &sd);
754
755 error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
756 if (!error) 717 if (!error)
757 kobj->sd = sd; 718 kobj->sd = sd;
758 return error; 719 return error;
@@ -766,13 +727,12 @@ static struct dentry *sysfs_lookup(struct inode *dir, struct dentry *dentry,
766 struct sysfs_dirent *parent_sd = parent->d_fsdata; 727 struct sysfs_dirent *parent_sd = parent->d_fsdata;
767 struct sysfs_dirent *sd; 728 struct sysfs_dirent *sd;
768 struct inode *inode; 729 struct inode *inode;
769 enum kobj_ns_type type; 730 const void *ns = NULL;
770 const void *ns;
771 731
772 mutex_lock(&sysfs_mutex); 732 mutex_lock(&sysfs_mutex);
773 733
774 type = sysfs_ns_type(parent_sd); 734 if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS)
775 ns = sysfs_info(dir->i_sb)->ns[type]; 735 ns = sysfs_info(dir->i_sb)->ns;
776 736
777 sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name); 737 sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name);
778 738
@@ -995,15 +955,15 @@ static int sysfs_readdir(struct file *file, struct dir_context *ctx)
995 struct dentry *dentry = file->f_path.dentry; 955 struct dentry *dentry = file->f_path.dentry;
996 struct sysfs_dirent *parent_sd = dentry->d_fsdata; 956 struct sysfs_dirent *parent_sd = dentry->d_fsdata;
997 struct sysfs_dirent *pos = file->private_data; 957 struct sysfs_dirent *pos = file->private_data;
998 enum kobj_ns_type type; 958 const void *ns = NULL;
999 const void *ns;
1000
1001 type = sysfs_ns_type(parent_sd);
1002 ns = sysfs_info(dentry->d_sb)->ns[type];
1003 959
1004 if (!dir_emit_dots(file, ctx)) 960 if (!dir_emit_dots(file, ctx))
1005 return 0; 961 return 0;
1006 mutex_lock(&sysfs_mutex); 962 mutex_lock(&sysfs_mutex);
963
964 if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS)
965 ns = sysfs_info(dentry->d_sb)->ns;
966
1007 for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); 967 for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos);
1008 pos; 968 pos;
1009 pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) { 969 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 = {
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 | (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
90static int sysfs_set_super(struct super_block *sb, void *data) 84static 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
99static void free_sysfs_super_info(struct sysfs_super_info *info) 93static 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 12d58ada3e6d..7d981ce2e87f 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);
@@ -50,29 +49,15 @@ static int sysfs_do_create_link_sd(struct sysfs_dirent *parent_sd,
50 if (!sd) 49 if (!sd)
51 goto out_put; 50 goto out_put;
52 51
53 ns_type = sysfs_ns_type(parent_sd); 52 sd->s_ns = target_sd->s_ns;
54 if (ns_type)
55 sd->s_ns = target_sd->s_ns;
56 sd->s_symlink.target_sd = target_sd; 53 sd->s_symlink.target_sd = target_sd;
57 target_sd = NULL; /* reference is now owned by the symlink */ 54 target_sd = NULL; /* reference is now owned by the symlink */
58 55
59 sysfs_addrm_start(&acxt, parent_sd); 56 sysfs_addrm_start(&acxt, parent_sd);
60 /* Symlinks must be between directories with the same ns_type */ 57 if (warn)
61 if (!ns_type || 58 error = sysfs_add_one(&acxt, sd);
62 (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { 59 else
63 if (warn) 60 error = __sysfs_add_one(&acxt, sd);
64 error = sysfs_add_one(&acxt, sd);
65 else
66 error = __sysfs_add_one(&acxt, sd);
67 } else {
68 error = -EINVAL;
69 WARN(1, KERN_WARNING
70 "sysfs: symlink across ns_types %s/%s -> %s/%s\n",
71 parent_sd->s_name,
72 sd->s_name,
73 sd->s_symlink.target_sd->s_parent->s_name,
74 sd->s_symlink.target_sd->s_name);
75 }
76 sysfs_addrm_finish(&acxt); 61 sysfs_addrm_finish(&acxt);
77 62
78 if (error) 63 if (error)
@@ -156,7 +141,7 @@ void sysfs_delete_link(struct kobject *kobj, struct kobject *targ,
156{ 141{
157 const void *ns = NULL; 142 const void *ns = NULL;
158 spin_lock(&sysfs_assoc_lock); 143 spin_lock(&sysfs_assoc_lock);
159 if (targ->sd && sysfs_ns_type(kobj->sd)) 144 if (targ->sd)
160 ns = targ->sd->s_ns; 145 ns = targ->sd->s_ns;
161 spin_unlock(&sysfs_assoc_lock); 146 spin_unlock(&sysfs_assoc_lock);
162 sysfs_hash_and_remove(kobj->sd, ns, name); 147 sysfs_hash_and_remove(kobj->sd, ns, name);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index a96da2559db2..7664d1b3d594 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -93,11 +93,8 @@ struct sysfs_dirent {
93#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) 93#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
94#define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) 94#define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR)
95 95
96/* identify any namespace tag on sysfs_dirents */ 96#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK
97#define SYSFS_NS_TYPE_MASK 0xf00 97#define SYSFS_FLAG_HAS_NS 0x01000
98#define SYSFS_NS_TYPE_SHIFT 8
99
100#define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK)
101#define SYSFS_FLAG_REMOVED 0x02000 98#define SYSFS_FLAG_REMOVED 0x02000
102 99
103static inline unsigned int sysfs_type(struct sysfs_dirent *sd) 100static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
@@ -105,15 +102,6 @@ static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
105 return sd->s_flags & SYSFS_TYPE_MASK; 102 return sd->s_flags & SYSFS_TYPE_MASK;
106} 103}
107 104
108/*
109 * Return any namespace tags on this dirent.
110 * enum kobj_ns_type is defined in linux/kobject.h
111 */
112static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd)
113{
114 return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT;
115}
116
117#ifdef CONFIG_DEBUG_LOCK_ALLOC 105#ifdef CONFIG_DEBUG_LOCK_ALLOC
118#define sysfs_dirent_init_lockdep(sd) \ 106#define sysfs_dirent_init_lockdep(sd) \
119do { \ 107do { \
@@ -141,12 +129,13 @@ struct sysfs_addrm_cxt {
141 */ 129 */
142 130
143/* 131/*
144 * Each sb is associated with a set of namespace tags (i.e. 132 * Each sb is associated with one namespace tag, currently the network
145 * the network namespace of the task which mounted this sysfs 133 * namespace of the task which mounted this sysfs instance. If multiple
146 * instance). 134 * tags become necessary, make the following an array and compare
135 * sysfs_dirent tag against every entry.
147 */ 136 */
148struct sysfs_super_info { 137struct sysfs_super_info {
149 void *ns[KOBJ_NS_TYPES]; 138 void *ns;
150}; 139};
151#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) 140#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
152extern struct sysfs_dirent sysfs_root; 141extern struct sysfs_dirent sysfs_root;
diff --git a/lib/kobject.c b/lib/kobject.c
index 85fb3a161b21..e769ee3c2fb9 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -29,11 +29,14 @@
29const void *kobject_namespace(struct kobject *kobj) 29const void *kobject_namespace(struct kobject *kobj)
30{ 30{
31 const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj); 31 const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj);
32 const void *ns;
32 33
33 if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE) 34 if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE)
34 return NULL; 35 return NULL;
35 36
36 return kobj->ktype->namespace(kobj); 37 ns = kobj->ktype->namespace(kobj);
38 WARN_ON(!ns); /* @kobj in a namespace is required to have !NULL tag */
39 return ns;
37} 40}
38 41
39/* 42/*