Unverified Commit 18b5c400 authored by Christian Brauner's avatar Christian Brauner
Browse files

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: default avatarChristian Brauner <brauner@kernel.org>
parents a67ee4e2 64539375
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ struct mnt_namespace {
	unsigned int		nr_mounts; /* # of mounts in the namespace */
	unsigned int		pending_mounts;
	refcount_t		passive; /* number references not pinning @mounts */
	bool			is_anon;
} __randomize_layout;

struct mnt_pcp {
@@ -175,7 +176,7 @@ static inline bool is_local_mountpoint(const struct dentry *dentry)

static inline bool is_anon_ns(struct mnt_namespace *ns)
{
	return ns->ns.ns_id == 0;
	return ns->is_anon;
}

static inline bool anon_ns_root(const struct mount *m)
+5 −4
Original line number Diff line number Diff line
@@ -138,7 +138,7 @@ static inline struct mnt_namespace *node_to_mnt_ns(const struct rb_node *node)

	if (!node)
		return NULL;
	ns = rb_entry(node, struct ns_common, ns_tree_node);
	ns = rb_entry(node, struct ns_common, ns_tree_node.ns_node);
	return container_of(ns, struct mnt_namespace, ns);
}

@@ -4093,8 +4093,9 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns, bool a
		dec_mnt_namespaces(ucounts);
		return ERR_PTR(ret);
	}
	if (!anon)
	ns_tree_gen_id(new_ns);

	new_ns->is_anon = anon;
	refcount_set(&new_ns->passive, 1);
	new_ns->mounts = RB_ROOT;
	init_waitqueue_head(&new_ns->poll);
@@ -5985,7 +5986,7 @@ SYSCALL_DEFINE4(listmount, const struct mnt_id_req __user *, req,
}

