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

Configure Feed

Select the types of activity you want to include in your feed.

nstree: introduce a unified tree

This will allow userspace to lookup and stat a namespace simply by its
identifier without having to know what type of namespace it is.

Link: https://patch.msgid.link/20251029-work-namespace-nstree-listns-v4-13-2e6f823ebdc0@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

+76 -24
+3
include/linux/ns_common.h
··· 109 109 union { 110 110 struct { 111 111 u64 ns_id; 112 + struct /* global namespace rbtree and list */ { 113 + struct rb_node ns_unified_tree_node; 114 + }; 112 115 struct /* per type rbtree and list */ { 113 116 struct rb_node ns_tree_node; 114 117 struct list_head ns_list_node;
+1
kernel/nscommon.c
··· 62 62 ns->ns_id = 0; 63 63 ns->ns_type = ns_type; 64 64 RB_CLEAR_NODE(&ns->ns_tree_node); 65 + RB_CLEAR_NODE(&ns->ns_unified_tree_node); 65 66 INIT_LIST_HEAD(&ns->ns_list_node); 66 67 67 68 #ifdef CONFIG_DEBUG_VFS
+72 -24
kernel/nstree.c
··· 5 5 #include <linux/proc_ns.h> 6 6 #include <linux/vfsdebug.h> 7 7 8 + static __cacheline_aligned_in_smp DEFINE_SEQLOCK(ns_tree_lock); 9 + static struct rb_root ns_unified_tree = RB_ROOT; /* protected by ns_tree_lock */ 10 + 8 11 /** 9 12 * struct ns_tree - Namespace tree 10 13 * @ns_tree: Rbtree of namespaces of a particular type 11 14 * @ns_list: Sequentially walkable list of all namespaces of this type 12 - * @ns_tree_lock: Seqlock to protect the tree and list 13 15 * @type: type of namespaces in this tree 14 16 */ 15 17 struct ns_tree { 16 - struct rb_root ns_tree; 17 - struct list_head ns_list; 18 - seqlock_t ns_tree_lock; 19 - int type; 18 + struct rb_root ns_tree; 19 + struct list_head ns_list; 20 + int type; 20 21 }; 21 22 22 23 struct ns_tree mnt_ns_tree = { 23 24 .ns_tree = RB_ROOT, 24 25 .ns_list = LIST_HEAD_INIT(mnt_ns_tree.ns_list), 25 - .ns_tree_lock = __SEQLOCK_UNLOCKED(mnt_ns_tree.ns_tree_lock), 26 26 .type = CLONE_NEWNS, 27 27 }; 28 28 29 29 struct ns_tree net_ns_tree = { 30 30 .ns_tree = RB_ROOT, 31 31 .ns_list = LIST_HEAD_INIT(net_ns_tree.ns_list), 32 - .ns_tree_lock = __SEQLOCK_UNLOCKED(net_ns_tree.ns_tree_lock), 33 32 .type = CLONE_NEWNET, 34 33 }; 35 34 EXPORT_SYMBOL_GPL(net_ns_tree); ··· 36 37 struct ns_tree uts_ns_tree = { 37 38 .ns_tree = RB_ROOT, 38 39 .ns_list = LIST_HEAD_INIT(uts_ns_tree.ns_list), 39 - .ns_tree_lock = __SEQLOCK_UNLOCKED(uts_ns_tree.ns_tree_lock), 40 40 .type = CLONE_NEWUTS, 41 41 }; 42 42 43 43 struct ns_tree user_ns_tree = { 44 44 .ns_tree = RB_ROOT, 45 45 .ns_list = LIST_HEAD_INIT(user_ns_tree.ns_list), 46 - .ns_tree_lock = __SEQLOCK_UNLOCKED(user_ns_tree.ns_tree_lock), 47 46 .type = CLONE_NEWUSER, 48 47 }; 49 48 50 49 struct ns_tree ipc_ns_tree = { 51 50 .ns_tree = RB_ROOT, 52 51 .ns_list = LIST_HEAD_INIT(ipc_ns_tree.ns_list), 53 - .ns_tree_lock = __SEQLOCK_UNLOCKED(ipc_ns_tree.ns_tree_lock), 54 52 .type = CLONE_NEWIPC, 55 53 }; 56 54 57 55 struct ns_tree pid_ns_tree = { 58 56 .ns_tree = RB_ROOT, 59 57 .ns_list = LIST_HEAD_INIT(pid_ns_tree.ns_list), 60 - .ns_tree_lock = __SEQLOCK_UNLOCKED(pid_ns_tree.ns_tree_lock), 61 58 .type = CLONE_NEWPID, 62 59 }; 63 60 64 61 struct ns_tree cgroup_ns_tree = { 65 62 .ns_tree = RB_ROOT, 66 63 .ns_list = LIST_HEAD_INIT(cgroup_ns_tree.ns_list), 67 - .ns_tree_lock = __SEQLOCK_UNLOCKED(cgroup_ns_tree.ns_tree_lock), 68 64 .type = CLONE_NEWCGROUP, 69 65 }; 70 66 71 67 struct ns_tree time_ns_tree = { 72 68 .ns_tree = RB_ROOT, 73 69 .ns_list = LIST_HEAD_INIT(time_ns_tree.ns_list), 74 - .ns_tree_lock = __SEQLOCK_UNLOCKED(time_ns_tree.ns_tree_lock), 75 70 .type = CLONE_NEWTIME, 76 71 }; 77 72 ··· 76 83 if (!node) 77 84 return NULL; 78 85 return rb_entry(node, struct ns_common, ns_tree_node); 86 + } 87 + 88 + static inline struct ns_common *node_to_ns_unified(const struct rb_node *node) 89 + { 90 + if (!node) 91 + return NULL; 92 + return rb_entry(node, struct ns_common, ns_unified_tree_node); 79 93 } 80 94 81 95 static inline int ns_cmp(struct rb_node *a, const struct rb_node *b) ··· 99 99 return 0; 100 100 } 101 101 102 + static inline int ns_cmp_unified(struct rb_node *a, const struct rb_node *b) 103 + { 104 + struct ns_common *ns_a = node_to_ns_unified(a); 105 + struct ns_common *ns_b = node_to_ns_unified(b); 106 + u64 ns_id_a = ns_a->ns_id; 107 + u64 ns_id_b = ns_b->ns_id; 108 + 109 + if (ns_id_a < ns_id_b) 110 + return -1; 111 + if (ns_id_a > ns_id_b) 112 + return 1; 113 + return 0; 114 + } 115 + 102 116 void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree *ns_tree) 103 117 { 104 118 struct rb_node *node, *prev; 105 119 106 120 VFS_WARN_ON_ONCE(!ns->ns_id); 107 121 108 - write_seqlock(&ns_tree->ns_tree_lock); 109 - 110 - VFS_WARN_ON_ONCE(ns->ns_type != ns_tree->type); 122 + write_seqlock(&ns_tree_lock); 111 123 112 124 node = rb_find_add_rcu(&ns->ns_tree_node, &ns_tree->ns_tree, ns_cmp); 113 125 /* ··· 132 120 else 133 121 list_add_rcu(&ns->ns_list_node, &node_to_ns(prev)->ns_list_node); 134 122 135 - write_sequnlock(&ns_tree->ns_tree_lock); 123 + rb_find_add_rcu(&ns->ns_unified_tree_node, &ns_unified_tree, ns_cmp_unified); 124 + write_sequnlock(&ns_tree_lock); 136 125 137 126 VFS_WARN_ON_ONCE(node); 138 127 ··· 152 139 VFS_WARN_ON_ONCE(list_empty(&ns->ns_list_node)); 153 140 VFS_WARN_ON_ONCE(ns->ns_type != ns_tree->type); 154 141 155 - write_seqlock(&ns_tree->ns_tree_lock); 142 + write_seqlock(&ns_tree_lock); 156 143 rb_erase(&ns->ns_tree_node, &ns_tree->ns_tree); 144 + rb_erase(&ns->ns_unified_tree_node, &ns_unified_tree); 157 145 list_bidir_del_rcu(&ns->ns_list_node); 158 146 RB_CLEAR_NODE(&ns->ns_tree_node); 159 - write_sequnlock(&ns_tree->ns_tree_lock); 147 + write_sequnlock(&ns_tree_lock); 160 148 } 161 149 EXPORT_SYMBOL_GPL(__ns_tree_remove); 162 150 ··· 173 159 return 0; 174 160 } 175 161 162 + static int ns_find_unified(const void *key, const struct rb_node *node) 163 + { 164 + const u64 ns_id = *(u64 *)key; 165 + const struct ns_common *ns = node_to_ns_unified(node); 166 + 167 + if (ns_id < ns->ns_id) 168 + return -1; 169 + if (ns_id > ns->ns_id) 170 + return 1; 171 + return 0; 172 + } 176 173 177 174 static struct ns_tree *ns_tree_from_type(int ns_type) 178 175 { ··· 209 184 return NULL; 210 185 } 211 186 212 - struct ns_common *ns_tree_lookup_rcu(u64 ns_id, int ns_type) 187 + static struct ns_common *__ns_unified_tree_lookup_rcu(u64 ns_id) 188 + { 189 + struct rb_node *node; 190 + unsigned int seq; 191 + 192 + do { 193 + seq = read_seqbegin(&ns_tree_lock); 194 + node = rb_find_rcu(&ns_id, &ns_unified_tree, ns_find_unified); 195 + if (node) 196 + break; 197 + } while (read_seqretry(&ns_tree_lock, seq)); 198 + 199 + return node_to_ns_unified(node); 200 + } 201 + 202 + static struct ns_common *__ns_tree_lookup_rcu(u64 ns_id, int ns_type) 213 203 { 214 204 struct ns_tree *ns_tree; 215 205 struct rb_node *node; 216 206 unsigned int seq; 217 - 218 - RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "suspicious ns_tree_lookup_rcu() usage"); 219 207 220 208 ns_tree = ns_tree_from_type(ns_type); 221 209 if (!ns_tree) 222 210 return NULL; 223 211 224 212 do { 225 - seq = read_seqbegin(&ns_tree->ns_tree_lock); 213 + seq = read_seqbegin(&ns_tree_lock); 226 214 node = rb_find_rcu(&ns_id, &ns_tree->ns_tree, ns_find); 227 215 if (node) 228 216 break; 229 - } while (read_seqretry(&ns_tree->ns_tree_lock, seq)); 217 + } while (read_seqretry(&ns_tree_lock, seq)); 230 218 231 219 return node_to_ns(node); 220 + } 221 + 222 + struct ns_common *ns_tree_lookup_rcu(u64 ns_id, int ns_type) 223 + { 224 + RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "suspicious ns_tree_lookup_rcu() usage"); 225 + 226 + if (ns_type) 227 + return __ns_tree_lookup_rcu(ns_id, ns_type); 228 + 229 + return __ns_unified_tree_lookup_rcu(ns_id); 232 230 } 233 231 234 232 /**