xref: /linux/include/linux/ns_common.h (revision 415d34b92c1f921a9ff3c38f56319cbc5536f642)
1 /* SPDX-License-Identifier: GPL-2.0 */
2 #ifndef _LINUX_NS_COMMON_H
3 #define _LINUX_NS_COMMON_H
4 
5 #include <linux/ns/ns_common_types.h>
6 #include <linux/refcount.h>
7 #include <linux/vfsdebug.h>
8 #include <uapi/linux/sched.h>
9 #include <uapi/linux/nsfs.h>
10 
11 bool is_current_namespace(struct ns_common *ns);
12 int __ns_common_init(struct ns_common *ns, u32 ns_type, const struct proc_ns_operations *ops, int inum);
13 void __ns_common_free(struct ns_common *ns);
14 struct ns_common *__must_check ns_owner(struct ns_common *ns);
15 
is_ns_init_inum(const struct ns_common * ns)16 static __always_inline bool is_ns_init_inum(const struct ns_common *ns)
17 {
18 	VFS_WARN_ON_ONCE(ns->inum == 0);
19 	return unlikely(in_range(ns->inum, MNT_NS_INIT_INO,
20 				 IPC_NS_INIT_INO - MNT_NS_INIT_INO + 1));
21 }
22 
is_ns_init_id(const struct ns_common * ns)23 static __always_inline bool is_ns_init_id(const struct ns_common *ns)
24 {
25 	VFS_WARN_ON_ONCE(ns->ns_id == 0);
26 	return ns->ns_id <= NS_LAST_INIT_ID;
27 }
28 
29 #define NS_COMMON_INIT(nsname)										\
30 {													\
31 	.ns_type			= ns_common_type(&nsname),					\
32 	.ns_id				= ns_init_id(&nsname),						\
33 	.inum				= ns_init_inum(&nsname),					\
34 	.ops				= to_ns_operations(&nsname),					\
35 	.stashed			= NULL,								\
36 	.__ns_ref			= REFCOUNT_INIT(1),						\
37 	.__ns_ref_active		= ATOMIC_INIT(1),						\
38 	.ns_unified_node.ns_list_entry	= LIST_HEAD_INIT(nsname.ns.ns_unified_node.ns_list_entry),	\
39 	.ns_tree_node.ns_list_entry	= LIST_HEAD_INIT(nsname.ns.ns_tree_node.ns_list_entry),		\
40 	.ns_owner_node.ns_list_entry	= LIST_HEAD_INIT(nsname.ns.ns_owner_node.ns_list_entry),	\
41 	.ns_owner_root.ns_list_head	= LIST_HEAD_INIT(nsname.ns.ns_owner_root.ns_list_head),		\
42 }
43 
44 #define ns_common_init(__ns)                     \
45 	__ns_common_init(to_ns_common(__ns),     \
46 			 ns_common_type(__ns),   \
47 			 to_ns_operations(__ns), \
48 			 (((__ns) == ns_init_ns(__ns)) ? ns_init_inum(__ns) : 0))
49 
50 #define ns_common_init_inum(__ns, __inum)        \
51 	__ns_common_init(to_ns_common(__ns),     \
52 			 ns_common_type(__ns),   \
53 			 to_ns_operations(__ns), \
54 			 __inum)
55 
56 #define ns_common_free(__ns) __ns_common_free(to_ns_common((__ns)))
57 
__ns_ref_active_read(const struct ns_common * ns)58 static __always_inline __must_check int __ns_ref_active_read(const struct ns_common *ns)
59 {
60 	return atomic_read(&ns->__ns_ref_active);
61 }
62 
__ns_ref_read(const struct ns_common * ns)63 static __always_inline __must_check int __ns_ref_read(const struct ns_common *ns)
64 {
65 	return refcount_read(&ns->__ns_ref);
66 }
67 
__ns_ref_put(struct ns_common * ns)68 static __always_inline __must_check bool __ns_ref_put(struct ns_common *ns)
69 {
70 	if (is_ns_init_id(ns)) {
71 		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
72 		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
73 		return false;
74 	}
75 	if (refcount_dec_and_test(&ns->__ns_ref)) {
76 		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns));
77 		return true;
78 	}
79 	return false;
80 }
81 
__ns_ref_get(struct ns_common * ns)82 static __always_inline __must_check bool __ns_ref_get(struct ns_common *ns)
83 {
84 	if (is_ns_init_id(ns)) {
85 		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
86 		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
87 		return true;
88 	}
89 	if (refcount_inc_not_zero(&ns->__ns_ref))
90 		return true;
91 	VFS_WARN_ON_ONCE(__ns_ref_active_read(ns));
92 	return false;
93 }
94 
__ns_ref_inc(struct ns_common * ns)95 static __always_inline void __ns_ref_inc(struct ns_common *ns)
96 {
97 	if (is_ns_init_id(ns)) {
98 		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
99 		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
100 		return;
101 	}
102 	refcount_inc(&ns->__ns_ref);
103 }
104 
__ns_ref_dec_and_lock(struct ns_common * ns,spinlock_t * ns_lock)105 static __always_inline __must_check bool __ns_ref_dec_and_lock(struct ns_common *ns,
106 							       spinlock_t *ns_lock)
107 {
108 	if (is_ns_init_id(ns)) {
109 		VFS_WARN_ON_ONCE(__ns_ref_read(ns) != 1);
110 		VFS_WARN_ON_ONCE(__ns_ref_active_read(ns) != 1);
111 		return false;
112 	}
113 	return refcount_dec_and_lock(&ns->__ns_ref, ns_lock);
114 }
115 
116 #define ns_ref_read(__ns) __ns_ref_read(to_ns_common((__ns)))
117 #define ns_ref_inc(__ns) \
118 	do { if (__ns) __ns_ref_inc(to_ns_common((__ns))); } while (0)
119 #define ns_ref_get(__ns) \
120 	((__ns) ? __ns_ref_get(to_ns_common((__ns))) : false)
121 #define ns_ref_put(__ns) \
122 	((__ns) ? __ns_ref_put(to_ns_common((__ns))) : false)
123 #define ns_ref_put_and_lock(__ns, __ns_lock) \
124 	((__ns) ? __ns_ref_dec_and_lock(to_ns_common((__ns)), __ns_lock) : false)
125 
126 #define ns_ref_active_read(__ns) \
127 	((__ns) ? __ns_ref_active_read(to_ns_common(__ns)) : 0)
128 
129 void __ns_ref_active_put(struct ns_common *ns);
130 
131 #define ns_ref_active_put(__ns) \
132 	do { if (__ns) __ns_ref_active_put(to_ns_common(__ns)); } while (0)
133 
ns_get_unless_inactive(struct ns_common * ns)134 static __always_inline struct ns_common *__must_check ns_get_unless_inactive(struct ns_common *ns)
135 {
136 	if (!__ns_ref_active_read(ns)) {
137 		VFS_WARN_ON_ONCE(is_ns_init_id(ns));
138 		return NULL;
139 	}
140 	if (!__ns_ref_get(ns))
141 		return NULL;
142 	return ns;
143 }
144 
145 void __ns_ref_active_get(struct ns_common *ns);
146 
147 #define ns_ref_active_get(__ns) \
148 	do { if (__ns) __ns_ref_active_get(to_ns_common(__ns)); } while (0)
149 
150 #endif
151