struct mnt_namespace init_mnt_ns = {
	.ns		= NS_COMMON_INIT(init_mnt_ns, 1),
	.ns		= NS_COMMON_INIT(init_mnt_ns),
	.user_ns	= &init_user_ns,
	.passive	= REFCOUNT_INIT(1),
	.mounts		= RB_ROOT,
+196 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
#ifndef _LINUX_NS_COMMON_TYPES_H
#define _LINUX_NS_COMMON_TYPES_H

#include <linux/atomic.h>
#include <linux/ns/nstree_types.h>
#include <linux/rbtree.h>
#include <linux/refcount.h>
#include <linux/types.h>

struct cgroup_namespace;
struct dentry;
struct ipc_namespace;
struct mnt_namespace;
struct net;
struct pid_namespace;
struct proc_ns_operations;
struct time_namespace;
struct user_namespace;
struct uts_namespace;

extern struct cgroup_namespace init_cgroup_ns;
extern struct ipc_namespace init_ipc_ns;
extern struct mnt_namespace init_mnt_ns;
extern struct net init_net;
extern struct pid_namespace init_pid_ns;
extern struct time_namespace init_time_ns;
extern struct user_namespace init_user_ns;
extern struct uts_namespace init_uts_ns;

extern const struct proc_ns_operations cgroupns_operations;
extern const struct proc_ns_operations ipcns_operations;
extern const struct proc_ns_operations mntns_operations;
extern const struct proc_ns_operations netns_operations;
extern const struct proc_ns_operations pidns_operations;
extern const struct proc_ns_operations pidns_for_children_operations;
extern const struct proc_ns_operations timens_operations;
extern const struct proc_ns_operations timens_for_children_operations;
extern const struct proc_ns_operations userns_operations;
extern const struct proc_ns_operations utsns_operations;

/*
 * Namespace lifetimes are managed via a two-tier reference counting model:
 *
 * (1) __ns_ref (refcount_t): Main reference count tracking memory
 *     lifetime. Controls when the namespace structure itself is freed.
 *     It also pins the namespace on the namespace trees whereas (2)
 *     only regulates their visibility to userspace.
 *
 * (2) __ns_ref_active (atomic_t): Reference count tracking active users.
 *     Controls visibility of the namespace in the namespace trees.
 *     Any live task that uses the namespace (via nsproxy or cred) holds
 *     an active reference. Any open file descriptor or bind-mount of
 *     the namespace holds an active reference. Once all tasks have
 *     called exited their namespaces and all file descriptors and
 *     bind-mounts have been released the active reference count drops
 *     to zero and the namespace becomes inactive. IOW, the namespace
 *     cannot be listed or opened via file handles anymore.
 *
 *     Note that it is valid to transition from active to inactive and
 *     back from inactive to active e.g., when resurrecting an inactive
 *     namespace tree via the SIOCGSKNS ioctl().
 *
 * Relationship and lifecycle states:
 *
 * - Active (__ns_ref_active > 0):
 *   Namespace is actively used and visible to userspace. The namespace
 *   can be reopened via /proc/<pid>/ns/<ns_type>, via namespace file
 *   handles, or discovered via listns().
 *
 * - Inactive (__ns_ref_active == 0, __ns_ref > 0):
 *   No tasks are actively using the namespace and it isn't pinned by
 *   any bind-mounts or open file descriptors anymore. But the namespace
 *   is still kept alive by internal references. For example, the user
 *   namespace could be pinned by an open file through file->f_cred
 *   references when one of the now defunct tasks had opened a file and
 *   handed the file descriptor off to another process via a UNIX
 *   sockets. Such references keep the namespace structure alive through
 *   __ns_ref but will not hold an active reference.
 *
 * - Destroyed (__ns_ref == 0):
 *   No references remain. The namespace is removed from the tree and freed.
 *
 * State transitions:
 *
 * Active -> Inactive:
 *   When the last task using the namespace exits it drops its active
 *   references to all namespaces. However, user and pid namespaces
 *   remain accessible until the task has been reaped.
 *
 * Inactive -> Active:
 *   An inactive namespace tree might be resurrected due to e.g., the
 *   SIOCGSKNS ioctl() on a socket.
 *
 * Inactive -> Destroyed:
 *   When __ns_ref drops to zero the namespace is removed from the
 *   namespaces trees and the memory is freed (after RCU grace period).
 *
 * Initial namespaces:
 *   Boot-time namespaces (init_net, init_pid_ns, etc.) start with
 *   __ns_ref_active = 1 and remain active forever.
 *
 * @ns_type: type of namespace (e.g., CLONE_NEWNET)
 * @stashed: cached dentry to be used by the vfs
 * @ops: namespace operations
 * @inum: namespace inode number (quickly recycled for non-initial namespaces)
 * @__ns_ref: main reference count (do not use directly)
 * @ns_tree: namespace tree nodes and active reference count
 */
struct ns_common {
	u32 ns_type;
	struct dentry *stashed;
	const struct proc_ns_operations *ops;
	unsigned int inum;
	refcount_t __ns_ref; /* do not use directly */
	union {
		struct ns_tree;
		struct rcu_head ns_rcu;
	};
};

#define to_ns_common(__ns)                                    \
	_Generic((__ns),                                      \
		struct cgroup_namespace *:       &(__ns)->ns, \
		const struct cgroup_namespace *: &(__ns)->ns, \
		struct ipc_namespace *:          &(__ns)->ns, \
		const struct ipc_namespace *:    &(__ns)->ns, \
		struct mnt_namespace *:          &(__ns)->ns, \
		const struct mnt_namespace *:    &(__ns)->ns, \
		struct net *:                    &(__ns)->ns, \
		const struct net *:              &(__ns)->ns, \
		struct pid_namespace *:          &(__ns)->ns, \
		const struct pid_namespace *:    &(__ns)->ns, \
		struct time_namespace *:         &(__ns)->ns, \
		const struct time_namespace *:   &(__ns)->ns, \
		struct user_namespace *:         &(__ns)->ns, \
		const struct user_namespace *:   &(__ns)->ns, \
		struct uts_namespace *:          &(__ns)->ns, \
		const struct uts_namespace *:    &(__ns)->ns)

#define ns_init_inum(__ns)                                     \
	_Generic((__ns),                                       \
		struct cgroup_namespace *: CGROUP_NS_INIT_INO, \
		struct ipc_namespace *:    IPC_NS_INIT_INO,    \
		struct mnt_namespace *:    MNT_NS_INIT_INO,    \
		struct net *:              NET_NS_INIT_INO,    \
		struct pid_namespace *:    PID_NS_INIT_INO,    \
		struct time_namespace *:   TIME_NS_INIT_INO,   \
		struct user_namespace *:   USER_NS_INIT_INO,   \
		struct uts_namespace *:    UTS_NS_INIT_INO)

#define ns_init_ns(__ns)                                    \
	_Generic((__ns),                                    \
		struct cgroup_namespace *: &init_cgroup_ns, \
		struct ipc_namespace *:    &init_ipc_ns,    \
		struct mnt_namespace *:    &init_mnt_ns,     \
		struct net *:              &init_net,       \
		struct pid_namespace *:    &init_pid_ns,    \
		struct time_namespace *:   &init_time_ns,   \
		struct user_namespace *:   &init_user_ns,   \
		struct uts_namespace *:    &init_uts_ns)

#define ns_init_id(__ns)						\
	_Generic((__ns),						\
		struct cgroup_namespace *:	CGROUP_NS_INIT_ID,	\
		struct ipc_namespace *:		IPC_NS_INIT_ID,		\
		struct mnt_namespace *:		MNT_NS_INIT_ID,		\
		struct net *:			NET_NS_INIT_ID,		\
		struct pid_namespace *:		PID_NS_INIT_ID,		\
		struct time_namespace *:	TIME_NS_INIT_ID,	\
		struct user_namespace *:	USER_NS_INIT_ID,	\
		struct uts_namespace *:		UTS_NS_INIT_ID)

#define to_ns_operations(__ns)                                                                         \
	_Generic((__ns),                                                                               \
		struct cgroup_namespace *: (IS_ENABLED(CONFIG_CGROUPS) ? &cgroupns_operations : NULL), \
		struct ipc_namespace *:    (IS_ENABLED(CONFIG_IPC_NS)  ? &ipcns_operations    : NULL), \
		struct mnt_namespace *:    &mntns_operations,                                          \
		struct net *:              (IS_ENABLED(CONFIG_NET_NS)  ? &netns_operations    : NULL), \
		struct pid_namespace *:    (IS_ENABLED(CONFIG_PID_NS)  ? &pidns_operations    : NULL), \
		struct time_namespace *:   (IS_ENABLED(CONFIG_TIME_NS) ? &timens_operations   : NULL), \
		struct user_namespace *:   (IS_ENABLED(CONFIG_USER_NS) ? &userns_operations   : NULL), \
		struct uts_namespace *:    (IS_ENABLED(CONFIG_UTS_NS)  ? &utsns_operations    : NULL))

#define ns_common_type(__ns)                                \
	_Generic((__ns),                                    \
		struct cgroup_namespace *: CLONE_NEWCGROUP, \
		struct ipc_namespace *:    CLONE_NEWIPC,    \
		struct mnt_namespace *:    CLONE_NEWNS,     \
		struct net *:              CLONE_NEWNET,    \
		struct pid_namespace *:    CLONE_NEWPID,    \
		struct time_namespace *:   CLONE_NEWTIME,   \
		struct user_namespace *:   CLONE_NEWUSER,   \
		struct uts_namespace *:    CLONE_NEWUTS)

#endif /* _LINUX_NS_COMMON_TYPES_H */
+55 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
/* Copyright (c) 2025 Christian Brauner <brauner@kernel.org> */
#ifndef _LINUX_NSTREE_TYPES_H
#define _LINUX_NSTREE_TYPES_H

#include <linux/rbtree.h>
#include <linux/list.h>

/**
 * struct ns_tree_root - Root of a namespace tree
 * @ns_rb: Red-black tree root for efficient lookups
 * @ns_list_head: List head for sequential iteration
 *
 * Each namespace tree maintains both an rbtree (for O(log n) lookups)
 * and a list (for efficient sequential iteration). The list is kept in
 * the same sorted order as the rbtree.
 */
struct ns_tree_root {
	struct rb_root ns_rb;
	struct list_head ns_list_head;
};

/**
 * struct ns_tree_node - Node in a namespace tree
 * @ns_node: Red-black tree node
 * @ns_list_entry: List entry for sequential iteration
 *
 * Represents a namespace's position in a tree. Each namespace has
 * multiple tree nodes for different trees (unified, per-type, owner).
 */
struct ns_tree_node {
	struct rb_node ns_node;
	struct list_head ns_list_entry;
};

/**
 * struct ns_tree - Namespace tree nodes and active reference count
 * @ns_id: Unique namespace identifier
 * @__ns_ref_active: Active reference count (do not use directly)
 * @ns_unified_node: Node in the global namespace tree
 * @ns_tree_node: Node in the per-type namespace tree
 * @ns_owner_node: Node in the owner namespace's tree of owned namespaces
 * @ns_owner_root: Root of the tree of namespaces owned by this namespace
 *                 (only used when this namespace is an owner)
 */
struct ns_tree {
	u64 ns_id;
	atomic_t __ns_ref_active;
	struct ns_tree_node ns_unified_node;
	struct ns_tree_node ns_tree_node;
	struct ns_tree_node ns_owner_node;
	struct ns_tree_root ns_owner_root;
};

#endif /* _LINUX_NSTREE_TYPES_H */
+51 −215
Original line number Diff line number Diff line
@@ -2,139 +2,18 @@
#ifndef _LINUX_NS_COMMON_H
#define _LINUX_NS_COMMON_H

#include <linux/ns/ns_common_types.h>
#include <linux/refcount.h>
#include <linux/rbtree.h>
#include <linux/vfsdebug.h>
#include <uapi/linux/sched.h>
#include <uapi/linux/nsfs.h>

struct proc_ns_operations;

struct cgroup_namespace;
struct ipc_namespace;
struct mnt_namespace;
struct net;
struct pid_namespace;
struct time_namespace;
struct user_namespace;
struct uts_namespace;

extern struct cgroup_namespace init_cgroup_ns;
extern struct ipc_namespace init_ipc_ns;
extern struct mnt_namespace init_mnt_ns;
extern struct net init_net;
extern struct pid_namespace init_pid_ns;
extern struct time_namespace init_time_ns;
extern struct user_namespace init_user_ns;
extern struct uts_namespace init_uts_ns;

extern const struct proc_ns_operations netns_operations;
extern const struct proc_ns_operations utsns_operations;
extern const struct proc_ns_operations ipcns_operations;
extern const struct proc_ns_operations pidns_operations;
extern const struct proc_ns_operations pidns_for_children_operations;
extern const struct proc_ns_operations userns_operations;
extern const struct proc_ns_operations mntns_operations;
extern const struct proc_ns_operations cgroupns_operations;
extern const struct proc_ns_operations timens_operations;
extern const struct proc_ns_operations timens_for_children_operations;

/*
 * Namespace lifetimes are managed via a two-tier reference counting model:
 *
 * (1) __ns_ref (refcount_t): Main reference count tracking memory
 *     lifetime. Controls when the namespace structure itself is freed.
 *     It also pins the namespace on the namespace trees whereas (2)
 *     only regulates their visibility to userspace.
 *
 * (2) __ns_ref_active (atomic_t): Reference count tracking active users.
 *     Controls visibility of the namespace in the namespace trees.
 *     Any live task that uses the namespace (via nsproxy or cred) holds
 *     an active reference. Any open file descriptor or bind-mount of
 *     the namespace holds an active reference. Once all tasks have
 *     called exited their namespaces and all file descriptors and
 *     bind-mounts have been released the active reference count drops
 *     to zero and the namespace becomes inactive. IOW, the namespace
 *     cannot be listed or opened via file handles anymore.
 *
 *     Note that it is valid to transition from active to inactive and
 *     back from inactive to active e.g., when resurrecting an inactive
 *     namespace tree via the SIOCGSKNS ioctl().
 *
 * Relationship and lifecycle states:
 *
 * - Active (__ns_ref_active > 0):
 *   Namespace is actively used and visible to userspace. The namespace
 *   can be reopened via /proc/<pid>/ns/<ns_type>, via namespace file
 *   handles, or discovered via listns().
 *
 * - Inactive (__ns_ref_active == 0, __ns_ref > 0):
 *   No tasks are actively using the namespace and it isn't pinned by
 *   any bind-mounts or open file descriptors anymore. But the namespace
 *   is still kept alive by internal references. For example, the user
 *   namespace could be pinned by an open file through file->f_cred
 *   references when one of the now defunct tasks had opened a file and
 *   handed the file descriptor off to another process via a UNIX
 *   sockets. Such references keep the namespace structure alive through
 *   __ns_ref but will not hold an active reference.
 *
 * - Destroyed (__ns_ref == 0):
 *   No references remain. The namespace is removed from the tree and freed.
 *
 * State transitions:
 *
 * Active -> Inactive:
 *   When the last task using the namespace exits it drops its active
 *   references to all namespaces. However, user and pid namespaces
 *   remain accessible until the task has been reaped.
 *
 * Inactive -> Active:
 *   An inactive namespace tree might be resurrected due to e.g., the
 *   SIOCGSKNS ioctl() on a socket.
 *
 * Inactive -> Destroyed:
 *   When __ns_ref drops to zero the namespace is removed from the
 *   namespaces trees and the memory is freed (after RCU grace period).
 *
 * Initial namespaces:
 *   Boot-time namespaces (init_net, init_pid_ns, etc.) start with
 *   __ns_ref_active = 1 and remain active forever.
 */
struct ns_common {
	u32 ns_type;
	struct dentry *stashed;
	const struct proc_ns_operations *ops;
	unsigned int inum;
	refcount_t __ns_ref; /* do not use directly */
	union {
		struct {
			u64 ns_id;
			struct /* global namespace rbtree and list */ {
				struct rb_node ns_unified_tree_node;
				struct list_head ns_unified_list_node;
			};
			struct /* per type rbtree and list */ {
				struct rb_node ns_tree_node;
				struct list_head ns_list_node;
			};
			struct /* namespace ownership rbtree and list */ {
				struct rb_root ns_owner_tree; /* rbtree of namespaces owned by this namespace */
				struct list_head ns_owner; /* list of namespaces owned by this namespace */
				struct rb_node ns_owner_tree_node; /* node in the owner namespace's rbtree */
				struct list_head ns_owner_entry; /* node in the owner namespace's ns_owned list */
			};
			atomic_t __ns_ref_active; /* do not use directly */
		};
		struct rcu_head ns_rcu;
	};
};

bool is_current_namespace(struct ns_common *ns);
int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum);
void __ns_common_free(struct ns_common *ns);
struct ns_common *__must_check ns_owner(struct ns_common *ns);

