diff options
Diffstat (limited to 'fs/sysfs/dir.c')
-rw-r--r-- | fs/sysfs/dir.c | 112 |
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 | */ |
535 | struct sysfs_dirent *sysfs_find_dirent(struct sysfs_dirent *parent_sd, | 541 | struct 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 | */ |
560 | struct sysfs_dirent *sysfs_get_dirent(struct sysfs_dirent *parent_sd, | 570 | struct 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, | |||
572 | EXPORT_SYMBOL_GPL(sysfs_get_dirent); | 583 | EXPORT_SYMBOL_GPL(sysfs_get_dirent); |
573 | 584 | ||
574 | static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, | 585 | static 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, | |||
601 | int sysfs_create_subdir(struct kobject *kobj, const char *name, | 616 | int 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 | |||
623 | static 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 | */ |
611 | int sysfs_create_dir(struct kobject * kobj) | 644 | int 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 | ||
737 | int sysfs_rename(struct sysfs_dirent *sd, | 782 | int 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 | ||
781 | int sysfs_rename_dir(struct kobject *kobj, const char *new_name) | 828 | int 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 | ||
786 | int sysfs_move_dir(struct kobject *kobj, struct kobject *new_parent_kobj) | 839 | int 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 | ||
810 | static struct sysfs_dirent *sysfs_dir_pos(struct sysfs_dirent *parent_sd, | 866 | static 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 | ||
830 | static struct sysfs_dirent *sysfs_dir_next_pos(struct sysfs_dirent *parent_sd, | 887 | static 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; |