aboutsummaryrefslogtreecommitdiffstats
path: root/fs/sysfs/dir.c
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 /fs/sysfs/dir.c
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>
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r--fs/sysfs/dir.c112
1 files changed, 88 insertions, 24 deletions
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;