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

Merge patch series "ns: header cleanups and initial namespace reference count improvements"

Christian Brauner <brauner@kernel.org> says:

Cleanup the namespace headers by splitting them into types and helpers.
Better separate common namepace types and functions from namespace tree
types and functions.

Fix the reference counts of initial namespaces so we don't do any
pointless cacheline ping-pong for them when we know they can never go
away. Add a bunch of asserts for both the passive and active reference
counts to catch any changes that would break it.

* patches from https://patch.msgid.link/20251110-work-namespace-nstree-fixes-v1-0-e8a9264e0fb9@kernel.org:
selftests/namespaces: fix nsid tests
ns: drop custom reference count initialization for initial namespaces
pid: rely on common reference count behavior
ns: add asserts for initial namespace active reference counts
ns: add asserts for initial namespace reference counts
ns: make all reference counts on initial namespace a nop
ipc: enable is_ns_init_id() assertions
fs: use boolean to indicate anonymous mount namespace
ns: rename is_initial_namespace()
ns: make is_initial_namespace() argument const
nstree: use guards for ns_tree_lock
nstree: simplify owner list iteration
nstree: switch to new structures
nstree: add helper to operate on struct ns_tree_{node,root}
nstree: move nstree types into separate header
nstree: decouple from ns_common header
ns: move namespace types into separate header

Link: https://patch.msgid.link/20251110-work-namespace-nstree-fixes-v1-0-e8a9264e0fb9@kernel.org
Signed-off-by: Christian Brauner <brauner@kernel.org>

