Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Revert "sysfs: drop kobj_ns_type handling"

This reverts commit cb26a311578e67769e92a39a0a63476533cb7e12.

It mysteriously causes NetworkManager to not find the wireless device
for me. As far as I can tell, Tejun *meant* for this commit to not make
any semantic changes, but there clearly are some. So revert it, taking
into account some of the calling convention changes that happened in
this area in subsequent commits.

Cc: Tejun Heo <tj@kernel.org>
Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

+122 -47
+64 -24
fs/sysfs/dir.c
··· 111 111 /* add new node and rebalance the tree */ 112 112 rb_link_node(&sd->s_rb, parent, node); 113 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 - 119 114 return 0; 120 115 } 121 116 ··· 130 135 sd->s_parent->s_dir.subdirs--; 131 136 132 137 rb_erase(&sd->s_rb, &sd->s_parent->s_dir.children); 133 - 134 - /* 135 - * Either all or none of the children have tags. Clearing HAS_NS 136 - * when there's no child left is enough to keep the flag synced. 137 - */ 138 - if (RB_EMPTY_ROOT(&sd->s_parent->s_dir.children)) 139 - sd->s_parent->s_flags &= ~SYSFS_FLAG_HAS_NS; 140 138 } 141 139 142 140 /** ··· 279 291 static int sysfs_dentry_revalidate(struct dentry *dentry, unsigned int flags) 280 292 { 281 293 struct sysfs_dirent *sd; 294 + int type; 282 295 283 296 if (flags & LOOKUP_RCU) 284 297 return -ECHILD; ··· 300 311 goto out_bad; 301 312 302 313 /* The sysfs dirent has been moved to a different namespace */ 303 - if (sd->s_ns && sd->s_ns != sysfs_info(dentry->d_sb)->ns) 304 - goto out_bad; 314 + type = KOBJ_NS_TYPE_NONE; 315 + if (sd->s_parent) { 316 + type = sysfs_ns_type(sd->s_parent); 317 + if (type != KOBJ_NS_TYPE_NONE && 318 + sysfs_info(dentry->d_sb)->ns[type] != sd->s_ns) 319 + goto out_bad; 320 + } 305 321 306 322 mutex_unlock(&sysfs_mutex); 307 323 out_valid: ··· 425 431 { 426 432 struct sysfs_inode_attrs *ps_iattr; 427 433 int ret; 434 + 435 + if (!!sysfs_ns_type(parent_sd) != !!sd->s_ns) { 436 + WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", 437 + sysfs_ns_type(parent_sd) ? "required" : "invalid", 438 + parent_sd->s_name, sd->s_name); 439 + return -EINVAL; 440 + } 428 441 429 442 sd->s_hash = sysfs_name_hash(sd->s_name, sd->s_ns); 430 443 sd->s_parent = sysfs_get(parent_sd); ··· 612 611 struct rb_node *node = parent_sd->s_dir.children.rb_node; 613 612 unsigned int hash; 614 613 614 + if (!!sysfs_ns_type(parent_sd) != !!ns) { 615 + WARN(1, KERN_WARNING "sysfs: ns %s in '%s' for '%s'\n", 616 + sysfs_ns_type(parent_sd) ? "required" : "invalid", 617 + parent_sd->s_name, name); 618 + return NULL; 619 + } 620 + 615 621 hash = sysfs_name_hash(name, ns); 616 622 while (node) { 617 623 struct sysfs_dirent *sd; ··· 667 659 EXPORT_SYMBOL_GPL(sysfs_get_dirent_ns); 668 660 669 661 static int create_dir(struct kobject *kobj, struct sysfs_dirent *parent_sd, 662 + enum kobj_ns_type type, 670 663 const char *name, const void *ns, 671 664 struct sysfs_dirent **p_sd) 672 665 { ··· 681 672 if (!sd) 682 673 return -ENOMEM; 683 674 675 + sd->s_flags |= (type << SYSFS_NS_TYPE_SHIFT); 684 676 sd->s_ns = ns; 685 677 sd->s_dir.kobj = kobj; 686 678 ··· 701 691 int sysfs_create_subdir(struct kobject *kobj, const char *name, 702 692 struct sysfs_dirent **p_sd) 703 693 { 704 - return create_dir(kobj, kobj->sd, name, NULL, p_sd); 694 + return create_dir(kobj, kobj->sd, 695 + KOBJ_NS_TYPE_NONE, name, NULL, p_sd); 696 + } 697 + 698 + /** 699 + * sysfs_read_ns_type: return associated ns_type 700 + * @kobj: the kobject being queried 701 + * 702 + * Each kobject can be tagged with exactly one namespace type 703 + * (i.e. network or user). Return the ns_type associated with 704 + * this object if any 705 + */ 706 + static enum kobj_ns_type sysfs_read_ns_type(struct kobject *kobj) 707 + { 708 + const struct kobj_ns_type_operations *ops; 709 + enum kobj_ns_type type; 710 + 711 + ops = kobj_child_ns_ops(kobj); 712 + if (!ops) 713 + return KOBJ_NS_TYPE_NONE; 714 + 715 + type = ops->type; 716 + BUG_ON(type <= KOBJ_NS_TYPE_NONE); 717 + BUG_ON(type >= KOBJ_NS_TYPES); 718 + BUG_ON(!kobj_ns_type_registered(type)); 719 + 720 + return type; 705 721 } 706 722 707 723 /** ··· 737 701 */ 738 702 int sysfs_create_dir_ns(struct kobject *kobj, const void *ns) 739 703 { 704 + enum kobj_ns_type type; 740 705 struct sysfs_dirent *parent_sd, *sd; 741 706 int error = 0; 742 707 ··· 751 714 if (!parent_sd) 752 715 return -ENOENT; 753 716 754 - error = create_dir(kobj, parent_sd, kobject_name(kobj), ns, &sd); 717 + type = sysfs_read_ns_type(kobj); 718 + 719 + error = create_dir(kobj, parent_sd, type, kobject_name(kobj), ns, &sd); 755 720 if (!error) 756 721 kobj->sd = sd; 757 722 return error; ··· 767 728 struct sysfs_dirent *parent_sd = parent->d_fsdata; 768 729 struct sysfs_dirent *sd; 769 730 struct inode *inode; 770 - const void *ns = NULL; 731 + enum kobj_ns_type type; 732 + const void *ns; 771 733 772 734 mutex_lock(&sysfs_mutex); 773 735 774 - if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS) 775 - ns = sysfs_info(dir->i_sb)->ns; 736 + type = sysfs_ns_type(parent_sd); 737 + ns = sysfs_info(dir->i_sb)->ns[type]; 776 738 777 739 sd = sysfs_find_dirent(parent_sd, dentry->d_name.name, ns); 778 740 ··· 1096 1056 struct dentry *dentry = file->f_path.dentry; 1097 1057 struct sysfs_dirent *parent_sd = dentry->d_fsdata; 1098 1058 struct sysfs_dirent *pos = file->private_data; 1099 - const void *ns = NULL; 1059 + enum kobj_ns_type type; 1060 + const void *ns; 1061 + 1062 + type = sysfs_ns_type(parent_sd); 1063 + ns = sysfs_info(dentry->d_sb)->ns[type]; 1100 1064 1101 1065 if (!dir_emit_dots(file, ctx)) 1102 1066 return 0; 1103 1067 mutex_lock(&sysfs_mutex); 1104 - 1105 - if (parent_sd->s_flags & SYSFS_FLAG_HAS_NS) 1106 - ns = sysfs_info(dentry->d_sb)->ns; 1107 - 1108 1068 for (pos = sysfs_dir_pos(ns, parent_sd, ctx->pos, pos); 1109 1069 pos; 1110 1070 pos = sysfs_dir_next_pos(ns, parent_sd, ctx->pos, pos)) {
+18 -6
fs/sysfs/mount.c
··· 36 36 struct sysfs_dirent sysfs_root = { 37 37 .s_name = "", 38 38 .s_count = ATOMIC_INIT(1), 39 - .s_flags = SYSFS_DIR, 39 + .s_flags = SYSFS_DIR | (KOBJ_NS_TYPE_NONE << SYSFS_NS_TYPE_SHIFT), 40 40 .s_mode = S_IFDIR | S_IRUGO | S_IXUGO, 41 41 .s_ino = 1, 42 42 }; ··· 77 77 { 78 78 struct sysfs_super_info *sb_info = sysfs_info(sb); 79 79 struct sysfs_super_info *info = data; 80 + enum kobj_ns_type type; 81 + int found = 1; 80 82 81 - return sb_info->ns == info->ns; 83 + for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { 84 + if (sb_info->ns[type] != info->ns[type]) 85 + found = 0; 86 + } 87 + return found; 82 88 } 83 89 84 90 static int sysfs_set_super(struct super_block *sb, void *data) ··· 98 92 99 93 static void free_sysfs_super_info(struct sysfs_super_info *info) 100 94 { 101 - kobj_ns_drop(KOBJ_NS_TYPE_NET, info->ns); 95 + int type; 96 + for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) 97 + kobj_ns_drop(type, info->ns[type]); 102 98 kfree(info); 103 99 } 104 100 ··· 108 100 int flags, const char *dev_name, void *data) 109 101 { 110 102 struct sysfs_super_info *info; 103 + enum kobj_ns_type type; 111 104 struct super_block *sb; 112 105 int error; 113 106 ··· 116 107 if (!capable(CAP_SYS_ADMIN) && !fs_fully_visible(fs_type)) 117 108 return ERR_PTR(-EPERM); 118 109 119 - if (!kobj_ns_current_may_mount(KOBJ_NS_TYPE_NET)) 120 - return ERR_PTR(-EPERM); 110 + for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) { 111 + if (!kobj_ns_current_may_mount(type)) 112 + return ERR_PTR(-EPERM); 113 + } 121 114 } 122 115 123 116 info = kzalloc(sizeof(*info), GFP_KERNEL); 124 117 if (!info) 125 118 return ERR_PTR(-ENOMEM); 126 119 127 - info->ns = kobj_ns_grab_current(KOBJ_NS_TYPE_NET); 120 + for (type = KOBJ_NS_TYPE_NONE; type < KOBJ_NS_TYPES; type++) 121 + info->ns[type] = kobj_ns_grab_current(type); 128 122 129 123 sb = sget(fs_type, sysfs_test_super, sysfs_set_super, flags, info); 130 124 if (IS_ERR(sb) || sb->s_fs_info != info)
+21 -6
fs/sysfs/symlink.c
··· 28 28 struct sysfs_dirent *target_sd = NULL; 29 29 struct sysfs_dirent *sd = NULL; 30 30 struct sysfs_addrm_cxt acxt; 31 + enum kobj_ns_type ns_type; 31 32 int error; 32 33 33 34 BUG_ON(!name || !parent_sd); ··· 52 51 if (!sd) 53 52 goto out_put; 54 53 55 - sd->s_ns = target_sd->s_ns; 54 + ns_type = sysfs_ns_type(parent_sd); 55 + if (ns_type) 56 + sd->s_ns = target_sd->s_ns; 56 57 sd->s_symlink.target_sd = target_sd; 57 58 target_sd = NULL; /* reference is now owned by the symlink */ 58 59 59 60 sysfs_addrm_start(&acxt); 60 - if (warn) 61 - error = sysfs_add_one(&acxt, sd, parent_sd); 62 - else 63 - error = __sysfs_add_one(&acxt, sd, parent_sd); 61 + /* Symlinks must be between directories with the same ns_type */ 62 + if (!ns_type || 63 + (ns_type == sysfs_ns_type(sd->s_symlink.target_sd->s_parent))) { 64 + if (warn) 65 + error = sysfs_add_one(&acxt, sd, parent_sd); 66 + else 67 + error = __sysfs_add_one(&acxt, sd, parent_sd); 68 + } else { 69 + error = -EINVAL; 70 + WARN(1, KERN_WARNING 71 + "sysfs: symlink across ns_types %s/%s -> %s/%s\n", 72 + parent_sd->s_name, 73 + sd->s_name, 74 + sd->s_symlink.target_sd->s_parent->s_name, 75 + sd->s_symlink.target_sd->s_name); 76 + } 64 77 sysfs_addrm_finish(&acxt); 65 78 66 79 if (error) ··· 164 149 * sysfs_remove_dir() for details. 165 150 */ 166 151 spin_lock(&sysfs_symlink_target_lock); 167 - if (targ->sd) 152 + if (targ->sd && sysfs_ns_type(kobj->sd)) 168 153 ns = targ->sd->s_ns; 169 154 spin_unlock(&sysfs_symlink_target_lock); 170 155 sysfs_hash_and_remove(kobj->sd, name, ns);
+18 -7
fs/sysfs/sysfs.h
··· 90 90 #define SYSFS_COPY_NAME (SYSFS_DIR | SYSFS_KOBJ_LINK) 91 91 #define SYSFS_ACTIVE_REF (SYSFS_KOBJ_ATTR | SYSFS_KOBJ_BIN_ATTR) 92 92 93 - #define SYSFS_FLAG_MASK ~SYSFS_TYPE_MASK 94 - #define SYSFS_FLAG_HAS_NS 0x01000 93 + /* identify any namespace tag on sysfs_dirents */ 94 + #define SYSFS_NS_TYPE_MASK 0xf00 95 + #define SYSFS_NS_TYPE_SHIFT 8 96 + 97 + #define SYSFS_FLAG_MASK ~(SYSFS_NS_TYPE_MASK|SYSFS_TYPE_MASK) 95 98 #define SYSFS_FLAG_REMOVED 0x02000 96 99 97 100 static inline unsigned int sysfs_type(struct sysfs_dirent *sd) 98 101 { 99 102 return sd->s_flags & SYSFS_TYPE_MASK; 103 + } 104 + 105 + /* 106 + * Return any namespace tags on this dirent. 107 + * enum kobj_ns_type is defined in linux/kobject.h 108 + */ 109 + static inline enum kobj_ns_type sysfs_ns_type(struct sysfs_dirent *sd) 110 + { 111 + return (sd->s_flags & SYSFS_NS_TYPE_MASK) >> SYSFS_NS_TYPE_SHIFT; 100 112 } 101 113 102 114 #ifdef CONFIG_DEBUG_LOCK_ALLOC ··· 155 143 */ 156 144 157 145 /* 158 - * Each sb is associated with one namespace tag, currently the network 159 - * namespace of the task which mounted this sysfs instance. If multiple 160 - * tags become necessary, make the following an array and compare 161 - * sysfs_dirent tag against every entry. 146 + * Each sb is associated with a set of namespace tags (i.e. 147 + * the network namespace of the task which mounted this sysfs 148 + * instance). 162 149 */ 163 150 struct sysfs_super_info { 164 - void *ns; 151 + void *ns[KOBJ_NS_TYPES]; 165 152 }; 166 153 #define sysfs_info(SB) ((struct sysfs_super_info *)(SB->s_fs_info)) 167 154 extern struct sysfs_dirent sysfs_root;
+1 -4
lib/kobject.c
··· 30 30 const void *kobject_namespace(struct kobject *kobj) 31 31 { 32 32 const struct kobj_ns_type_operations *ns_ops = kobj_ns_ops(kobj); 33 - const void *ns; 34 33 35 34 if (!ns_ops || ns_ops->type == KOBJ_NS_TYPE_NONE) 36 35 return NULL; 37 36 38 - ns = kobj->ktype->namespace(kobj); 39 - WARN_ON(!ns); /* @kobj in a namespace is required to have !NULL tag */ 40 - return ns; 37 + return kobj->ktype->namespace(kobj); 41 38 } 42 39 43 40 /*