aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2013-09-11 22:29:07 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2013-09-26 18:30:22 -0400
commitcb26a311578e67769e92a39a0a63476533cb7e12 (patch)
tree13a1c59bdf23abdb063d1bc4a8cc1679e36dcd38 /fs/sysfs/dir.c
parent4b30ee58ee64c64f59fd876e4afa6ed82caef3a4 (diff)
sysfs: drop kobj_ns_type handling
The way namespace tags are implemented in sysfs is more complicated than necessary. As each tag is a pointer value and required to be non-NULL under a namespace enabled parent, there's no need to record separately what type each tag is or where namespace is enabled. If multiple namespace types are needed, which currently aren't, we can simply compare the tag to a set of allowed tags in the superblock assuming that the tags, being pointers, won't have the same value across multiple types. Also, whether to filter by namespace tag or not can be trivially determined by whether the node has any tagged children or not. This patch rips out kobj_ns_type handling from sysfs. sysfs no longer cares whether specific type of namespace is enabled or not. If a sysfs_dirent has a non-NULL tag, the parent is marked as needing namespace filtering and the value is tested against the allowed set of tags for the superblock (currently only one but increasing this number isn't difficult) and the sysfs_dirent is ignored if it doesn't match. This removes most kobject namespace knowledge from sysfs proper which will enable proper separation and layering of sysfs. The namespace sanity checks in fs/sysfs/dir.c are replaced by the new sanity check in kobject_namespace(). As this is the only place ktype->namespace() is called for sysfs, this doesn't weaken the sanity check significantly. I omitted converting the sanity check in sysfs_do_create_link_sd(). While the check can be shifted to upper layer, mistakes there are well contained and should be easily visible anyway. Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Eric W. Biederman <ebiederm@xmission.com> Cc: Kay Sievers <kay@vrfy.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c90
1 files changed, 25 insertions, 65 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)) {