+576 -437
+2 -1
fs/mount.h
··· 27 27 unsigned int nr_mounts; /* # of mounts in the namespace */ 28 28 unsigned int pending_mounts; 29 29 refcount_t passive; /* number references not pinning @mounts */ 30 + bool is_anon; 30 31 } __randomize_layout; 31 32 32 33 struct mnt_pcp { ··· 176 175 177 176 static inline bool is_anon_ns(struct mnt_namespace *ns) 178 177 { 179 - return ns->ns.ns_id == 0; 178 + return ns->is_anon; 180 179 } 181 180 182 181 static inline bool anon_ns_root(const struct mount *m)
+5 -4
fs/namespace.c
··· 138 138 139 139 if (!node) 140 140 return NULL; 141 - ns = rb_entry(node, struct ns_common, ns_tree_node); 141 + ns = rb_entry(node, struct ns_common, ns_tree_node.ns_node); 142 142 return container_of(ns, struct mnt_namespace, ns); 143 143 } 144 144 ··· 4093 4093 dec_mnt_namespaces(ucounts); 4094 4094 return ERR_PTR(ret); 4095 4095 } 4096 - if (!anon) 4097 - ns_tree_gen_id(new_ns); 4096 + ns_tree_gen_id(new_ns); 4097 + 4098 + new_ns->is_anon = anon; 4098 4099 refcount_set(&new_ns->passive, 1); 4099 4100 new_ns->mounts = RB_ROOT; 4100 4101 init_waitqueue_head(&new_ns->poll); ··· 5986 5985 } 5987 5986 5988 5987 struct mnt_namespace init_mnt_ns = { 5989 - .ns = NS_COMMON_INIT(init_mnt_ns, 1), 5988 + .ns = NS_COMMON_INIT(init_mnt_ns), 5990 5989 .user_ns = &init_user_ns, 5991 5990 .passive = REFCOUNT_INIT(1), 5992 5991 .mounts = RB_ROOT,
+196
include/linux/ns/ns_common_types.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + #ifndef _LINUX_NS_COMMON_TYPES_H 3 + #define _LINUX_NS_COMMON_TYPES_H 4 + 5 + #include <linux/atomic.h> 6 + #include <linux/ns/nstree_types.h> 7 + #include <linux/rbtree.h> 8 + #include <linux/refcount.h> 9 + #include <linux/types.h> 10 + 11 + struct cgroup_namespace; 12 + struct dentry; 13 + struct ipc_namespace; 14 + struct mnt_namespace; 15 + struct net; 16 + struct pid_namespace; 17 + struct proc_ns_operations; 18 + struct time_namespace; 19 + struct user_namespace; 20 + struct uts_namespace; 21 + 22 + extern struct cgroup_namespace init_cgroup_ns; 23 + extern struct ipc_namespace init_ipc_ns; 24 + extern struct mnt_namespace init_mnt_ns; 25 + extern struct net init_net; 26 + extern struct pid_namespace init_pid_ns; 27 + extern struct time_namespace init_time_ns; 28 + extern struct user_namespace init_user_ns; 29 + extern struct uts_namespace init_uts_ns; 30 + 31 + extern const struct proc_ns_operations cgroupns_operations; 32 + extern const struct proc_ns_operations ipcns_operations; 33 + extern const struct proc_ns_operations mntns_operations; 34 + extern const struct proc_ns_operations netns_operations; 35 + extern const struct proc_ns_operations pidns_operations; 36 + extern const struct proc_ns_operations pidns_for_children_operations; 37 + extern const struct proc_ns_operations timens_operations; 38 + extern const struct proc_ns_operations timens_for_children_operations; 39 + extern const struct proc_ns_operations userns_operations; 40 + extern const struct proc_ns_operations utsns_operations; 41 + 42 + /* 43 + * Namespace lifetimes are managed via a two-tier reference counting model: 44 + * 45 + * (1) __ns_ref (refcount_t): Main reference count tracking memory 46 + * lifetime. Controls when the namespace structure itself is freed. 47 + * It also pins the namespace on the namespace trees whereas (2) 48 + * only regulates their visibility to userspace. 49 + * 50 + * (2) __ns_ref_active (atomic_t): Reference count tracking active users. 51 + * Controls visibility of the namespace in the namespace trees. 52 + * Any live task that uses the namespace (via nsproxy or cred) holds 53 + * an active reference. Any open file descriptor or bind-mount of 54 + * the namespace holds an active reference. Once all tasks have 55 + * called exited their namespaces and all file descriptors and 56 + * bind-mounts have been released the active reference count drops 57 + * to zero and the namespace becomes inactive. IOW, the namespace 58 + * cannot be listed or opened via file handles anymore. 59 + * 60 + * Note that it is valid to transition from active to inactive and 61 + * back from inactive to active e.g., when resurrecting an inactive 62 + * namespace tree via the SIOCGSKNS ioctl(). 63 + * 64 + * Relationship and lifecycle states: 65 + * 66 + * - Active (__ns_ref_active > 0): 67 + * Namespace is actively used and visible to userspace. The namespace 68 + * can be reopened via /proc/<pid>/ns/<ns_type>, via namespace file 69 + * handles, or discovered via listns(). 70 + * 71 + * - Inactive (__ns_ref_active == 0, __ns_ref > 0): 72 + * No tasks are actively using the namespace and it isn't pinned by 73 + * any bind-mounts or open file descriptors anymore. But the namespace 74 + * is still kept alive by internal references. For example, the user 75 + * namespace could be pinned by an open file through file->f_cred 76 + * references when one of the now defunct tasks had opened a file and 77 + * handed the file descriptor off to another process via a UNIX 78 + * sockets. Such references keep the namespace structure alive through 79 + * __ns_ref but will not hold an active reference. 80 + * 81 + * - Destroyed (__ns_ref == 0): 82 + * No references remain. The namespace is removed from the tree and freed. 83 + * 84 + * State transitions: 85 + * 86 + * Active -> Inactive: 87 + * When the last task using the namespace exits it drops its active 88 + * references to all namespaces. However, user and pid namespaces 89 + * remain accessible until the task has been reaped. 90 + * 91 + * Inactive -> Active: 92 + * An inactive namespace tree might be resurrected due to e.g., the 93 + * SIOCGSKNS ioctl() on a socket. 94 + * 95 + * Inactive -> Destroyed: 96 + * When __ns_ref drops to zero the namespace is removed from the 97 + * namespaces trees and the memory is freed (after RCU grace period). 98 + * 99 + * Initial namespaces: 100 + * Boot-time namespaces (init_net, init_pid_ns, etc.) start with 101 + * __ns_ref_active = 1 and remain active forever. 102 + * 103 + * @ns_type: type of namespace (e.g., CLONE_NEWNET) 104 + * @stashed: cached dentry to be used by the vfs 105 + * @ops: namespace operations 106 + * @inum: namespace inode number (quickly recycled for non-initial namespaces) 107 + * @__ns_ref: main reference count (do not use directly) 108 + * @ns_tree: namespace tree nodes and active reference count 109 + */ 110 + struct ns_common { 111 + u32 ns_type; 112 + struct dentry *stashed; 113 + const struct proc_ns_operations *ops; 114 + unsigned int inum; 115 + refcount_t __ns_ref; /* do not use directly */ 116 + union { 117 + struct ns_tree; 118 + struct rcu_head ns_rcu; 119 + }; 120 + }; 121 + 122 + #define to_ns_common(__ns) \ 123 + _Generic((__ns), \ 124 + struct cgroup_namespace *: &(__ns)->ns, \ 125 + const struct cgroup_namespace *: &(__ns)->ns, \ 126 + struct ipc_namespace *: &(__ns)->ns, \ 127 + const struct ipc_namespace *: &(__ns)->ns, \ 128 + struct mnt_namespace *: &(__ns)->ns, \ 129 + const struct mnt_namespace *: &(__ns)->ns, \ 130 + struct net *: &(__ns)->ns, \ 131 + const struct net *: &(__ns)->ns, \ 132 + struct pid_namespace *: &(__ns)->ns, \ 133 + const struct pid_namespace *: &(__ns)->ns, \ 134 + struct time_namespace *: &(__ns)->ns, \ 135 + const struct time_namespace *: &(__ns)->ns, \ 136 + struct user_namespace *: &(__ns)->ns, \ 137 + const struct user_namespace *: &(__ns)->ns, \ 138 + struct uts_namespace *: &(__ns)->ns, \ 139 + const struct uts_namespace *: &(__ns)->ns) 140 + 141 + #define ns_init_inum(__ns) \ 142 + _Generic((__ns), \ 143 + struct cgroup_namespace *: CGROUP_NS_INIT_INO, \ 144 + struct ipc_namespace *: IPC_NS_INIT_INO, \ 145 + struct mnt_namespace *: MNT_NS_INIT_INO, \ 146 + struct net *: NET_NS_INIT_INO, \ 147 + struct pid_namespace *: PID_NS_INIT_INO, \ 148 + struct time_namespace *: TIME_NS_INIT_INO, \ 149 + struct user_namespace *: USER_NS_INIT_INO, \ 150 + struct uts_namespace *: UTS_NS_INIT_INO) 151 + 152 + #define ns_init_ns(__ns) \ 153 + _Generic((__ns), \ 154 + struct cgroup_namespace *: &init_cgroup_ns, \ 155 + struct ipc_namespace *: &init_ipc_ns, \ 156 + struct mnt_namespace *: &init_mnt_ns, \ 157 + struct net *: &init_net, \ 158 + struct pid_namespace *: &init_pid_ns, \ 159 + struct time_namespace *: &init_time_ns, \ 160 + struct user_namespace *: &init_user_ns, \ 161 + struct uts_namespace *: &init_uts_ns) 162 + 163 + #define ns_init_id(__ns) \ 164 + _Generic((__ns), \ 165 + struct cgroup_namespace *: CGROUP_NS_INIT_ID, \ 166 + struct ipc_namespace *: IPC_NS_INIT_ID, \ 167 + struct mnt_namespace *: MNT_NS_INIT_ID, \ 168 + struct net *: NET_NS_INIT_ID, \ 169 + struct pid_namespace *: PID_NS_INIT_ID, \ 170 + struct time_namespace *: TIME_NS_INIT_ID, \ 171 + struct user_namespace *: USER_NS_INIT_ID, \ 172 + struct uts_namespace *: UTS_NS_INIT_ID) 173 + 174 + #define to_ns_operations(__ns) \ 175 + _Generic((__ns), \ 176 + struct cgroup_namespace *: (IS_ENABLED(CONFIG_CGROUPS) ? &cgroupns_operations : NULL), \ 177 + struct ipc_namespace *: (IS_ENABLED(CONFIG_IPC_NS) ? &ipcns_operations : NULL), \ 178 + struct mnt_namespace *: &mntns_operations, \ 179 + struct net *: (IS_ENABLED(CONFIG_NET_NS) ? &netns_operations : NULL), \ 180 + struct pid_namespace *: (IS_ENABLED(CONFIG_PID_NS) ? &pidns_operations : NULL), \ 181 + struct time_namespace *: (IS_ENABLED(CONFIG_TIME_NS) ? &timens_operations : NULL), \ 182 + struct user_namespace *: (IS_ENABLED(CONFIG_USER_NS) ? &userns_operations : NULL), \ 183 + struct uts_namespace *: (IS_ENABLED(CONFIG_UTS_NS) ? &utsns_operations : NULL)) 184 + 185 + #define ns_common_type(__ns) \ 186 + _Generic((__ns), \ 187 + struct cgroup_namespace *: CLONE_NEWCGROUP, \ 188 + struct ipc_namespace *: CLONE_NEWIPC, \ 189 + struct mnt_namespace *: CLONE_NEWNS, \ 190 + struct net *: CLONE_NEWNET, \ 191 + struct pid_namespace *: CLONE_NEWPID, \ 192 + struct time_namespace *: CLONE_NEWTIME, \ 193 + struct user_namespace *: CLONE_NEWUSER, \ 194 + struct uts_namespace *: CLONE_NEWUTS) 195 + 196 + #endif /* _LINUX_NS_COMMON_TYPES_H */
+55
include/linux/ns/nstree_types.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright (c) 2025 Christian Brauner <brauner@kernel.org> */ 3 + #ifndef _LINUX_NSTREE_TYPES_H 4 + #define _LINUX_NSTREE_TYPES_H 5 + 6 + #include <linux/rbtree.h> 7 + #include <linux/list.h> 8 + 9 + /** 10 + * struct ns_tree_root - Root of a namespace tree 11 + * @ns_rb: Red-black tree root for efficient lookups 12 + * @ns_list_head: List head for sequential iteration 13 + * 14 + * Each namespace tree maintains both an rbtree (for O(log n) lookups) 15 + * and a list (for efficient sequential iteration). The list is kept in 16 + * the same sorted order as the rbtree. 17 + */ 18 + struct ns_tree_root { 19 + struct rb_root ns_rb; 20 + struct list_head ns_list_head; 21 + }; 22 + 23 + /** 24 + * struct ns_tree_node - Node in a namespace tree 25 + * @ns_node: Red-black tree node 26 + * @ns_list_entry: List entry for sequential iteration 27 + * 28 + * Represents a namespace's position in a tree. Each namespace has 29 + * multiple tree nodes for different trees (unified, per-type, owner). 30 + */ 31 + struct ns_tree_node { 32 + struct rb_node ns_node; 33 + struct list_head ns_list_entry; 34 + }; 35 + 36 + /** 37 + * struct ns_tree - Namespace tree nodes and active reference count 38 + * @ns_id: Unique namespace identifier 39 + * @__ns_ref_active: Active reference count (do not use directly) 40 + * @ns_unified_node: Node in the global namespace tree 41 + * @ns_tree_node: Node in the per-type namespace tree 42 + * @ns_owner_node: Node in the owner namespace's tree of owned namespaces 43 + * @ns_owner_root: Root of the tree of namespaces owned by this namespace 44 + * (only used when this namespace is an owner) 45 + */ 46 + struct ns_tree { 47 + u64 ns_id; 48 + atomic_t __ns_ref_active; 49 + struct ns_tree_node ns_unified_node; 50 + struct ns_tree_node ns_tree_node; 51 + struct ns_tree_node ns_owner_node; 52 + struct ns_tree_root ns_owner_root; 53 + }; 54 + 55 + #endif /* _LINUX_NSTREE_TYPES_H */
+51 -215
include/linux/ns_common.h
··· 2 2 #ifndef _LINUX_NS_COMMON_H 3 3 #define _LINUX_NS_COMMON_H 4 4 5 + #include <linux/ns/ns_common_types.h> 5 6 #include <linux/refcount.h> 6 - #include <linux/rbtree.h> 7 7 #include <linux/vfsdebug.h> 8 8 #include <uapi/linux/sched.h> 9 9 #include <uapi/linux/nsfs.h> 10 - 11 - struct proc_ns_operations; 12 - 13 - struct cgroup_namespace; 14 - struct ipc_namespace; 15 - struct mnt_namespace; 16 - struct net; 17 - struct pid_namespace; 18 - struct time_namespace; 19 - struct user_namespace; 20 - struct uts_namespace; 21 - 22 - extern struct cgroup_namespace init_cgroup_ns; 23 - extern struct ipc_namespace init_ipc_ns; 24 - extern struct mnt_namespace init_mnt_ns; 25 - extern struct net init_net; 26 - extern struct pid_namespace init_pid_ns; 27 - extern struct time_namespace init_time_ns; 28 - extern struct user_namespace init_user_ns; 29 - extern struct uts_namespace init_uts_ns; 30 - 31 - extern const struct proc_ns_operations netns_operations; 32 - extern const struct proc_ns_operations utsns_operations; 33 - extern const struct proc_ns_operations ipcns_operations; 34 - extern const struct proc_ns_operations pidns_operations; 35 - extern const struct proc_ns_operations pidns_for_children_operations; 36 - extern const struct proc_ns_operations userns_operations; 37 - extern const struct proc_ns_operations mntns_operations; 38 - extern const struct proc_ns_operations cgroupns_operations; 39 - extern const struct proc_ns_operations timens_operations; 40 - extern const struct proc_ns_operations timens_for_children_operations; 41 - 42 - /* 43 - * Namespace lifetimes are managed via a two-tier reference counting model: 44 - * 45 - * (1) __ns_ref (refcount_t): Main reference count tracking memory 46 - * lifetime. Controls when the namespace structure itself is freed. 47 - * It also pins the namespace on the namespace trees whereas (2) 48 - * only regulates their visibility to userspace. 49 - * 50 - * (2) __ns_ref_active (atomic_t): Reference count tracking active users. 51 - * Controls visibility of the namespace in the namespace trees. 52 - * Any live task that uses the namespace (via nsproxy or cred) holds 53 - * an active reference. Any open file descriptor or bind-mount of 54 - * the namespace holds an active reference. Once all tasks have 55 - * called exited their namespaces and all file descriptors and 56 - * bind-mounts have been released the active reference count drops 57 - * to zero and the namespace becomes inactive. IOW, the namespace 58 - * cannot be listed or opened via file handles anymore. 59 - * 60 - * Note that it is valid to transition from active to inactive and 61 - * back from inactive to active e.g., when resurrecting an inactive 62 - * namespace tree via the SIOCGSKNS ioctl(). 63 - * 64 - * Relationship and lifecycle states: 65 - * 66 - * - Active (__ns_ref_active > 0): 67 - * Namespace is actively used and visible to userspace. The namespace 68 - * can be reopened via /proc/<pid>/ns/<ns_type>, via namespace file 69 - * handles, or discovered via listns(). 70 - * 71 - * - Inactive (__ns_ref_active == 0, __ns_ref > 0): 72 - * No tasks are actively using the namespace and it isn't pinned by 73 - * any bind-mounts or open file descriptors anymore. But the namespace 74 - * is still kept alive by internal references. For example, the user 75 - * namespace could be pinned by an open file through file->f_cred 76 - * references when one of the now defunct tasks had opened a file and 77 - * handed the file descriptor off to another process via a UNIX 78 - * sockets. Such references keep the namespace structure alive through 79 - * __ns_ref but will not hold an active reference. 80 - * 81 - * - Destroyed (__ns_ref == 0): 82 - * No references remain. The namespace is removed from the tree and freed. 83 - * 84 - * State transitions: 85 - * 86 - * Active -> Inactive: 87 - * When the last task using the namespace exits it drops its active 88 - * references to all namespaces. However, user and pid namespaces 89 - * remain accessible until the task has been reaped. 90 - * 91 - * Inactive -> Active: 92 - * An inactive namespace tree might be resurrected due to e.g., the 93 - * SIOCGSKNS ioctl() on a socket. 94 - * 95 - * Inactive -> Destroyed: 96 - * When __ns_ref drops to zero the namespace is removed from the 97 - * namespaces trees and the memory is freed (after RCU grace period). 98 - * 99 - * Initial namespaces: 100 - * Boot-time namespaces (init_net, init_pid_ns, etc.) start with 101 - * __ns_ref_active = 1 and remain active forever. 102 - */ 103 - struct ns_common { 104 - u32 ns_type; 105 - struct dentry *stashed; 106 - const struct proc_ns_operations *ops; 107 - unsigned int inum; 108 - refcount_t __ns_ref; /* do not use directly */ 109 - union { 110 - struct { 111 - u64 ns_id; 112 - struct /* global namespace rbtree and list */ { 113 - struct rb_node ns_unified_tree_node; 114 - struct list_head ns_unified_list_node; 115 - }; 116 - struct /* per type rbtree and list */ { 117 - struct rb_node ns_tree_node; 118 - struct list_head ns_list_node; 119 - }; 120 - struct /* namespace ownership rbtree and list */ { 121 - struct rb_root ns_owner_tree; /* rbtree of namespaces owned by this namespace */ 122 - struct list_head ns_owner; /* list of namespaces owned by this namespace */ 123 - struct rb_node ns_owner_tree_node; /* node in the owner namespace's rbtree */ 124 - struct list_head ns_owner_entry; /* node in the owner namespace's ns_owned list */ 125 - }; 126 - atomic_t __ns_ref_active; /* do not use directly */ 127 - }; 128 - struct rcu_head ns_rcu; 129 - }; 130 - }; 131 10 132 11 bool is_current_namespace(struct ns_common *ns); 133 12 int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum); 134 13 void __ns_common_free(struct ns_common *ns); 135 14 struct ns_common *__must_check ns_owner(struct ns_common *ns); 136 15 137 - static __always_inline bool is_initial_namespace(struct ns_common *ns) 16 + static __always_inline bool is_ns_init_inum(const struct ns_common *ns) 138 17 { 139 18 VFS_WARN_ON_ONCE(ns->inum == 0); 140 19 return unlikely(in_range(ns->inum, MNT_NS_INIT_INO, ··· 26 147 return ns->ns_id <= NS_LAST_INIT_ID; 27 148 } 28 149 29 - #define to_ns_common(__ns) \ 30 - _Generic((__ns), \ 31 - struct cgroup_namespace *: &(__ns)->ns, \ 32 - const struct cgroup_namespace *: &(__ns)->ns, \ 33 - struct ipc_namespace *: &(__ns)->ns, \ 34 - const struct ipc_namespace *: &(__ns)->ns, \ 35 - struct mnt_namespace *: &(__ns)->ns, \ 36 - const struct mnt_namespace *: &(__ns)->ns, \ 37 - struct net *: &(__ns)->ns, \ 38 - const struct net *: &(__ns)->ns, \ 39 - struct pid_namespace *: &(__ns)->ns, \ 40 - const struct pid_namespace *: &(__ns)->ns, \ 41 - struct time_namespace *: &(__ns)->ns, \ 42 - const struct time_namespace *: &(__ns)->ns, \ 43 - struct user_namespace *: &(__ns)->ns, \ 44 - const struct user_namespace *: &(__ns)->ns, \ 45 - struct uts_namespace *: &(__ns)->ns, \ 46 - const struct uts_namespace *: &(__ns)->ns) 47 - 48 - #define ns_init_inum(__ns) \ 49 - _Generic((__ns), \ 50 - struct cgroup_namespace *: CGROUP_NS_INIT_INO, \ 51 - struct ipc_namespace *: IPC_NS_INIT_INO, \ 52 - struct mnt_namespace *: MNT_NS_INIT_INO, \ 53 - struct net *: NET_NS_INIT_INO, \ 54 - struct pid_namespace *: PID_NS_INIT_INO, \ 55 - struct time_namespace *: TIME_NS_INIT_INO, \ 56 - struct user_namespace *: USER_NS_INIT_INO, \ 57 - struct uts_namespace *: UTS_NS_INIT_INO) 58 - 59 - #define ns_init_ns(__ns) \ 60 - _Generic((__ns), \ 61 - struct cgroup_namespace *: &init_cgroup_ns, \ 62 - struct ipc_namespace *: &init_ipc_ns, \ 63 - struct mnt_namespace *: &init_mnt_ns, \ 64 - struct net *: &init_net, \ 65 - struct pid_namespace *: &init_pid_ns, \ 66 - struct time_namespace *: &init_time_ns, \ 67 - struct user_namespace *: &init_user_ns, \ 68 - struct uts_namespace *: &init_uts_ns) 69 - 70 - #define ns_init_id(__ns) \ 71 - _Generic((__ns), \ 72 - struct cgroup_namespace *: CGROUP_NS_INIT_ID, \ 73 - struct ipc_namespace *: IPC_NS_INIT_ID, \ 74 - struct mnt_namespace *: MNT_NS_INIT_ID, \ 75 - struct net *: NET_NS_INIT_ID, \ 76 - struct pid_namespace *: PID_NS_INIT_ID, \ 77 - struct time_namespace *: TIME_NS_INIT_ID, \ 78 - struct user_namespace *: USER_NS_INIT_ID, \ 79 - struct uts_namespace *: UTS_NS_INIT_ID) 80 - 81 - #define to_ns_operations(__ns) \ 82 - _Generic((__ns), \ 83 - struct cgroup_namespace *: (IS_ENABLED(CONFIG_CGROUPS) ? &cgroupns_operations : NULL), \ 84 - struct ipc_namespace *: (IS_ENABLED(CONFIG_IPC_NS) ? &ipcns_operations : NULL), \ 85 - struct mnt_namespace *: &mntns_operations, \ 86 - struct net *: (IS_ENABLED(CONFIG_NET_NS) ? &netns_operations : NULL), \ 87 - struct pid_namespace *: (IS_ENABLED(CONFIG_PID_NS) ? &pidns_operations : NULL), \ 88 - struct time_namespace *: (IS_ENABLED(CONFIG_TIME_NS) ? &timens_operations : NULL), \ 89 - struct user_namespace *: (IS_ENABLED(CONFIG_USER_NS) ? &userns_operations : NULL), \ 90 - struct uts_namespace *: (IS_ENABLED(CONFIG_UTS_NS) ? &utsns_operations : NULL)) 91 - 92 - #define ns_common_type(__ns) \ 93 - _Generic((__ns), \ 94 - struct cgroup_namespace *: CLONE_NEWCGROUP, \ 95 - struct ipc_namespace *: CLONE_NEWIPC, \ 96 - struct mnt_namespace *: CLONE_NEWNS, \ 97 - struct net *: CLONE_NEWNET, \ 98 - struct pid_namespace *: CLONE_NEWPID, \ 99 - struct time_namespace *: CLONE_NEWTIME, \ 100 - struct user_namespace *: CLONE_NEWUSER, \ 101 - struct uts_namespace *: CLONE_NEWUTS) 102 - 103 - #define NS_COMMON_INIT(nsname, refs) \ 104 - { \ 105 - .ns_type = ns_common_type(&nsname), \ 106 - .ns_id = ns_init_id(&nsname), \ 107 - .inum = ns_init_inum(&nsname), \ 108 - .ops = to_ns_operations(&nsname), \ 109 - .stashed = NULL, \ 110 - .__ns_ref = REFCOUNT_INIT(refs), \ 111 - .__ns_ref_active = ATOMIC_INIT(1), \ 112 - .ns_list_node = LIST_HEAD_INIT(nsname.ns.ns_list_node), \ 113 - .ns_owner_entry = LIST_HEAD_INIT(nsname.ns.ns_owner_entry), \ 114 - .ns_owner = LIST_HEAD_INIT(nsname.ns.ns_owner), \ 115 - .ns_unified_list_node = LIST_HEAD_INIT(nsname.ns.ns_unified_list_node), \ 150 + #define NS_COMMON_INIT(nsname) \ 151 + { \ 152 + .ns_type = ns_common_type(&nsname), \ 153 + .ns_id = ns_init_id(&nsname), \ 154 + .inum = ns_init_inum(&nsname), \ 155 + .ops = to_ns_operations(&nsname), \ 156 + .stashed = NULL, \ 157 + .__ns_ref = REFCOUNT_INIT(1), \ 158 + .__ns_ref_active = ATOMIC_INIT(1), \ 159 + .ns_unified_node.ns_list_entry = LIST_HEAD_INIT(nsname.ns.ns_unified_node.ns_list_entry), \ 160 + .ns_tree_node.ns_list_entry = LIST_HEAD_INIT(nsname.ns.ns_tree_node.ns_list_entry), \ 161 + .ns_owner_node.ns_list_entry = LIST_HEAD_INIT(nsname.ns.ns_owner_node.ns_list_entry), \ 162 + .ns_owner_root.ns_list_head = LIST_HEAD_INIT(nsname.ns.ns_owner_root.ns_list_head), \ 116 163 } 117 164 118 165 #define ns_common_init(__ns) \ ··· 60 255 return atomic_read(&ns->__ns_ref_active); 61 256 } 62 257 258 + static __always_inline __must_check int __ns_ref_read(const struct ns_common *ns) 259 + { 260 + return refcount_read(&ns->__ns_ref); 261 + } 262 + 63 263 static __always_inline __must_check bool __ns_ref_put(struct ns_common *ns) 64 264 { 265 + if (is_ns_init_id(ns)) { 266 + VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1); 267 + VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1); 268 + return false; 269 + } 65 270 if (refcount_dec_and_test(&ns->__ns_ref)) { 66 271 VFS_WARN_ON_ONCE(__ns_ref_active_read(ns)); 67 272 return true; ··· 81 266 82 267 static __always_inline __must_check bool __ns_ref_get(struct ns_common *ns) 83 268 { 269 + if (is_ns_init_id(ns)) { 270 + VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1); 271 + VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1); 272 + return true; 273 + } 84 274 if (refcount_inc_not_zero(&ns->__ns_ref)) 85 275 return true; 86 276 VFS_WARN_ON_ONCE(__ns_ref_active_read(ns)); 87 277 return false; 88 278 } 89 279 90 - static __always_inline __must_check int __ns_ref_read(const struct ns_common *ns) 280 + static __always_inline void __ns_ref_inc(struct ns_common *ns) 91 281 { 92 - return refcount_read(&ns->__ns_ref); 282 + if (is_ns_init_id(ns)) { 283 + VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1); 284 + VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1); 285 + return; 286 + } 287 + refcount_inc(&ns->__ns_ref); 288 + } 289 + 290 + static __always_inline __must_check bool __ns_ref_dec_and_lock(struct ns_common *ns, 291 + spinlock_t *ns_lock) 292 + { 293 + if (is_ns_init_id(ns)) { 294 + VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1); 295 + VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1); 296 + return false; 297 + } 298 + return refcount_dec_and_lock(&ns->__ns_ref, ns_lock); 93 299 } 94 300 95 301 #define ns_ref_read(__ns) __ns_ref_read(to_ns_common((__ns))) 96 - #define ns_ref_inc(__ns) refcount_inc(&to_ns_common((__ns))->__ns_ref) 302 + #define ns_ref_inc(__ns) __ns_ref_inc(to_ns_common((__ns))) 97 303 #define ns_ref_get(__ns) __ns_ref_get(to_ns_common((__ns))) 98 304 #define ns_ref_put(__ns) __ns_ref_put(to_ns_common((__ns))) 99 - #define ns_ref_put_and_lock(__ns, __lock) \ 100 - refcount_dec_and_lock(&to_ns_common((__ns))->__ns_ref, (__lock)) 305 + #define ns_ref_put_and_lock(__ns, __ns_lock) \ 306 + __ns_ref_dec_and_lock(to_ns_common((__ns)), __ns_lock) 101 307 102 308 #define ns_ref_active_read(__ns) \ 103 309 ((__ns) ? __ns_ref_active_read(to_ns_common(__ns)) : 0)
+24 -14
include/linux/nstree.h
··· 3 3 #ifndef _LINUX_NSTREE_H 4 4 #define _LINUX_NSTREE_H 5 5 6 - #include <linux/ns_common.h> 6 + #include <linux/ns/nstree_types.h> 7 7 #include <linux/nsproxy.h> 8 8 #include <linux/rbtree.h> 9 9 #include <linux/seqlock.h> ··· 11 11 #include <linux/cookie.h> 12 12 #include <uapi/linux/nsfs.h> 13 13 14 - extern struct ns_tree cgroup_ns_tree; 15 - extern struct ns_tree ipc_ns_tree; 16 - extern struct ns_tree mnt_ns_tree; 17 - extern struct ns_tree net_ns_tree; 18 - extern struct ns_tree pid_ns_tree; 19 - extern struct ns_tree time_ns_tree; 20 - extern struct ns_tree user_ns_tree; 21 - extern struct ns_tree uts_ns_tree; 14 + struct ns_common; 15 + 16 + extern struct ns_tree_root cgroup_ns_tree; 17 + extern struct ns_tree_root ipc_ns_tree; 18 + extern struct ns_tree_root mnt_ns_tree; 19 + extern struct ns_tree_root net_ns_tree; 20 + extern struct ns_tree_root pid_ns_tree; 21 + extern struct ns_tree_root time_ns_tree; 22 + extern struct ns_tree_root user_ns_tree; 23 + extern struct ns_tree_root uts_ns_tree; 24 + 25 + void ns_tree_node_init(struct ns_tree_node *node); 26 + void ns_tree_root_init(struct ns_tree_root *root); 27 + bool ns_tree_node_empty(const struct ns_tree_node *node); 28 + struct rb_node *ns_tree_node_add(struct ns_tree_node *node, 29 + struct ns_tree_root *root, 30 + int (*cmp)(struct rb_node *, const struct rb_node *)); 31 + void ns_tree_node_del(struct ns_tree_node *node, struct ns_tree_root *root); 22 32 23 33 #define to_ns_tree(__ns) \ 24 34 _Generic((__ns), \ ··· 46 36 (((__ns) == ns_init_ns(__ns)) ? ns_init_id(__ns) : 0)) 47 37 48 38 u64 __ns_tree_gen_id(struct ns_common *ns, u64 id); 49 - void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree *ns_tree); 50 - void __ns_tree_remove(struct ns_common *ns, struct ns_tree *ns_tree); 39 + void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree_root *ns_tree); 40 + void __ns_tree_remove(struct ns_common *ns, struct ns_tree_root *ns_tree); 51 41 struct ns_common *ns_tree_lookup_rcu(u64 ns_id, int ns_type); 52 42 struct ns_common *__ns_tree_adjoined_rcu(struct ns_common *ns, 53 - struct ns_tree *ns_tree, 43 + struct ns_tree_root *ns_tree, 54 44 bool previous); 55 45 56 - static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree *ns_tree, u64 id) 46 + static inline void __ns_tree_add(struct ns_common *ns, struct ns_tree_root *ns_tree, u64 id) 57 47 { 58 48 __ns_tree_gen_id(ns, id); 59 49 __ns_tree_add_raw(ns, ns_tree); ··· 91 81 #define ns_tree_adjoined_rcu(__ns, __previous) \ 92 82 __ns_tree_adjoined_rcu(to_ns_common(__ns), to_ns_tree(__ns), __previous) 93 83 94 - #define ns_tree_active(__ns) (!RB_EMPTY_NODE(&to_ns_common(__ns)->ns_tree_node)) 84 + #define ns_tree_active(__ns) (!RB_EMPTY_NODE(&to_ns_common(__ns)->ns_tree_node.ns_node)) 95 85 96 86 #endif /* _LINUX_NSTREE_H */
+1 -2
include/linux/pid_namespace.h
··· 61 61 62 62 static inline struct pid_namespace *get_pid_ns(struct pid_namespace *ns) 63 63 { 64 - if (ns != &init_pid_ns) 65 - ns_ref_inc(ns); 64 + ns_ref_inc(ns); 66 65 return ns; 67 66 } 68 67
+1 -1
init/version-timestamp.c
··· 8 8 #include <linux/utsname.h> 9 9 10 10 struct uts_namespace init_uts_ns = { 11 - .ns = NS_COMMON_INIT(init_uts_ns, 2), 11 + .ns = NS_COMMON_INIT(init_uts_ns), 12 12 .name = { 13 13 .sysname = UTS_SYSNAME, 14 14 .nodename = UTS_NODENAME,
+1 -1
ipc/msgutil.c
··· 27 27 * and not CONFIG_IPC_NS. 28 28 */ 29 29 struct ipc_namespace init_ipc_ns = { 30 - .ns = NS_COMMON_INIT(init_ipc_ns, 1), 30 + .ns = NS_COMMON_INIT(init_ipc_ns), 31 31 .user_ns = &init_user_ns, 32 32 }; 33 33
+2 -1
ipc/namespace.c
··· 66 66 if (err) 67 67 goto fail_free; 68 68 69 + ns_tree_gen_id(ns); 69 70 ns->user_ns = get_user_ns(user_ns); 70 71 ns->ucounts = ucounts; 71 72 ··· 87 86 88 87 sem_init_ns(ns); 89 88 shm_init_ns(ns); 90 - ns_tree_add(ns); 89 + ns_tree_add_raw(ns); 91 90 92 91 return ns; 93 92
+1 -1
kernel/cgroup/cgroup.c
··· 250 250 251 251 /* cgroup namespace for init task */ 252 252 struct cgroup_namespace init_cgroup_ns = { 253 - .ns = NS_COMMON_INIT(init_cgroup_ns, 2), 253 + .ns = NS_COMMON_INIT(init_cgroup_ns), 254 254 .user_ns = &init_user_ns, 255 255 .root_cset = &init_css_set, 256 256 };
+6 -9
kernel/nscommon.c
··· 2 2 /* Copyright (c) 2025 Christian Brauner <brauner@kernel.org> */ 3 3 4 4 #include <linux/ns_common.h> 5 + #include <linux/nstree.h> 5 6 #include <linux/proc_ns.h> 6 7 #include <linux/user_namespace.h> 7 8 #include <linux/vfsdebug.h> ··· 62 61 ns->ops = ops; 63 62 ns->ns_id = 0; 64 63 ns->ns_type = ns_type; 65 - RB_CLEAR_NODE(&ns->ns_tree_node); 66 - RB_CLEAR_NODE(&ns->ns_unified_tree_node); 67 - RB_CLEAR_NODE(&ns->ns_owner_tree_node); 68 - INIT_LIST_HEAD(&ns->ns_list_node); 69 - INIT_LIST_HEAD(&ns->ns_unified_list_node); 70 - ns->ns_owner_tree = RB_ROOT; 71 - INIT_LIST_HEAD(&ns->ns_owner); 72 - INIT_LIST_HEAD(&ns->ns_owner_entry); 64 + ns_tree_node_init(&ns->ns_tree_node); 65 + ns_tree_node_init(&ns->ns_unified_node); 66 + ns_tree_node_init(&ns->ns_owner_node); 67 + ns_tree_root_init(&ns->ns_owner_root); 73 68 74 69 #ifdef CONFIG_DEBUG_VFS 75 70 ns_debug(ns, ops); ··· 82 85 * active use (installed in nsproxy) and decremented when all 83 86 * active uses are gone. Initial namespaces are always active. 84 87 */ 85 - if (is_initial_namespace(ns)) 88 + if (is_ns_init_inum(ns)) 86 89 atomic_set(&ns->__ns_ref_active, 1); 87 90 else 88 91 atomic_set(&ns->__ns_ref_active, 0);
+176 -128
kernel/nstree.c
··· 9 9 #include <linux/user_namespace.h> 10 10 11 11 static __cacheline_aligned_in_smp DEFINE_SEQLOCK(ns_tree_lock); 12 - static struct rb_root ns_unified_tree = RB_ROOT; /* protected by ns_tree_lock */ 13 - static LIST_HEAD(ns_unified_list); /* protected by ns_tree_lock */ 14 12 15 - /** 16 - * struct ns_tree - Namespace tree 17 - * @ns_tree: Rbtree of namespaces of a particular type 18 - * @ns_list: Sequentially walkable list of all namespaces of this type 19 - * @type: type of namespaces in this tree 20 - */ 21 - struct ns_tree { 22 - struct rb_root ns_tree; 23 - struct list_head ns_list; 24 - int type; 13 + DEFINE_LOCK_GUARD_0(ns_tree_writer, 14 + write_seqlock(&ns_tree_lock), 15 + write_sequnlock(&ns_tree_lock)) 16 + 17 + DEFINE_LOCK_GUARD_0(ns_tree_locked_reader, 18 + read_seqlock_excl(&ns_tree_lock), 19 + read_sequnlock_excl(&ns_tree_lock)) 20 + 21 + static struct ns_tree_root ns_unified_root = { /* protected by ns_tree_lock */ 22 + .ns_rb = RB_ROOT, 23 + .ns_list_head = LIST_HEAD_INIT(ns_unified_root.ns_list_head), 25 24 }; 26 25 27 - struct ns_tree mnt_ns_tree = { 28 - .ns_tree = RB_ROOT, 29 - .ns_list = LIST_HEAD_INIT(mnt_ns_tree.ns_list), 30 - .type = CLONE_NEWNS, 26 + struct ns_tree_root mnt_ns_tree = { 27 + .ns_rb = RB_ROOT, 28 + .ns_list_head = LIST_HEAD_INIT(mnt_ns_tree.ns_list_head), 31 29 }; 32 30 33 - struct ns_tree net_ns_tree = { 34 - .ns_tree = RB_ROOT, 35 - .ns_list = LIST_HEAD_INIT(net_ns_tree.ns_list), 36 - .type = CLONE_NEWNET, 31 + struct ns_tree_root net_ns_tree = { 32 + .ns_rb = RB_ROOT, 33 + .ns_list_head = LIST_HEAD_INIT(net_ns_tree.ns_list_head), 37 34 }; 38 35 EXPORT_SYMBOL_GPL(net_ns_tree); 39 36 40 - struct ns_tree uts_ns_tree = { 41 - .ns_tree = RB_ROOT, 42 - .ns_list = LIST_HEAD_INIT(uts_ns_tree.ns_list), 43 - .type = CLONE_NEWUTS, 37 + struct ns_tree_root uts_ns_tree = { 38 + .ns_rb = RB_ROOT, 39 + .ns_list_head = LIST_HEAD_INIT(uts_ns_tree.ns_list_head), 44 40 }; 45 41 46 - struct ns_tree user_ns_tree = { 47 - .ns_tree = RB_ROOT, 48 - .ns_list = LIST_HEAD_INIT(user_ns_tree.ns_list), 49 - .type = CLONE_NEWUSER, 42 + struct ns_tree_root user_ns_tree = { 43 + .ns_rb = RB_ROOT, 44 + .ns_list_head = LIST_HEAD_INIT(user_ns_tree.ns_list_head), 50 45 }; 51 46 52 - struct ns_tree ipc_ns_tree = { 53 - .ns_tree = RB_ROOT, 54 - .ns_list = LIST_HEAD_INIT(ipc_ns_tree.ns_list), 55 - .type = CLONE_NEWIPC, 47 + struct ns_tree_root ipc_ns_tree = { 48 + .ns_rb = RB_ROOT, 49 + .ns_list_head = LIST_HEAD_INIT(ipc_ns_tree.ns_list_head), 56 50 }; 57 51 58 - struct ns_tree pid_ns_tree = { 59 - .ns_tree = RB_ROOT, 60 - .ns_list = LIST_HEAD_INIT(pid_ns_tree.ns_list), 61 - .type = CLONE_NEWPID, 52 + struct ns_tree_root pid_ns_tree = { 53 + .ns_rb = RB_ROOT, 54 + .ns_list_head = LIST_HEAD_INIT(pid_ns_tree.ns_list_head), 62 55 }; 63 56 64 - struct ns_tree cgroup_ns_tree = { 65 - .ns_tree = RB_ROOT, 66 - .ns_list = LIST_HEAD_INIT(cgroup_ns_tree.ns_list), 67 - .type = CLONE_NEWCGROUP, 57 + struct ns_tree_root cgroup_ns_tree = { 58 + .ns_rb = RB_ROOT, 59 + .ns_list_head = LIST_HEAD_INIT(cgroup_ns_tree.ns_list_head), 68 60 }; 69 61 70 - struct ns_tree time_ns_tree = { 71 - .ns_tree = RB_ROOT, 72 - .ns_list = LIST_HEAD_INIT(time_ns_tree.ns_list), 73 - .type = CLONE_NEWTIME, 62 + struct ns_tree_root time_ns_tree = { 63 + .ns_rb = RB_ROOT, 64 + .ns_list_head = LIST_HEAD_INIT(time_ns_tree.ns_list_head), 74 65 }; 66 + 67 + /** 68 + * ns_tree_node_init - Initialize a namespace tree node 69 + * @node: The node to initialize 70 + * 71 + * Initializes both the rbtree node and list entry. 72 + */ 73 + void ns_tree_node_init(struct ns_tree_node *node) 74 + { 75 + RB_CLEAR_NODE(&node->ns_node); 76 + INIT_LIST_HEAD(&node->ns_list_entry); 77 + } 78 + 79 + /** 80 + * ns_tree_root_init - Initialize a namespace tree root 81 + * @root: The root to initialize 82 + * 83 + * Initializes both the rbtree root and list head. 84 + */ 85 + void ns_tree_root_init(struct ns_tree_root *root) 86 + { 87 + root->ns_rb = RB_ROOT; 88 + INIT_LIST_HEAD(&root->ns_list_head); 89 + } 90 + 91 + /** 92 + * ns_tree_node_empty - Check if a namespace tree node is empty 93 + * @node: The node to check 94 + * 95 + * Returns true if the node is not in any tree. 96 + */ 97 + bool ns_tree_node_empty(const struct ns_tree_node *node) 98 + { 99 + return RB_EMPTY_NODE(&node->ns_node); 100 + } 101 + 102 + /** 103 + * ns_tree_node_add - Add a node to a namespace tree 104 + * @node: The node to add 105 + * @root: The tree root to add to 106 + * @cmp: Comparison function for rbtree insertion 107 + * 108 + * Adds the node to both the rbtree and the list, maintaining sorted order. 109 + * The list is maintained in the same order as the rbtree to enable efficient 110 + * iteration. 111 + * 112 + * Returns: NULL if insertion succeeded, existing node if duplicate found 113 + */ 114 + struct rb_node *ns_tree_node_add(struct ns_tree_node *node, 115 + struct ns_tree_root *root, 116 + int (*cmp)(struct rb_node *, const struct rb_node *)) 117 + { 118 + struct rb_node *ret, *prev; 119 + 120 + /* Add to rbtree */ 121 + ret = rb_find_add_rcu(&node->ns_node, &root->ns_rb, cmp); 122 + 123 + /* Add to list in sorted order */ 124 + prev = rb_prev(&node->ns_node); 125 + if (!prev) { 126 + /* No previous node, add at head */ 127 + list_add_rcu(&node->ns_list_entry, &root->ns_list_head); 128 + } else { 129 + /* Add after previous node */ 130 + struct ns_tree_node *prev_node; 131 + prev_node = rb_entry(prev, struct ns_tree_node, ns_node); 132 + list_add_rcu(&node->ns_list_entry, &prev_node->ns_list_entry); 133 + } 134 + 135 + return ret; 136 + } 137 + 138 + /** 139 + * ns_tree_node_del - Remove a node from a namespace tree 140 + * @node: The node to remove 141 + * @root: The tree root to remove from 142 + * 143 + * Removes the node from both the rbtree and the list atomically. 144 + */ 145 + void ns_tree_node_del(struct ns_tree_node *node, struct ns_tree_root *root) 146 + { 147 + rb_erase(&node->ns_node, &root->ns_rb); 148 + RB_CLEAR_NODE(&node->ns_node); 149 + list_bidir_del_rcu(&node->ns_list_entry); 150 + } 75 151 76 152 static inline struct ns_common *node_to_ns(const struct rb_node *node) 77 153 { 78 154 if (!node) 79 155 return NULL; 80 - return rb_entry(node, struct ns_common, ns_tree_node); 156 + return rb_entry(node, struct ns_common, ns_tree_node.ns_node); 81 157 } 82 158 83 159 static inline struct ns_common *node_to_ns_unified(const struct rb_node *node) 84 160 { 85 161 if (!node) 86 162 return NULL; 87 - return rb_entry(node, struct ns_common, ns_unified_tree_node); 163 + return rb_entry(node, struct ns_common, ns_unified_node.ns_node); 88 164 } 89 165 90 166 static inline struct ns_common *node_to_ns_owner(const struct rb_node *node) 91 167 { 92 168 if (!node) 93 169 return NULL; 94 - return rb_entry(node, struct ns_common, ns_owner_tree_node); 170 + return rb_entry(node, struct ns_common, ns_owner_node.ns_node); 95 171 } 96 172 97 173 static int ns_id_cmp(u64 id_a, u64 id_b) ··· 194 118 return ns_id_cmp(node_to_ns_owner(a)->ns_id, node_to_ns_owner(b)->ns_id); 195 119 } 196 120 197 - void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree *ns_tree) 121 + void __ns_tree_add_raw(struct ns_common *ns, struct ns_tree_root *ns_tree) 198 122 { 199 - struct rb_node *node, *prev; 123 + struct rb_node *node; 200 124 const struct proc_ns_operations *ops = ns->ops; 201 125 202 126 VFS_WARN_ON_ONCE(!ns->ns_id); 203 - VFS_WARN_ON_ONCE(ns->ns_type != ns_tree->type); 204 127 205 - write_seqlock(&ns_tree_lock); 128 + guard(ns_tree_writer)(); 206 129 207 - node = rb_find_add_rcu(&ns->ns_tree_node, &ns_tree->ns_tree, ns_cmp); 208 - /* 209 - * If there's no previous entry simply add it after the 210 - * head and if there is add it after the previous entry. 211 - */ 212 - prev = rb_prev(&ns->ns_tree_node); 213 - if (!prev) 214 - list_add_rcu(&ns->ns_list_node, &ns_tree->ns_list); 215 - else 216 - list_add_rcu(&ns->ns_list_node, &node_to_ns(prev)->ns_list_node); 130 + /* Add to per-type tree and list */ 131 + node = ns_tree_node_add(&ns->ns_tree_node, ns_tree, ns_cmp); 217 132 218 133 /* Add to unified tree and list */ 219 - rb_find_add_rcu(&ns->ns_unified_tree_node, &ns_unified_tree, ns_cmp_unified); 220 - prev = rb_prev(&ns->ns_unified_tree_node); 221 - if (!prev) 222 - list_add_rcu(&ns->ns_unified_list_node, &ns_unified_list); 223 - else 224 - list_add_rcu(&ns->ns_unified_list_node, &node_to_ns_unified(prev)->ns_unified_list_node); 134 + ns_tree_node_add(&ns->ns_unified_node, &ns_unified_root, ns_cmp_unified); 225 135 136 + /* Add to owner's tree if applicable */ 226 137 if (ops) { 227 138 struct user_namespace *user_ns; 228 139 ··· 219 156 struct ns_common *owner = &user_ns->ns; 220 157 VFS_WARN_ON_ONCE(owner->ns_type != CLONE_NEWUSER); 221 158 222 - /* Insert into owner's rbtree */ 223 - rb_find_add_rcu(&ns->ns_owner_tree_node, &owner->ns_owner_tree, ns_cmp_owner); 224 - 225 - /* Insert into owner's list in sorted order */ 226 - prev = rb_prev(&ns->ns_owner_tree_node); 227 - if (!prev) 228 - list_add_rcu(&ns->ns_owner_entry, &owner->ns_owner); 229 - else 230 - list_add_rcu(&ns->ns_owner_entry, &node_to_ns_owner(prev)->ns_owner_entry); 159 + /* Insert into owner's tree and list */ 160 + ns_tree_node_add(&ns->ns_owner_node, &owner->ns_owner_root, ns_cmp_owner); 231 161 } else { 232 162 /* Only the initial user namespace doesn't have an owner. */ 233 163 VFS_WARN_ON_ONCE(ns != to_ns_common(&init_user_ns)); 234 164 } 235 165 } 236 - write_sequnlock(&ns_tree_lock); 237 166 238 167 VFS_WARN_ON_ONCE(node); 239 168 } 240 169 241 - void __ns_tree_remove(struct ns_common *ns, struct ns_tree *ns_tree) 170 + void __ns_tree_remove(struct ns_common *ns, struct ns_tree_root *ns_tree) 242 171 { 243 172 const struct proc_ns_operations *ops = ns->ops; 244 173 struct user_namespace *user_ns; 245 174 246 - VFS_WARN_ON_ONCE(RB_EMPTY_NODE(&ns->ns_tree_node)); 247 - VFS_WARN_ON_ONCE(list_empty(&ns->ns_list_node)); 248 - VFS_WARN_ON_ONCE(ns->ns_type != ns_tree->type); 175 + VFS_WARN_ON_ONCE(ns_tree_node_empty(&ns->ns_tree_node)); 176 + VFS_WARN_ON_ONCE(list_empty(&ns->ns_tree_node.ns_list_entry)); 249 177 250 178 write_seqlock(&ns_tree_lock); 251 - rb_erase(&ns->ns_tree_node, &ns_tree->ns_tree); 252 - RB_CLEAR_NODE(&ns->ns_tree_node); 253 179 254 - list_bidir_del_rcu(&ns->ns_list_node); 180 + /* Remove from per-type tree and list */ 181 + ns_tree_node_del(&ns->ns_tree_node, ns_tree); 255 182 256 - rb_erase(&ns->ns_unified_tree_node, &ns_unified_tree); 257 - RB_CLEAR_NODE(&ns->ns_unified_tree_node); 183 + /* Remove from unified tree and list */ 184 + ns_tree_node_del(&ns->ns_unified_node, &ns_unified_root); 258 185 259 - list_bidir_del_rcu(&ns->ns_unified_list_node); 260 - 261 - /* Remove from owner's rbtree if this namespace has an owner */ 186 + /* Remove from owner's tree if applicable */ 262 187 if (ops) { 263 188 user_ns = ops->owner(ns); 264 189 if (user_ns) { 265 190 struct ns_common *owner = &user_ns->ns; 266 - rb_erase(&ns->ns_owner_tree_node, &owner->ns_owner_tree); 267 - RB_CLEAR_NODE(&ns->ns_owner_tree_node); 191 + ns_tree_node_del(&ns->ns_owner_node, &owner->ns_owner_root); 268 192 } 269 - 270 - list_bidir_del_rcu(&ns->ns_owner_entry); 271 193 } 272 194 273 195 write_sequnlock(&ns_tree_lock); ··· 283 235 return 0; 284 236 } 285 237 286 - static struct ns_tree *ns_tree_from_type(int ns_type) 238 + static struct ns_tree_root *ns_tree_from_type(int ns_type) 287 239 { 288 240 switch (ns_type) { 289 241 case CLONE_NEWCGROUP: ··· 314 266 315 267 do { 316 268 seq = read_seqbegin(&ns_tree_lock); 317 - node = rb_find_rcu(&ns_id, &ns_unified_tree, ns_find_unified); 269 + node = rb_find_rcu(&ns_id, &ns_unified_root.ns_rb, ns_find_unified); 318 270 if (node) 319 271 break; 320 272 } while (read_seqretry(&ns_tree_lock, seq)); ··· 324 276 325 277 static struct ns_common *__ns_tree_lookup_rcu(u64 ns_id, int ns_type) 326 278 { 327 - struct ns_tree *ns_tree; 279 + struct ns_tree_root *ns_tree; 328 280 struct rb_node *node; 329 281 unsigned int seq; 330 282 ··· 334 286 335 287 do { 336 288 seq = read_seqbegin(&ns_tree_lock); 337 - node = rb_find_rcu(&ns_id, &ns_tree->ns_tree, ns_find); 289 + node = rb_find_rcu(&ns_id, &ns_tree->ns_rb, ns_find); 338 290 if (node) 339 291 break; 340 292 } while (read_seqretry(&ns_tree_lock, seq)); ··· 362 314 * there is no next/previous namespace, -ENOENT is returned. 363 315 */ 364 316 struct ns_common *__ns_tree_adjoined_rcu(struct ns_common *ns, 365 - struct ns_tree *ns_tree, bool previous) 317 + struct ns_tree_root *ns_tree, bool previous) 366 318 { 367 319 struct list_head *list; 368 320 369 321 RCU_LOCKDEP_WARN(!rcu_read_lock_held(), "suspicious ns_tree_adjoined_rcu() usage"); 370 322 371 323 if (previous) 372 - list = rcu_dereference(list_bidir_prev_rcu(&ns->ns_list_node)); 324 + list = rcu_dereference(list_bidir_prev_rcu(&ns->ns_tree_node.ns_list_entry)); 373 325 else 374 - list = rcu_dereference(list_next_rcu(&ns->ns_list_node)); 375 - if (list_is_head(list, &ns_tree->ns_list)) 326 + list = rcu_dereference(list_next_rcu(&ns->ns_tree_node.ns_list_entry)); 327 + if (list_is_head(list, &ns_tree->ns_list_head)) 376 328 return ERR_PTR(-ENOENT); 377 329 378 - VFS_WARN_ON_ONCE(list_entry_rcu(list, struct ns_common, ns_list_node)->ns_type != ns_tree->type); 379 - 380 - return list_entry_rcu(list, struct ns_common, ns_list_node); 330 + return list_entry_rcu(list, struct ns_common, ns_tree_node.ns_list_entry); 381 331 } 382 332 383 333 /** ··· 468 422 469 423 VFS_WARN_ON_ONCE(owner->ns_type != CLONE_NEWUSER); 470 424 471 - read_seqlock_excl(&ns_tree_lock); 472 - node = owner->ns_owner_tree.rb_node; 425 + guard(ns_tree_locked_reader)(); 473 426 427 + node = owner->ns_owner_root.ns_rb.rb_node; 474 428 while (node) { 475 429 struct ns_common *ns; 476 430 ··· 487 441 488 442 if (ret) 489 443 ret = ns_get_unless_inactive(ret); 490 - read_sequnlock_excl(&ns_tree_lock); 491 444 return ret; 492 445 } 493 446 ··· 598 553 } 599 554 600 555 ret = 0; 601 - head = &to_ns_common(kls->user_ns)->ns_owner; 556 + head = &to_ns_common(kls->user_ns)->ns_owner_root.ns_list_head; 602 557 kls->userns_capable = ns_capable_noaudit(kls->user_ns, CAP_SYS_ADMIN); 603 558 604 559 rcu_read_lock(); 605 560 606 561 if (!first_ns) 607 - first_ns = list_entry_rcu(head->next, typeof(*ns), ns_owner_entry); 562 + first_ns = list_entry_rcu(head->next, typeof(*first_ns), ns_owner_node.ns_list_entry); 608 563 609 - for (ns = first_ns; &ns->ns_owner_entry != head && nr_ns_ids; 610 - ns = list_entry_rcu(ns->ns_owner_entry.next, typeof(*ns), ns_owner_entry)) { 564 + ns = first_ns; 565 + list_for_each_entry_from_rcu(ns, head, ns_owner_node.ns_list_entry) { 611 566 struct ns_common *valid; 567 + 568 + if (!nr_ns_ids) 569 + break; 612 570 613 571 valid = legitimize_ns(kls, ns); 614 572 if (!valid) ··· 645 597 static struct ns_common *lookup_ns_id_at(u64 ns_id, int ns_type) 646 598 { 647 599 struct ns_common *ret = NULL; 648 - struct ns_tree *ns_tree = NULL; 600 + struct ns_tree_root *ns_tree = NULL; 649 601 struct rb_node *node; 650 602 651 603 if (ns_type) { ··· 654 606 return NULL; 655 607 } 656 608 657 - read_seqlock_excl(&ns_tree_lock); 609 + guard(ns_tree_locked_reader)(); 610 + 658 611 if (ns_tree) 659 - node = ns_tree->ns_tree.rb_node; 612 + node = ns_tree->ns_rb.rb_node; 660 613 else 661 - node = ns_unified_tree.rb_node; 614 + node = ns_unified_root.ns_rb.rb_node; 662 615 663 616 while (node) { 664 617 struct ns_common *ns; ··· 684 635 685 636 if (ret) 686 637 ret = ns_get_unless_inactive(ret); 687 - read_sequnlock_excl(&ns_tree_lock); 688 638 return ret; 689 639 } 690 640 691 641 static inline struct ns_common *first_ns_common(const struct list_head *head, 692 - struct ns_tree *ns_tree) 642 + struct ns_tree_root *ns_tree) 693 643 { 694 644 if (ns_tree) 695 - return list_entry_rcu(head->next, struct ns_common, ns_list_node); 696 - return list_entry_rcu(head->next, struct ns_common, ns_unified_list_node); 645 + return list_entry_rcu(head->next, struct ns_common, ns_tree_node.ns_list_entry); 646 + return list_entry_rcu(head->next, struct ns_common, ns_unified_node.ns_list_entry); 697 647 } 698 648 699 649 static inline struct ns_common *next_ns_common(struct ns_common *ns, 700 - struct ns_tree *ns_tree) 650 + struct ns_tree_root *ns_tree) 701 651 { 702 652 if (ns_tree) 703 - return list_entry_rcu(ns->ns_list_node.next, struct ns_common, ns_list_node); 704 - return list_entry_rcu(ns->ns_unified_list_node.next, struct ns_common, ns_unified_list_node); 653 + return list_entry_rcu(ns->ns_tree_node.ns_list_entry.next, struct ns_common, ns_tree_node.ns_list_entry); 654 + return list_entry_rcu(ns->ns_unified_node.ns_list_entry.next, struct ns_common, ns_unified_node.ns_list_entry); 705 655 } 706 656 707 657 static inline bool ns_common_is_head(struct ns_common *ns, 708 658 const struct list_head *head, 709 - struct ns_tree *ns_tree) 659 + struct ns_tree_root *ns_tree) 710 660 { 711 661 if (ns_tree) 712 - return &ns->ns_list_node == head; 713 - return &ns->ns_unified_list_node == head; 662 + return &ns->ns_tree_node.ns_list_entry == head; 663 + return &ns->ns_unified_node.ns_list_entry == head; 714 664 } 715 665 716 666 static ssize_t do_listns(struct klistns *kls) ··· 717 669 u64 __user *ns_ids = kls->uns_ids; 718 670 size_t nr_ns_ids = kls->nr_ns_ids; 719 671 struct ns_common *ns, *first_ns = NULL, *prev = NULL; 720 - struct ns_tree *ns_tree = NULL; 672 + struct ns_tree_root *ns_tree = NULL; 721 673 const struct list_head *head; 722 674 u32 ns_type; 723 675 ssize_t ret; ··· 742 694 743 695 ret = 0; 744 696 if (ns_tree) 745 - head = &ns_tree->ns_list; 697 + head = &ns_tree->ns_list_head; 746 698 else 747 - head = &ns_unified_list; 699 + head = &ns_unified_root.ns_list_head; 748 700 749 701 rcu_read_lock(); 750 702
+1 -1
kernel/pid.c
··· 71 71 * the scheme scales to up to 4 million PIDs, runtime. 72 72 */ 73 73 struct pid_namespace init_pid_ns = { 74 - .ns = NS_COMMON_INIT(init_pid_ns, 2), 74 + .ns = NS_COMMON_INIT(init_pid_ns), 75 75 .idr = IDR_INIT(init_pid_ns.idr), 76 76 .pid_allocated = PIDNS_ADDING, 77 77 .level = 0,
+1 -1
kernel/pid_namespace.c
··· 184 184 185 185 void put_pid_ns(struct pid_namespace *ns) 186 186 { 187 - if (ns && ns != &init_pid_ns && ns_ref_put(ns)) 187 + if (ns && ns_ref_put(ns)) 188 188 schedule_work(&ns->work); 189 189 } 190 190 EXPORT_SYMBOL_GPL(put_pid_ns);
+1 -1
kernel/time/namespace.c
··· 478 478 }; 479 479 480 480 struct time_namespace init_time_ns = { 481 - .ns = NS_COMMON_INIT(init_time_ns, 3), 481 + .ns = NS_COMMON_INIT(init_time_ns), 482 482 .user_ns = &init_user_ns, 483 483 .frozen_offsets = true, 484 484 };
+1 -1
kernel/user.c
··· 35 35 * and 1 for... ? 36 36 */ 37 37 struct user_namespace init_user_ns = { 38 - .ns = NS_COMMON_INIT(init_user_ns, 3), 38 + .ns = NS_COMMON_INIT(init_user_ns), 39 39 .uid_map = { 40 40 { 41 41 .extent[0] = {
+51 -56
tools/testing/selftests/namespaces/nsid_test.c
··· 6 6 #include <libgen.h> 7 7 #include <limits.h> 8 8 #include <pthread.h> 9 + #include <signal.h> 9 10 #include <string.h> 10 11 #include <sys/mount.h> 11 12 #include <poll.h> ··· 15 14 #include <sys/stat.h> 16 15 #include <sys/socket.h> 17 16 #include <sys/un.h> 17 + #include <sys/wait.h> 18 18 #include <unistd.h> 19 19 #include <linux/fs.h> 20 20 #include <linux/limits.h> 21 21 #include <linux/nsfs.h> 22 22 #include "../kselftest_harness.h" 23 + 24 + /* Fixture for tests that create child processes */ 25 + FIXTURE(nsid) { 26 + pid_t child_pid; 27 + }; 28 + 29 + FIXTURE_SETUP(nsid) { 30 + self->child_pid = 0; 31 + } 32 + 33 + FIXTURE_TEARDOWN(nsid) { 34 + /* Clean up any child process that may still be running */ 35 + if (self->child_pid > 0) { 36 + kill(self->child_pid, SIGKILL); 37 + waitpid(self->child_pid, NULL, 0); 38 + } 39 + } 23 40 24 41 TEST(nsid_mntns_basic) 25 42 { ··· 63 44 close(fd_mntns); 64 45 } 65 46 66 - TEST(nsid_mntns_separate) 47 + TEST_F(nsid, mntns_separate) 67 48 { 68 49 __u64 parent_mnt_ns_id = 0; 69 50 __u64 child_mnt_ns_id = 0; ··· 109 90 _exit(0); 110 91 } 111 92 93 + /* Track child for cleanup */ 94 + self->child_pid = pid; 95 + 112 96 /* Parent process */ 113 97 close(pipefd[1]); 114 98 ··· 121 99 122 100 if (buf == 'S') { 123 101 /* Child couldn't create namespace, skip test */ 124 - kill(pid, SIGTERM); 125 - waitpid(pid, NULL, 0); 126 102 close(fd_parent_mntns); 127 103 SKIP(return, "No permission to create mount namespace"); 128 104 } ··· 143 123 144 124 close(fd_parent_mntns); 145 125 close(fd_child_mntns); 146 - 147 - /* Clean up child process */ 148 - kill(pid, SIGTERM); 149 - waitpid(pid, NULL, 0); 150 126 } 151 127 152 128 TEST(nsid_cgroupns_basic) ··· 169 153 close(fd_cgroupns); 170 154 } 171 155 172 - TEST(nsid_cgroupns_separate) 156 + TEST_F(nsid, cgroupns_separate) 173 157 { 174 158 __u64 parent_cgroup_ns_id = 0; 175 159 __u64 child_cgroup_ns_id = 0; ··· 215 199 _exit(0); 216 200 } 217 201 202 + /* Track child for cleanup */ 203 + self->child_pid = pid; 204 + 218 205 /* Parent process */ 219 206 close(pipefd[1]); 220 207 ··· 227 208 228 209 if (buf == 'S') { 229 210 /* Child couldn't create namespace, skip test */ 230 - kill(pid, SIGTERM); 231 - waitpid(pid, NULL, 0); 232 211 close(fd_parent_cgroupns); 233 212 SKIP(return, "No permission to create cgroup namespace"); 234 213 } ··· 249 232 250 233 close(fd_parent_cgroupns); 251 234 close(fd_child_cgroupns); 252 - 253 - /* Clean up child process */ 254 - kill(pid, SIGTERM); 255 - waitpid(pid, NULL, 0); 256 235 } 257 236 258 237 TEST(nsid_ipcns_basic) ··· 275 262 close(fd_ipcns); 276 263 } 277 264 278 - TEST(nsid_ipcns_separate) 265 + TEST_F(nsid, ipcns_separate) 279 266 { 280 267 __u64 parent_ipc_ns_id = 0; 281 268 __u64 child_ipc_ns_id = 0; ··· 321 308 _exit(0); 322 309 } 323 310 311 + /* Track child for cleanup */ 312 + self->child_pid = pid; 313 + 324 314 /* Parent process */ 325 315 close(pipefd[1]); 326 316 ··· 333 317 334 318 if (buf == 'S') { 335 319 /* Child couldn't create namespace, skip test */ 336 - kill(pid, SIGTERM); 337 - waitpid(pid, NULL, 0); 338 320 close(fd_parent_ipcns); 339 321 SKIP(return, "No permission to create IPC namespace"); 340 322 } ··· 355 341 356 342 close(fd_parent_ipcns); 357 343 close(fd_child_ipcns); 358 - 359 - /* Clean up child process */ 360 - kill(pid, SIGTERM); 361 - waitpid(pid, NULL, 0); 362 344 } 363 345 364 346 TEST(nsid_utsns_basic) ··· 381 371 close(fd_utsns); 382 372 } 383 373 384 - TEST(nsid_utsns_separate) 374 + TEST_F(nsid, utsns_separate) 385 375 { 386 376 __u64 parent_uts_ns_id = 0; 387 377 __u64 child_uts_ns_id = 0; ··· 427 417 _exit(0); 428 418 } 429 419 420 + /* Track child for cleanup */ 421 + self->child_pid = pid; 422 + 430 423 /* Parent process */ 431 424 close(pipefd[1]); 432 425 ··· 439 426 440 427 if (buf == 'S') { 441 428 /* Child couldn't create namespace, skip test */ 442 - kill(pid, SIGTERM); 443 - waitpid(pid, NULL, 0); 444 429 close(fd_parent_utsns); 445 430 SKIP(return, "No permission to create UTS namespace"); 446 431 } ··· 461 450 462 451 close(fd_parent_utsns); 463 452 close(fd_child_utsns); 464 - 465 - /* Clean up child process */ 466 - kill(pid, SIGTERM); 467 - waitpid(pid, NULL, 0); 468 453 } 469 454 470 455 TEST(nsid_userns_basic) ··· 487 480 close(fd_userns); 488 481 } 489 482 490 - TEST(nsid_userns_separate) 483 + TEST_F(nsid, userns_separate) 491 484 { 492 485 __u64 parent_user_ns_id = 0; 493 486 __u64 child_user_ns_id = 0; ··· 533 526 _exit(0); 534 527 } 535 528 529 + /* Track child for cleanup */ 530 + self->child_pid = pid; 531 + 536 532 /* Parent process */ 537 533 close(pipefd[1]); 538 534 ··· 545 535 546 536 if (buf == 'S') { 547 537 /* Child couldn't create namespace, skip test */ 548 - kill(pid, SIGTERM); 549 - waitpid(pid, NULL, 0); 550 538 close(fd_parent_userns); 551 539 SKIP(return, "No permission to create user namespace"); 552 540 } ··· 567 559 568 560 close(fd_parent_userns); 569 561 close(fd_child_userns); 570 - 571 - /* Clean up child process */ 572 - kill(pid, SIGTERM); 573 - waitpid(pid, NULL, 0); 574 562 } 575 563 576 564 TEST(nsid_timens_basic) ··· 595 591 close(fd_timens); 596 592 } 597 593 598 - TEST(nsid_timens_separate) 594 + TEST_F(nsid, timens_separate) 599 595 { 600 596 __u64 parent_time_ns_id = 0; 601 597 __u64 child_time_ns_id = 0; ··· 656 652 } 657 653 } 658 654 655 + /* Track child for cleanup */ 656 + self->child_pid = pid; 657 + 659 658 /* Parent process */ 660 659 close(pipefd[1]); 661 660 ··· 667 660 668 661 if (buf == 'S') { 669 662 /* Child couldn't create namespace, skip test */ 670 - kill(pid, SIGTERM); 671 - waitpid(pid, NULL, 0); 672 663 close(fd_parent_timens); 673 664 close(pipefd[0]); 674 665 SKIP(return, "Cannot create time namespace"); ··· 694 689 695 690 close(fd_parent_timens); 696 691 close(fd_child_timens); 697 - 698 - /* Clean up child process */ 699 - kill(pid, SIGTERM); 700 - waitpid(pid, NULL, 0); 701 692 } 702 693 703 694 TEST(nsid_pidns_basic) ··· 720 719 close(fd_pidns); 721 720 } 722 721 723 - TEST(nsid_pidns_separate) 722 + TEST_F(nsid, pidns_separate) 724 723 { 725 724 __u64 parent_pid_ns_id = 0; 726 725 __u64 child_pid_ns_id = 0; ··· 777 776 } 778 777 } 779 778 779 + /* Track child for cleanup */ 780 + self->child_pid = pid; 781 + 780 782 /* Parent process */ 781 783 close(pipefd[1]); 782 784 ··· 788 784 789 785 if (buf == 'S') { 790 786 /* Child couldn't create namespace, skip test */ 791 - kill(pid, SIGTERM); 792 - waitpid(pid, NULL, 0); 793 787 close(fd_parent_pidns); 794 788 close(pipefd[0]); 795 789 SKIP(return, "No permission to create PID namespace"); ··· 815 813 816 814 close(fd_parent_pidns); 817 815 close(fd_child_pidns); 818 - 819 - /* Clean up child process */ 820 - kill(pid, SIGTERM); 821 - waitpid(pid, NULL, 0); 822 816 } 823 817 824 818 TEST(nsid_netns_basic) ··· 858 860 close(fd_netns); 859 861 } 860 862 861 - TEST(nsid_netns_separate) 863 + TEST_F(nsid, netns_separate) 862 864 { 863 865 __u64 parent_net_ns_id = 0; 864 866 __u64 parent_netns_cookie = 0; ··· 918 920 _exit(0); 919 921 } 920 922 923 + /* Track child for cleanup */ 924 + self->child_pid = pid; 925 + 921 926 /* Parent process */ 922 927 close(pipefd[1]); 923 928 ··· 930 929 931 930 if (buf == 'S') { 932 931 /* Child couldn't create namespace, skip test */ 933 - kill(pid, SIGTERM); 934 - waitpid(pid, NULL, 0); 935 932 close(fd_parent_netns); 936 933 close(parent_sock); 937 934 SKIP(return, "No permission to create network namespace"); ··· 976 977 close(fd_parent_netns); 977 978 close(fd_child_netns); 978 979 close(parent_sock); 979 - 980 - /* Clean up child process */ 981 - kill(pid, SIGTERM); 982 - waitpid(pid, NULL, 0); 983 980 } 984 981 985 982 TEST_HARNESS_MAIN