aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2010-03-30 14:31:26 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2010-05-21 12:37:31 -0400
commit3ff195b011d7decf501a4d55aeed312731094796 (patch)
tree8cfdc330abbf82893955f2d7d6e96efee81bfd7c
parentbc451f2058238013e1cdf4acd443c01734d332f0 (diff)
sysfs: Implement sysfs tagged directory support.
The problem. When implementing a network namespace I need to be able to have multiple network devices with the same name. Currently this is a problem for /sys/class/net/*, /sys/devices/virtual/net/*, and potentially a few other directories of the form /sys/ ... /net/*. What this patch does is to add an additional tag field to the sysfs dirent structure. For directories that should show different contents depending on the context such as /sys/class/net/, and /sys/devices/virtual/net/ this tag field is used to specify the context in which those directories should be visible. Effectively this is the same as creating multiple distinct directories with the same name but internally to sysfs the result is nicer. I am calling the concept of a single directory that looks like multiple directories all at the same path in the filesystem tagged directories. For the networking namespace the set of directories whose contents I need to filter with tags can depend on the presence or absence of hotplug hardware or which modules are currently loaded. Which means I need a simple race free way to setup those directories as tagged. To achieve a reace free design all tagged directories are created and managed by sysfs itself. Users of this interface: - define a type in the sysfs_tag_type enumeration. - call sysfs_register_ns_types with the type and it's operations - sysfs_exit_ns when an individual tag is no longer valid - Implement mount_ns() which returns the ns of the calling process so we can attach it to a sysfs superblock. - Implement ktype.namespace() which returns the ns of a syfs kobject. Everything else is left up to sysfs and the driver layer. For the network namespace mount_ns and namespace() are essentially one line functions, and look to remain that. Tags are currently represented a const void * pointers as that is both generic, prevides enough information for equality comparisons, and is trivial to create for current users, as it is just the existing namespace pointer. The work needed in sysfs is more extensive. At each directory or symlink creating I need to check if the directory it is being created in is a tagged directory and if so generate the appropriate tag to place on the sysfs_dirent. Likewise at each symlink or directory removal I need to check if the sysfs directory it is being removed from is a tagged directory and if so figure out which tag goes along with the name I am deleting. Currently only directories which hold kobjects, and symlinks are supported. There is not enough information in the current file attribute interfaces to give us anything to discriminate on which makes it useless, and there are no potential users which makes it an uninteresting problem to solve. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Benjamin Thery <benjamin.thery@bull.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/gpio/gpiolib.c2
-rw-r--r--drivers/md/bitmap.c4
-rw-r--r--drivers/md/md.c6
-rw-r--r--fs/sysfs/bin.c2
-rw-r--r--fs/sysfs/dir.c112
-rw-r--r--fs/sysfs/file.c17
-rw-r--r--fs/sysfs/group.c6
-rw-r--r--fs/sysfs/inode.c4
-rw-r--r--fs/sysfs/mount.c33
-rw-r--r--fs/sysfs/symlink.c15
-rw-r--r--fs/sysfs/sysfs.h20
-rw-r--r--include/linux/sysfs.h10
-rw-r--r--lib/kobject.c1
13 files changed, 181 insertions, 51 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index eb0c3fe44b29..cae1b8c5b08c 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -399,7 +399,7 @@ static int gpio_setup_irq(struct gpio_desc *desc, struct device *dev,
399 goto free_id; 399 goto free_id;
400 } 400 }
401 401
402 pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, "value"); 402 pdesc->value_sd = sysfs_get_dirent(dev->kobj.sd, NULL, "value");
403 if (!pdesc->value_sd) { 403 if (!pdesc->value_sd) {
404 ret = -ENODEV; 404 ret = -ENODEV;
405 goto free_id; 405 goto free_id;
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index 26ac8aad0b19..f084249295d9 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -1678,9 +1678,9 @@ int bitmap_create(mddev_t *mddev)
1678 1678
1679 bitmap->mddev = mddev; 1679 bitmap->mddev = mddev;
1680 1680
1681 bm = sysfs_get_dirent(mddev->kobj.sd, "bitmap"); 1681 bm = sysfs_get_dirent(mddev->kobj.sd, NULL, "bitmap");
1682 if (bm) { 1682 if (bm) {
1683 bitmap->sysfs_can_clear = sysfs_get_dirent(bm, "can_clear"); 1683 bitmap->sysfs_can_clear = sysfs_get_dirent(bm, NULL, "can_clear");
1684 sysfs_put(bm); 1684 sysfs_put(bm);
1685 } else 1685 } else
1686 bitmap->sysfs_can_clear = NULL; 1686 bitmap->sysfs_can_clear = NULL;
diff --git a/drivers/md/md.c b/drivers/md/md.c
index cefd63daff31..a9fd491796ac 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1766,7 +1766,7 @@ static int bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
1766 kobject_del(&rdev->kobj); 1766 kobject_del(&rdev->kobj);
1767 goto fail; 1767 goto fail;
1768 } 1768 }
1769 rdev->sysfs_state = sysfs_get_dirent(rdev->kobj.sd, "state"); 1769 rdev->sysfs_state = sysfs_get_dirent(rdev->kobj.sd, NULL, "state");
1770 1770
1771 list_add_rcu(&rdev->same_set, &mddev->disks); 1771 list_add_rcu(&rdev->same_set, &mddev->disks);
1772 bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk); 1772 bd_claim_by_disk(rdev->bdev, rdev->bdev->bd_holder, mddev->gendisk);
@@ -4189,7 +4189,7 @@ static int md_alloc(dev_t dev, char *name)
4189 mutex_unlock(&disks_mutex); 4189 mutex_unlock(&disks_mutex);
4190 if (!error) { 4190 if (!error) {
4191 kobject_uevent(&mddev->kobj, KOBJ_ADD); 4191 kobject_uevent(&mddev->kobj, KOBJ_ADD);
4192 mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, "array_state"); 4192 mddev->sysfs_state = sysfs_get_dirent(mddev->kobj.sd, NULL, "array_state");
4193 } 4193 }
4194 mddev_put(mddev); 4194 mddev_put(mddev);
4195 return error; 4195 return error;
@@ -4398,7 +4398,7 @@ static int do_md_run(mddev_t * mddev)
4398 printk(KERN_WARNING 4398 printk(KERN_WARNING
4399 "md: cannot register extra attributes for %s\n", 4399 "md: cannot register extra attributes for %s\n",
4400 mdname(mddev)); 4400 mdname(mddev));
4401 mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action"); 4401 mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, NULL, "sync_action");
4402 } else if (mddev->ro == 2) /* auto-readonly not meaningful */ 4402 } else if (mddev->ro == 2) /* auto-readonly not meaningful */
4403 mddev->ro = 0; 4403 mddev->ro = 0;
4404 4404
diff --git a/fs/sysfs/bin.c b/fs/sysfs/bin.c
index e9d293593e52..806b277453f9 100644
--- a/fs/sysfs/bin.c
+++ b/fs/sysfs/bin.c
@@ -501,7 +501,7 @@ int sysfs_create_bin_file(struct kobject *kobj,
501void sysfs_remove_bin_file(struct kobject *kobj, 501void sysfs_remove_bin_file(struct kobject *kobj,
502 const struct bin_attribute *attr) 502 const struct bin_attribute *attr)
503{ 503{
504 sysfs_hash_and_remove(kobj->sd, attr->attr.name); 504 sysfs_hash_and_remove(kobj->sd, NULL, attr->attr.name);
505} 505}
506 506
507EXPORT_SYMBOL_GPL(sysfs_create_bin_file); 507EXPORT_SYMBOL_GPL(sysfs_create_bin_file);
diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c
index 590717861c7a..b2b83067ccc8 100644
--- a/fs/sysfs/dir.c
+++ b/fs/sysfs/dir.c
@@ -380,9 +380,15 @@ int __sysfs_add_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd)
380{ 380{
381 struct sysfs_inode_attrs *ps_iattr; 381 struct sysfs_inode_attrs *ps_iattr;
382 382
383 if (sysfs_find_dirent(acxt->parent_sd, sd->s_name)) 383 if (sysfs_find_dirent(acxt->parent_sd, sd->s_ns, sd->s_name))
384 return -EEXIST; 384 return -EEXIST;
385 385
386 if (sysfs_ns_type(acxt->parent_sd) && !sd->s_ns) {
387 WARN(1, KERN_WARNING "sysfs: ns required in '%s' for '%s'\n",
388 acxt->parent_sd->s_name, sd->s_name);
389 return -EINVAL;
390 }
391
386 sd->s_parent = sysfs_get(acxt->parent_sd); 392 sd->s_parent = sysfs_get(acxt->parent_sd);
387 393
388 sysfs_link_sibling(sd); 394 sysfs_link_sibling(sd);
@@ -533,13 +539,17 @@ void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt)
533 * Pointer to sysfs_dirent if found, NULL if not. 539 * Pointer to sysfs_dirent if found, NULL if not.
534 */ 540 */
535struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, 541struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
542 const void *ns,
536 const unsigned char *name) 543 const unsigned char *name)
537{ 544{
538 struct sysfs_dirent *sd; 545 struct sysfs_dirent *sd;
539 546
540 for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) 547 for (sd = parent_sd->s_dir.children; sd; sd = sd->s_sibling) {
548 if (sd->s_ns != ns)
549 continue;
541 if (!strcmp(sd->s_name, name)) 550 if (!strcmp(sd->s_name, name))
542 return sd; 551 return sd;
552 }
543 return NULL; 553 return NULL;
544} 554}
545 555
@@ -558,12 +568,13 @@ struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
558 * Pointer to sysfs_dirent if found, NULL if not. 568 * Pointer to sysfs_dirent if found, NULL if not.
559 */ 569 */
560struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, 570struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
571 const void *ns,
561 const unsigned char *name) 572 const unsigned char *name)
562{ 573{
563 struct sysfs_dirent *sd; 574 struct sysfs_dirent *sd;
564 575
565 mutex_lock(&sysfs_mutex); 576 mutex_lock(&sysfs_mutex);
566 sd = sysfs_find_dirent(parent_sd, name); 577 sd = sysfs_find_dirent(parent_sd, ns, name);
567 sysfs_get(sd); 578 sysfs_get(sd);
568 mutex_unlock(&sysfs_mutex); 579 mutex_unlock(&sysfs_mutex);
569 580
@@ -572,7 +583,8 @@ struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
572EXPORT_SYMBOL_GPL(sysfs_get_dirent); 583EXPORT_SYMBOL_GPL(sysfs_get_dirent);
573 584
574static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, 585static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
575 const char *name, struct sysfs_dirent **p_sd) 586 enum kobj_ns_type type, const void *ns, const char *name,
587 struct sysfs_dirent **p_sd)
576{ 588{
577 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; 589 umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
578 struct sysfs_addrm_cxt acxt; 590 struct sysfs_addrm_cxt acxt;
@@ -583,6 +595,9 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
583 sd = sysfs_new_dirent(name, mode, SYSFS_DIR); 595 sd = sysfs_new_dirent(name, mode, SYSFS_DIR);
584 if (!sd) 596 if (!sd)
585 return -ENOMEM; 597 return -ENOMEM;
598
599 sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT);
600 sd->s_ns = ns;
586 sd->s_dir.kobj = kobj; 601 sd->s_dir.kobj = kobj;
587 602
588 /* link in */ 603 /* link in */
@@ -601,7 +616,25 @@ static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd,
601int sysfs_create_subdir(struct kobject *kobj, const char *name, 616int sysfs_create_subdir(struct kobject *kobj, const char *name,
602 struct sysfs_dirent **p_sd) 617 struct sysfs_dirent **p_sd)
603{ 618{
604 return create_dir(kobj, kobj->sd, name, p_sd); 619 return create_dir(kobj, kobj->sd,
620 KOBJ_NS_TYPE_NONE, NULL, name, p_sd);
621}
622
623static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj)
624{
625 const struct kobj_ns_type_operations *ops;
626 enum kobj_ns_type type;
627
628 ops = kobj_child_ns_ops(kobj);
629 if (!ops)
630 return KOBJ_NS_TYPE_NONE;
631
632 type = ops->type;
633 BUG_ON(type <= KOBJ_NS_TYPE_NONE);
634 BUG_ON(type >= KOBJ_NS_TYPES);
635 BUG_ON(!kobj_ns_type_registered(type));
636
637 return type;
605} 638}
606 639
607/** 640/**
@@ -610,7 +643,9 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
610 */ 643 */
611int sysfs_create_dir(struct kobject * kobj) 644int sysfs_create_dir(struct kobject * kobj)
612{ 645{
646 enum kobj_ns_type type;
613 struct sysfs_dirent *parent_sd, *sd; 647 struct sysfs_dirent *parent_sd, *sd;
648 const void *ns = NULL;
614 int error = 0; 649 int error = 0;
615 650
616 BUG_ON(!kobj); 651 BUG_ON(!kobj);
@@ -620,7 +655,11 @@ int sysfs_create_dir(struct kobject * kobj)
620 else 655 else
621 parent_sd = &sysfs_root; 656 parent_sd = &sysfs_root;
622 657
623 error = create_dir(kobj, parent_sd, kobject_name(kobj), &sd); 658 if (sysfs_ns_type(parent_sd))
659 ns = kobj->ktype->namespace(kobj);
660 type = sysfs_read_ns_type(kobj);
661
662 error = create_dir(kobj, parent_sd, type, ns, kobject_name(kobj), &sd);
624 if (!error) 663 if (!error)
625 kobj->sd = sd; 664 kobj->sd = sd;
626 return error; 665 return error;
@@ -630,13 +669,19 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry,
630 struct nameidata *nd) 669 struct nameidata *nd)
631{ 670{
632 struct dentry *ret = NULL; 671 struct dentry *ret = NULL;
633 struct sysfs_dirent *parent_sd = dentry->d_parent->d_fsdata; 672 struct dentry *parent = dentry->d_parent;
673 struct sysfs_dirent *parent_sd = parent->d_fsdata;
634 struct sysfs_dirent *sd; 674 struct sysfs_dirent *sd;
635 struct inode *inode; 675 struct inode *inode;
676 enum kobj_ns_type type;
677 const void *ns;
636 678
637 mutex_lock(&sysfs_mutex); 679 mutex_lock(&sysfs_mutex);
638 680
639 sd = sysfs_find_dirent(parent_sd, dentry->d_name.name); 681 type = sysfs_ns_type(parent_sd);
682 ns = sysfs_info(dir->i_sb)->ns[type];
683
684 sd = sysfs_find_dirent(parent_sd, ns, dentry->d_name.name);
640 685
641 /* no such entry */ 686 /* no such entry */
642 if (!sd) { 687 if (!sd) {
@@ -735,7 +780,8 @@ void sysfs_remove_dir(struct kobject * kobj)
735} 780}
736 781
737int sysfs_rename(struct sysfs_dirent *sd, 782int sysfs_rename(struct sysfs_dirent *sd,
738 struct sysfs_dirent *new_parent_sd, const char *new_name) 783 struct sysfs_dirent *new_parent_sd, const void *new_ns,
784 const char *new_name)
739{ 785{
740 const char *dup_name = NULL; 786 const char *dup_name = NULL;
741 int error; 787 int error;
@@ -743,12 +789,12 @@ int sysfs_rename(struct sysfs_dirent *sd,
743 mutex_lock(&sysfs_mutex); 789 mutex_lock(&sysfs_mutex);
744 790
745 error = 0; 791 error = 0;
746 if ((sd->s_parent == new_parent_sd) && 792 if ((sd->s_parent == new_parent_sd) && (sd->s_ns == new_ns) &&
747 (strcmp(sd->s_name, new_name) == 0)) 793 (strcmp(sd->s_name, new_name) == 0))
748 goto out; /* nothing to rename */ 794 goto out; /* nothing to rename */
749 795
750 error = -EEXIST; 796 error = -EEXIST;
751 if (sysfs_find_dirent(new_parent_sd, new_name)) 797 if (sysfs_find_dirent(new_parent_sd, new_ns, new_name))
752 goto out; 798 goto out;
753 799
754 /* rename sysfs_dirent */ 800 /* rename sysfs_dirent */
@@ -770,6 +816,7 @@ int sysfs_rename(struct sysfs_dirent *sd,
770 sd->s_parent = new_parent_sd; 816 sd->s_parent = new_parent_sd;
771 sysfs_link_sibling(sd); 817 sysfs_link_sibling(sd);
772 } 818 }
819 sd->s_ns = new_ns;
773 820
774 error = 0; 821 error = 0;
775 out: 822 out:
@@ -780,19 +827,28 @@ int sysfs_rename(struct sysfs_dirent *sd,
780 827
781int sysfs_rename_dir(struct kobject *kobj, const char *new_name) 828int sysfs_rename_dir(struct kobject *kobj, const char *new_name)
782{ 829{
783 return sysfs_rename(kobj->sd, kobj->sd->s_parent, new_name); 830 struct sysfs_dirent *parent_sd = kobj->sd->s_parent;
831 const void *new_ns = NULL;
832
833 if (sysfs_ns_type(parent_sd))
834 new_ns = kobj->ktype->namespace(kobj);
835
836 return sysfs_rename(kobj->sd, parent_sd, new_ns, new_name);
784} 837}
785 838
786int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) 839int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj)
787{ 840{
788 struct sysfs_dirent *sd = kobj->sd; 841 struct sysfs_dirent *sd = kobj->sd;
789 struct sysfs_dirent *new_parent_sd; 842 struct sysfs_dirent *new_parent_sd;
843 const void *new_ns = NULL;
790 844
791 BUG_ON(!sd->s_parent); 845 BUG_ON(!sd->s_parent);
846 if (sysfs_ns_type(sd->s_parent))
847 new_ns = kobj->ktype->namespace(kobj);
792 new_parent_sd = new_parent_kobj && new_parent_kobj->sd ? 848 new_parent_sd = new_parent_kobj && new_parent_kobj->sd ?
793 new_parent_kobj->sd : &sysfs_root; 849 new_parent_kobj->sd : &sysfs_root;
794 850
795 return sysfs_rename(sd, new_parent_sd, sd->s_name); 851 return sysfs_rename(sd, new_parent_sd, new_ns, sd->s_name);
796} 852}
797 853
798/* Relationship between s_mode and the DT_xxx types */ 854/* Relationship between s_mode and the DT_xxx types */
@@ -807,32 +863,35 @@ static int sysfs_dir_release(struct inode *inode, struct file *filp)
807 return 0; 863 return 0;
808} 864}
809 865
810static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd, 866static struct sysfs_dirent *sysfs_dir_pos(const void *ns,
811 ino_t ino, struct sysfs_dirent *pos) 867 struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
812{ 868{
813 if (pos) { 869 if (pos) {
814 int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) && 870 int valid = !(pos->s_flags & SYSFS_FLAG_REMOVED) &&
815 pos->s_parent == parent_sd && 871 pos->s_parent == parent_sd &&
816 ino == pos->s_ino; 872 ino == pos->s_ino;
817 sysfs_put(pos); 873 sysfs_put(pos);
818 if (valid) 874 if (!valid)
819 return pos; 875 pos = NULL;
820 } 876 }
821 pos = NULL; 877 if (!pos && (ino > 1) && (ino < INT_MAX)) {
822 if ((ino > 1) && (ino < INT_MAX)) {
823 pos = parent_sd->s_dir.children; 878 pos = parent_sd->s_dir.children;
824 while (pos && (ino > pos->s_ino)) 879 while (pos && (ino > pos->s_ino))
825 pos = pos->s_sibling; 880 pos = pos->s_sibling;
826 } 881 }
882 while (pos && pos->s_ns != ns)
883 pos = pos->s_sibling;
827 return pos; 884 return pos;
828} 885}
829 886
830static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd, 887static struct sysfs_dirent *sysfs_dir_next_pos(const void *ns,
831 ino_t ino, struct sysfs_dirent *pos) 888 struct sysfs_dirent *parent_sd, ino_t ino, struct sysfs_dirent *pos)
832{ 889{
833 pos = sysfs_dir_pos(parent_sd, ino, pos); 890 pos = sysfs_dir_pos(ns, parent_sd, ino, pos);
834 if (pos) 891 if (pos)
835 pos = pos->s_sibling; 892 pos = pos->s_sibling;
893 while (pos && pos->s_ns != ns)
894 pos = pos->s_sibling;
836 return pos; 895 return pos;
837} 896}
838 897
@@ -841,8 +900,13 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
841 struct dentry *dentry = filp->f_path.dentry; 900 struct dentry *dentry = filp->f_path.dentry;
842 struct sysfs_dirent * parent_sd = dentry->d_fsdata; 901 struct sysfs_dirent * parent_sd = dentry->d_fsdata;
843 struct sysfs_dirent *pos = filp->private_data; 902 struct sysfs_dirent *pos = filp->private_data;
903 enum kobj_ns_type type;
904 const void *ns;
844 ino_t ino; 905 ino_t ino;
845 906
907 type = sysfs_ns_type(parent_sd);
908 ns = sysfs_info(dentry->d_sb)->ns[type];
909
846 if (filp->f_pos == 0) { 910 if (filp->f_pos == 0) {
847 ino = parent_sd->s_ino; 911 ino = parent_sd->s_ino;
848 if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0) 912 if (filldir(dirent, ".", 1, filp->f_pos, ino, DT_DIR) == 0)
@@ -857,9 +921,9 @@ static int sysfs_readdir(struct file * filp, void * dirent, filldir_t filldir)
857 filp->f_pos++; 921 filp->f_pos++;
858 } 922 }
859 mutex_lock(&sysfs_mutex); 923 mutex_lock(&sysfs_mutex);
860 for (pos = sysfs_dir_pos(parent_sd, filp->f_pos, pos); 924 for (pos = sysfs_dir_pos(ns, parent_sd, filp->f_pos, pos);
861 pos; 925 pos;
862 pos = sysfs_dir_next_pos(parent_sd, filp->f_pos, pos)) { 926 pos = sysfs_dir_next_pos(ns, parent_sd, filp->f_pos, pos)) {
863 const char * name; 927 const char * name;
864 unsigned int type; 928 unsigned int type;
865 int len, ret; 929 int len, ret;
diff --git a/fs/sysfs/file.c b/fs/sysfs/file.c
index e222b2582746..1beaa739d0a6 100644
--- a/fs/sysfs/file.c
+++ b/fs/sysfs/file.c
@@ -478,9 +478,12 @@ void sysfs_notify(struct kobject *k, const char *dir, const char *attr)
478 mutex_lock(&sysfs_mutex); 478 mutex_lock(&sysfs_mutex);
479 479
480 if (sd && dir) 480 if (sd && dir)
481 sd = sysfs_find_dirent(sd, dir); 481 /* Only directories are tagged, so no need to pass
482 * a tag explicitly.
483 */
484 sd = sysfs_find_dirent(sd, NULL, dir);
482 if (sd && attr) 485 if (sd && attr)
483 sd = sysfs_find_dirent(sd, attr); 486 sd = sysfs_find_dirent(sd, NULL, attr);
484 if (sd) 487 if (sd)
485 sysfs_notify_dirent(sd); 488 sysfs_notify_dirent(sd);
486 489
@@ -569,7 +572,7 @@ int sysfs_add_file_to_group(struct kobject *kobj,
569 int error; 572 int error;
570 573
571 if (group) 574 if (group)
572 dir_sd = sysfs_get_dirent(kobj->sd, group); 575 dir_sd = sysfs_get_dirent(kobj->sd, NULL, group);
573 else 576 else
574 dir_sd = sysfs_get(kobj->sd); 577 dir_sd = sysfs_get(kobj->sd);
575 578
@@ -599,7 +602,7 @@ int sysfs_chmod_file(struct kobject *kobj, struct attribute *attr, mode_t mode)
599 mutex_lock(&sysfs_mutex); 602 mutex_lock(&sysfs_mutex);
600 603
601 rc = -ENOENT; 604 rc = -ENOENT;
602 sd = sysfs_find_dirent(kobj->sd, attr->name); 605 sd = sysfs_find_dirent(kobj->sd, NULL, attr->name);
603 if (!sd) 606 if (!sd)
604 goto out; 607 goto out;
605 608
@@ -624,7 +627,7 @@ EXPORT_SYMBOL_GPL(sysfs_chmod_file);
624 627
625void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr) 628void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr)
626{ 629{
627 sysfs_hash_and_remove(kobj->sd, attr->name); 630 sysfs_hash_and_remove(kobj->sd, NULL, attr->name);
628} 631}
629 632
630void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr) 633void sysfs_remove_files(struct kobject * kobj, const struct attribute **ptr)
@@ -646,11 +649,11 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
646 struct sysfs_dirent *dir_sd; 649 struct sysfs_dirent *dir_sd;
647 650
648 if (group) 651 if (group)
649 dir_sd = sysfs_get_dirent(kobj->sd, group); 652 dir_sd = sysfs_get_dirent(kobj->sd, NULL, group);
650 else 653 else
651 dir_sd = sysfs_get(kobj->sd); 654 dir_sd = sysfs_get(kobj->sd);
652 if (dir_sd) { 655 if (dir_sd) {
653 sysfs_hash_and_remove(dir_sd, attr->name); 656 sysfs_hash_and_remove(dir_sd, NULL, attr->name);
654 sysfs_put(dir_sd); 657 sysfs_put(dir_sd);
655 } 658 }
656} 659}
diff --git a/fs/sysfs/group.c b/fs/sysfs/group.c
index fe611949a7f7..23c1e598792a 100644
--- a/fs/sysfs/group.c
+++ b/fs/sysfs/group.c
@@ -23,7 +23,7 @@ static void remove_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
23 int i; 23 int i;
24 24
25 for (i = 0, attr = grp->attrs; *attr; i++, attr++) 25 for (i = 0, attr = grp->attrs; *attr; i++, attr++)
26 sysfs_hash_and_remove(dir_sd, (*attr)->name); 26 sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
27} 27}
28 28
29static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj, 29static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
@@ -39,7 +39,7 @@ static int create_files(struct sysfs_dirent *dir_sd, struct kobject *kobj,
39 * visibility. Do this by first removing then 39 * visibility. Do this by first removing then
40 * re-adding (if required) the file */ 40 * re-adding (if required) the file */
41 if (update) 41 if (update)
42 sysfs_hash_and_remove(dir_sd, (*attr)->name); 42 sysfs_hash_and_remove(dir_sd, NULL, (*attr)->name);
43 if (grp->is_visible) { 43 if (grp->is_visible) {
44 mode = grp->is_visible(kobj, *attr, i); 44 mode = grp->is_visible(kobj, *attr, i);
45 if (!mode) 45 if (!mode)
@@ -132,7 +132,7 @@ void sysfs_remove_group(struct kobject * kobj,
132 struct sysfs_dirent *sd; 132 struct sysfs_dirent *sd;
133 133
134 if (grp->name) { 134 if (grp->name) {
135 sd = sysfs_get_dirent(dir_sd, grp->name); 135 sd = sysfs_get_dirent(dir_sd, NULL, grp->name);
136 if (!sd) { 136 if (!sd) {
137 WARN(!sd, KERN_WARNING "sysfs group %p not found for " 137 WARN(!sd, KERN_WARNING "sysfs group %p not found for "
138 "kobject '%s'\n", grp, kobject_name(kobj)); 138 "kobject '%s'\n", grp, kobject_name(kobj));
diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c
index a4a0a9419711..cf2bad1462ea 100644
--- a/fs/sysfs/inode.c
+++ b/fs/sysfs/inode.c
@@ -324,7 +324,7 @@ void sysfs_delete_inode(struct inode *inode)
324 sysfs_put(sd); 324 sysfs_put(sd);
325} 325}
326 326
327int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name) 327int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name)
328{ 328{
329 struct sysfs_addrm_cxt acxt; 329 struct sysfs_addrm_cxt acxt;
330 struct sysfs_dirent *sd; 330 struct sysfs_dirent *sd;
@@ -334,7 +334,7 @@ int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name)
334 334
335 sysfs_addrm_start(&acxt, dir_sd); 335 sysfs_addrm_start(&acxt, dir_sd);
336 336
337 sd = sysfs_find_dirent(dir_sd, name); 337 sd = sysfs_find_dirent(dir_sd, ns, name);
338 if (sd) 338 if (sd)
339 sysfs_remove_one(&acxt, sd); 339 sysfs_remove_one(&acxt, sd);
340 340
diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c
index 50e4fb6a7403..1afa32ba242c 100644
--- a/fs/sysfs/mount.c
+++ b/fs/sysfs/mount.c
@@ -35,7 +35,7 @@ static const struct super_operations sysfs_ops = {
35struct sysfs_dirent sysfs_root = { 35struct sysfs_dirent sysfs_root = {
36 .s_name = "", 36 .s_name = "",
37 .s_count = ATOMIC_INIT(1), 37 .s_count = ATOMIC_INIT(1),
38 .s_flags = SYSFS_DIR, 38 .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT),
39 .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO, 39 .s_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
40 .s_ino = 1, 40 .s_ino = 1,
41}; 41};
@@ -76,7 +76,13 @@ static int sysfs_test_super(struct super_block *sb, void *data)
76{ 76{
77 struct sysfs_super_info *sb_info = sysfs_info(sb); 77 struct sysfs_super_info *sb_info = sysfs_info(sb);
78 struct sysfs_super_info *info = data; 78 struct sysfs_super_info *info = data;
79 enum kobj_ns_type type;
79 int found = 1; 80 int found = 1;
81
82 for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) {
83 if (sb_info->ns[type] != info->ns[type])
84 found = 0;
85 }
80 return found; 86 return found;
81} 87}
82 88
@@ -93,6 +99,7 @@ static int sysfs_get_sb(struct file_system_type *fs_type,
93 int flags, const char *dev_name, void *data, struct vfsmount *mnt) 99 int flags, const char *dev_name, void *data, struct vfsmount *mnt)
94{ 100{
95 struct sysfs_super_info *info; 101 struct sysfs_super_info *info;
102 enum kobj_ns_type type;
96 struct super_block *sb; 103 struct super_block *sb;
97 int error; 104 int error;
98 105
@@ -100,6 +107,10 @@ static int sysfs_get_sb(struct file_system_type *fs_type,
100 info = kzalloc(sizeof(*info), GFP_KERNEL); 107 info = kzalloc(sizeof(*info), GFP_KERNEL);
101 if (!info) 108 if (!info)
102 goto out; 109 goto out;
110
111 for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++)
112 info->ns[type] = kobj_ns_current(type);
113
103 sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info); 114 sb = sget(fs_type, sysfs_test_super, sysfs_set_super, info);
104 if (IS_ERR(sb) || sb->s_fs_info != info) 115 if (IS_ERR(sb) || sb->s_fs_info != info)
105 kfree(info); 116 kfree(info);
@@ -137,6 +148,26 @@ static struct file_system_type sysfs_fs_type = {
137 .kill_sb = sysfs_kill_sb, 148 .kill_sb = sysfs_kill_sb,
138}; 149};
139 150
151void sysfs_exit_ns(enum kobj_ns_type type, const void *ns)
152{
153 struct super_block *sb;
154
155 mutex_lock(&sysfs_mutex);
156 spin_lock(&sb_lock);
157 list_for_each_entry(sb, &sysfs_fs_type.fs_supers, s_instances) {
158 struct sysfs_super_info *info = sysfs_info(sb);
159 /* Ignore superblocks that are in the process of unmounting */
160 if (sb->s_count <= S_BIAS)
161 continue;
162 /* Ignore superblocks with the wrong ns */
163 if (info->ns[type] != ns)
164 continue;
165 info->ns[type] = NULL;
166 }
167 spin_unlock(&sb_lock);
168 mutex_unlock(&sysfs_mutex);
169}
170
140int __init sysfs_init(void) 171int __init sysfs_init(void)
141{ 172{
142 int err = -ENOMEM; 173 int err = -ENOMEM;
diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c
index 942f239a2132..b6ebdaa00f37 100644
--- a/fs/sysfs/symlink.c
+++ b/fs/sysfs/symlink.c
@@ -58,6 +58,8 @@ static int sysfs_do_create_link(struct kobject *kobj, struct kobject *target,
58 if (!sd) 58 if (!sd)
59 goto out_put; 59 goto out_put;
60 60
61 if (sysfs_ns_type(parent_sd))
62 sd->s_ns = target->ktype->namespace(target);
61 sd->s_symlink.target_sd = target_sd; 63 sd->s_symlink.target_sd = target_sd;
62 target_sd = NULL; /* reference is now owned by the symlink */ 64 target_sd = NULL; /* reference is now owned by the symlink */
63 65
@@ -121,7 +123,7 @@ void sysfs_remove_link(struct kobject * kobj, const char * name)
121 else 123 else
122 parent_sd = kobj->sd; 124 parent_sd = kobj->sd;
123 125
124 sysfs_hash_and_remove(parent_sd, name); 126 sysfs_hash_and_remove(parent_sd, NULL, name);
125} 127}
126 128
127/** 129/**
@@ -137,6 +139,7 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
137 const char *old, const char *new) 139 const char *old, const char *new)
138{ 140{
139 struct sysfs_dirent *parent_sd, *sd = NULL; 141 struct sysfs_dirent *parent_sd, *sd = NULL;
142 const void *old_ns = NULL, *new_ns = NULL;
140 int result; 143 int result;
141 144
142 if (!kobj) 145 if (!kobj)
@@ -144,8 +147,11 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
144 else 147 else
145 parent_sd = kobj->sd; 148 parent_sd = kobj->sd;
146 149
150 if (targ->sd)
151 old_ns = targ->sd->s_ns;
152
147 result = -ENOENT; 153 result = -ENOENT;
148 sd = sysfs_get_dirent(parent_sd, old); 154 sd = sysfs_get_dirent(parent_sd, old_ns, old);
149 if (!sd) 155 if (!sd)
150 goto out; 156 goto out;
151 157
@@ -155,7 +161,10 @@ int sysfs_rename_link(struct kobject *kobj, struct kobject *targ,
155 if (sd->s_symlink.target_sd->s_dir.kobj != targ) 161 if (sd->s_symlink.target_sd->s_dir.kobj != targ)
156 goto out; 162 goto out;
157 163
158 result = sysfs_rename(sd, parent_sd, new); 164 if (sysfs_ns_type(parent_sd))
165 new_ns = targ->ktype->namespace(targ);
166
167 result = sysfs_rename(sd, parent_sd, new_ns, new);
159 168
160out: 169out:
161 sysfs_put(sd); 170 sysfs_put(sd);
diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h
index 030a39dbb02c..93847d54c2e3 100644
--- a/fs/sysfs/sysfs.h
+++ b/fs/sysfs/sysfs.h
@@ -58,6 +58,7 @@ struct sysfs_dirent {
58 struct sysfs_dirent *s_sibling; 58 struct sysfs_dirent *s_sibling;
59 const char *s_name; 59 const char *s_name;
60 60
61 const void *s_ns;
61 union { 62 union {
62 struct sysfs_elem_dir s_dir; 63 struct sysfs_elem_dir s_dir;
63 struct sysfs_elem_symlink s_symlink; 64 struct sysfs_elem_symlink s_symlink;
@@ -81,14 +82,22 @@ struct sysfs_dirent {
81#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) 82#define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK)
82#define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) 83#define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR)
83 84
84#define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK 85#define SYSFS_NS_TYPE_MASK 0xff00
85#define SYSFS_FLAG_REMOVED 0x0200 86#define SYSFS_NS_TYPE_SHIFT 8
87
88#define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK)
89#define SYSFS_FLAG_REMOVED 0x020000
86 90
87static inline unsigned int sysfs_type(struct sysfs_dirent *sd) 91static inline unsigned int sysfs_type(struct sysfs_dirent *sd)
88{ 92{
89 return sd->s_flags & SYSFS_TYPE_MASK; 93 return sd->s_flags & SYSFS_TYPE_MASK;
90} 94}
91 95
96static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd)
97{
98 return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT;
99}
100
92#ifdef CONFIG_DEBUG_LOCK_ALLOC 101#ifdef CONFIG_DEBUG_LOCK_ALLOC
93#define sysfs_dirent_init_lockdep(sd) \ 102#define sysfs_dirent_init_lockdep(sd) \
94do { \ 103do { \
@@ -115,6 +124,7 @@ struct sysfs_addrm_cxt {
115 * mount.c 124 * mount.c
116 */ 125 */
117struct sysfs_super_info { 126struct sysfs_super_info {
127 const void *ns[KOBJ_NS_TYPES];
118}; 128};
119#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) 129#define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info))
120extern struct sysfs_dirent sysfs_root; 130extern struct sysfs_dirent sysfs_root;
@@ -140,8 +150,10 @@ void sysfs_remove_one(struct sysfs_addrm_cxt *acxt, struct sysfs_dirent *sd);
140void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt); 150void sysfs_addrm_finish(struct sysfs_addrm_cxt *acxt);
141 151
142struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, 152struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd,
153 const void *ns,
143 const unsigned char *name); 154 const unsigned char *name);
144struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, 155struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
156 const void *ns,
145 const unsigned char *name); 157 const unsigned char *name);
146struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type); 158struct sysfs_dirent *sysfs_new_dirent(const char *name, umode_t mode, int type);
147 159
@@ -152,7 +164,7 @@ int sysfs_create_subdir(struct kobject *kobj, const char *name,
152void sysfs_remove_subdir(struct sysfs_dirent *sd); 164void sysfs_remove_subdir(struct sysfs_dirent *sd);
153 165
154int sysfs_rename(struct sysfs_dirent *sd, 166int sysfs_rename(struct sysfs_dirent *sd,
155 struct sysfs_dirent *new_parent_sd, const char *new_name); 167 struct sysfs_dirent *new_parent_sd, const void *ns, const char *new_name);
156 168
157static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd) 169static inline struct sysfs_dirent *__sysfs_get(struct sysfs_dirent *sd)
158{ 170{
@@ -182,7 +194,7 @@ int sysfs_setattr(struct dentry *dentry, struct iattr *iattr);
182int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); 194int sysfs_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat);
183int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value, 195int sysfs_setxattr(struct dentry *dentry, const char *name, const void *value,
184 size_t size, int flags); 196 size_t size, int flags);
185int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const char *name); 197int sysfs_hash_and_remove(struct sysfs_dirent *dir_sd, const void *ns, const char *name);
186int sysfs_inode_init(void); 198int sysfs_inode_init(void);
187 199
188/* 200/*
diff --git a/include/linux/sysfs.h b/include/linux/sysfs.h
index f0496b3d1811..1885d21b0c80 100644
--- a/include/linux/sysfs.h
+++ b/include/linux/sysfs.h
@@ -20,6 +20,7 @@
20 20
21struct kobject; 21struct kobject;
22struct module; 22struct module;
23enum kobj_ns_type;
23 24
24/* FIXME 25/* FIXME
25 * The *owner field is no longer used. 26 * The *owner field is no longer used.
@@ -168,10 +169,14 @@ void sysfs_remove_file_from_group(struct kobject *kobj,
168void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr); 169void sysfs_notify(struct kobject *kobj, const char *dir, const char *attr);
169void sysfs_notify_dirent(struct sysfs_dirent *sd); 170void sysfs_notify_dirent(struct sysfs_dirent *sd);
170struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, 171struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
172 const void *ns,
171 const unsigned char *name); 173 const unsigned char *name);
172struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd); 174struct sysfs_dirent *sysfs_get(struct sysfs_dirent *sd);
173void sysfs_put(struct sysfs_dirent *sd); 175void sysfs_put(struct sysfs_dirent *sd);
174void sysfs_printk_last_file(void); 176void sysfs_printk_last_file(void);
177
178void sysfs_exit_ns(enum kobj_ns_type type, const void *tag);
179
175int __must_check sysfs_init(void); 180int __must_check sysfs_init(void);
176 181
177#else /* CONFIG_SYSFS */ 182#else /* CONFIG_SYSFS */
@@ -301,6 +306,7 @@ static inline void sysfs_notify_dirent(struct sysfs_dirent *sd)
301} 306}
302static inline 307static inline
303struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, 308struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd,
309 const void *ns,
304 const unsigned char *name) 310 const unsigned char *name)
305{ 311{
306 return NULL; 312 return NULL;
@@ -313,6 +319,10 @@ static inline void sysfs_put(struct sysfs_dirent *sd)
313{ 319{
314} 320}
315 321
322static inline void sysfs_exit_ns(enum kobj_ns_type type, const void *tag)
323{
324}
325
316static inline int __must_check sysfs_init(void) 326static inline int __must_check sysfs_init(void)
317{ 327{
318 return 0; 328 return 0;
diff --git a/lib/kobject.c b/lib/kobject.c
index bbb2bb40ee1f..b2c6d1f56e65 100644
--- a/lib/kobject.c
+++ b/lib/kobject.c
@@ -950,6 +950,7 @@ const void *kobj_ns_initial(enum kobj_ns_type type)
950 950
951void kobj_ns_exit(enum kobj_ns_type type, const void *ns) 951void kobj_ns_exit(enum kobj_ns_type type, const void *ns)
952{ 952{
953 sysfs_exit_ns(type, ns);
953} 954}
954 955
955 956