static __always_inline bool is_initial_namespace(struct ns_common *ns)
static __always_inline bool is_ns_init_inum(const struct ns_common *ns)
{
	VFS_WARN_ON_ONCE(ns->inum == 0);
	return unlikely(in_range(ns->inum, MNT_NS_INIT_INO,
@@ -147,93 +26,19 @@ static __always_inline bool is_ns_init_id(const struct ns_common *ns)
	return ns->ns_id <= NS_LAST_INIT_ID;
}

#define to_ns_common(__ns)                                    \
	_Generic((__ns),                                      \
		struct cgroup_namespace *:       &(__ns)->ns, \
		const struct cgroup_namespace *: &(__ns)->ns, \
		struct ipc_namespace *:          &(__ns)->ns, \
		const struct ipc_namespace *:    &(__ns)->ns, \
		struct mnt_namespace *:          &(__ns)->ns, \
		const struct mnt_namespace *:    &(__ns)->ns, \
		struct net *:                    &(__ns)->ns, \
		const struct net *:              &(__ns)->ns, \
		struct pid_namespace *:          &(__ns)->ns, \
		const struct pid_namespace *:    &(__ns)->ns, \
		struct time_namespace *:         &(__ns)->ns, \
		const struct time_namespace *:   &(__ns)->ns, \
		struct user_namespace *:         &(__ns)->ns, \
		const struct user_namespace *:   &(__ns)->ns, \
		struct uts_namespace *:          &(__ns)->ns, \
		const struct uts_namespace *:    &(__ns)->ns)

#define ns_init_inum(__ns)                                     \
	_Generic((__ns),                                       \
		struct cgroup_namespace *: CGROUP_NS_INIT_INO, \
		struct ipc_namespace *:    IPC_NS_INIT_INO,    \
		struct mnt_namespace *:    MNT_NS_INIT_INO,    \
		struct net *:              NET_NS_INIT_INO,    \
		struct pid_namespace *:    PID_NS_INIT_INO,    \
		struct time_namespace *:   TIME_NS_INIT_INO,   \
		struct user_namespace *:   USER_NS_INIT_INO,   \
		struct uts_namespace *:    UTS_NS_INIT_INO)

#define ns_init_ns(__ns)                                    \
	_Generic((__ns),                                    \
		struct cgroup_namespace *: &init_cgroup_ns, \
		struct ipc_namespace *:    &init_ipc_ns,    \
		struct mnt_namespace *:    &init_mnt_ns,     \
		struct net *:              &init_net,       \
		struct pid_namespace *:    &init_pid_ns,    \
		struct time_namespace *:   &init_time_ns,   \
		struct user_namespace *:   &init_user_ns,   \
		struct uts_namespace *:    &init_uts_ns)

#define ns_init_id(__ns)						\
	_Generic((__ns),						\
		struct cgroup_namespace *:	CGROUP_NS_INIT_ID,	\
		struct ipc_namespace *:		IPC_NS_INIT_ID,		\
		struct mnt_namespace *:		MNT_NS_INIT_ID,		\
		struct net *:			NET_NS_INIT_ID,		\
		struct pid_namespace *:		PID_NS_INIT_ID,		\
		struct time_namespace *:	TIME_NS_INIT_ID,	\
		struct user_namespace *:	USER_NS_INIT_ID,	\
		struct uts_namespace *:		UTS_NS_INIT_ID)

#define to_ns_operations(__ns)                                                                         \
	_Generic((__ns),                                                                               \
		struct cgroup_namespace *: (IS_ENABLED(CONFIG_CGROUPS) ? &cgroupns_operations : NULL), \
		struct ipc_namespace *:    (IS_ENABLED(CONFIG_IPC_NS)  ? &ipcns_operations    : NULL), \
		struct mnt_namespace *:    &mntns_operations,                                          \
		struct net *:              (IS_ENABLED(CONFIG_NET_NS)  ? &netns_operations    : NULL), \
		struct pid_namespace *:    (IS_ENABLED(CONFIG_PID_NS)  ? &pidns_operations    : NULL), \
		struct time_namespace *:   (IS_ENABLED(CONFIG_TIME_NS) ? &timens_operations   : NULL), \
		struct user_namespace *:   (IS_ENABLED(CONFIG_USER_NS) ? &userns_operations   : NULL), \
		struct uts_namespace *:    (IS_ENABLED(CONFIG_UTS_NS)  ? &utsns_operations    : NULL))

#define ns_common_type(__ns)                                \
	_Generic((__ns),                                    \
		struct cgroup_namespace *: CLONE_NEWCGROUP, \
		struct ipc_namespace *:    CLONE_NEWIPC,    \
		struct mnt_namespace *:    CLONE_NEWNS,     \
		struct net *:              CLONE_NEWNET,    \
		struct pid_namespace *:    CLONE_NEWPID,    \
		struct time_namespace *:   CLONE_NEWTIME,   \
		struct user_namespace *:   CLONE_NEWUSER,   \
		struct uts_namespace *:    CLONE_NEWUTS)

#define NS_COMMON_INIT(nsname, refs)							\
#define NS_COMMON_INIT(nsname)										\
{													\
	.ns_type			= ns_common_type(&nsname),					\
	.ns_id				= ns_init_id(&nsname),						\
	.inum				= ns_init_inum(&nsname),					\
	.ops				= to_ns_operations(&nsname),					\
	.stashed			= NULL,								\
	.__ns_ref		= REFCOUNT_INIT(refs),					\
	.__ns_ref			= REFCOUNT_INIT(1),						\
	.__ns_ref_active		= ATOMIC_INIT(1),						\
	.ns_list_node		= LIST_HEAD_INIT(nsname.ns.ns_list_node),		\
	.ns_owner_entry		= LIST_HEAD_INIT(nsname.ns.ns_owner_entry),		\
	.ns_owner		= LIST_HEAD_INIT(nsname.ns.ns_owner),			\
	.ns_unified_list_node	= LIST_HEAD_INIT(nsname.ns.ns_unified_list_node),	\
	.ns_unified_node.ns_list_entry	= LIST_HEAD_INIT(nsname.ns.ns_unified_node.ns_list_entry),	\
	.ns_tree_node.ns_list_entry	= LIST_HEAD_INIT(nsname.ns.ns_tree_node.ns_list_entry),		\
	.ns_owner_node.ns_list_entry	= LIST_HEAD_INIT(nsname.ns.ns_owner_node.ns_list_entry),	\
	.ns_owner_root.ns_list_head	= LIST_HEAD_INIT(nsname.ns.ns_owner_root.ns_list_head),		\
}

#define ns_common_init(__ns)                     \
@@ -255,8 +60,18 @@ static __always_inline __must_check int __ns_ref_active_read(const struct ns_com
	return atomic_read(&ns->__ns_ref_active);
}

static __always_inline __must_check int __ns_ref_read(const struct ns_common *ns)
{
	return refcount_read(&ns->__ns_ref);
}

static __always_inline __must_check bool __ns_ref_put(struct ns_common *ns)
{
	if (is_ns_init_id(ns)) {
		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
		return false;
	}
	if (refcount_dec_and_test(&ns->__ns_ref)) {
		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns));
		return true;
@@ -266,23 +81,44 @@ static __always_inline __must_check bool __ns_ref_put(struct ns_common *ns)

static __always_inline __must_check bool __ns_ref_get(struct ns_common *ns)
{
	if (is_ns_init_id(ns)) {
		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
		return true;
	}
	if (refcount_inc_not_zero(&ns->__ns_ref))
		return true;
	VFS_WARN_ON_ONCE(__ns_ref_active_read(ns));
	return false;
}

static __always_inline __must_check int __ns_ref_read(const struct ns_common *ns)
static __always_inline void __ns_ref_inc(struct ns_common *ns)
{
	return refcount_read(&ns->__ns_ref);
	if (is_ns_init_id(ns)) {
		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
		return;
	}
	refcount_inc(&ns->__ns_ref);
}

static __always_inline __must_check bool __ns_ref_dec_and_lock(struct ns_common *ns,
							       spinlock_t *ns_lock)
{
	if (is_ns_init_id(ns)) {
		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
		return false;
	}
	return refcount_dec_and_lock(&ns->__ns_ref, ns_lock);
}

#define ns_ref_read(__ns) __ns_ref_read(to_ns_common((__ns)))
#define ns_ref_inc(__ns) refcount_inc(&to_ns_common((__ns))->__ns_ref)
#define ns_ref_inc(__ns) __ns_ref_inc(to_ns_common((__ns)))
#define ns_ref_get(__ns) __ns_ref_get(to_ns_common((__ns)))
#define ns_ref_put(__ns) __ns_ref_put(to_ns_common((__ns)))
#define ns_ref_put_and_lock(__ns, __lock) \
	refcount_dec_and_lock(&to_ns_common((__ns))->__ns_ref, (__lock))
#define ns_ref_put_and_lock(__ns, __ns_lock) \
	__ns_ref_dec_and_lock(to_ns_common((__ns)), __ns_lock)

#define ns_ref_active_read(__ns) \
	((__ns) ? __ns_ref_active_read(to_ns_common(__ns)) : 0)
Loading