1 /* SPDX-License-Identifier: GPL-2.0-only */
2 #ifndef _LINUX_FILE_REF_H
3 #define _LINUX_FILE_REF_H
5 #include <linux/atomic.h>
6 #include <linux/preempt.h>
7 #include <linux/types.h>
10 * file_ref is a reference count implementation specifically for use by
11 * files. It takes inspiration from rcuref but differs in key aspects
12 * such as support for SLAB_TYPESAFE_BY_RCU type caches.
14 * FILE_REF_ONEREF FILE_REF_MAXREF
15 * 0x0000000000000000UL 0x7FFFFFFFFFFFFFFFUL
16 * <-------------------valid ------------------->
19 * 0x8000000000000000UL 0xA000000000000000UL 0xBFFFFFFFFFFFFFFFUL
20 * <-----------------------saturation zone---------------------->
22 * FILE_REF_RELEASED FILE_REF_DEAD
23 * 0xC000000000000000UL 0xE000000000000000UL
24 * <-------------------dead zone------------------->
27 * 0xFFFFFFFFFFFFFFFFUL
31 #define FILE_REF_ONEREF 0x0000000000000000UL
32 #define FILE_REF_MAXREF 0x7FFFFFFFFFFFFFFFUL
33 #define FILE_REF_SATURATED 0xA000000000000000UL
34 #define FILE_REF_RELEASED 0xC000000000000000UL
35 #define FILE_REF_DEAD 0xE000000000000000UL
36 #define FILE_REF_NOREF 0xFFFFFFFFFFFFFFFFUL
38 #define FILE_REF_ONEREF 0x00000000U
39 #define FILE_REF_MAXREF 0x7FFFFFFFU
40 #define FILE_REF_SATURATED 0xA0000000U
41 #define FILE_REF_RELEASED 0xC0000000U
42 #define FILE_REF_DEAD 0xE0000000U
43 #define FILE_REF_NOREF 0xFFFFFFFFU
55 * file_ref_init - Initialize a file reference count
56 * @ref: Pointer to the reference count
57 * @cnt: The initial reference count typically '1'
59 static inline void file_ref_init(file_ref_t
*ref
, unsigned long cnt
)
61 atomic_long_set(&ref
->refcnt
, cnt
- 1);
64 bool __file_ref_put(file_ref_t
*ref
, unsigned long cnt
);
67 * file_ref_get - Acquire one reference on a file
68 * @ref: Pointer to the reference count
70 * Similar to atomic_inc_not_zero() but saturates at FILE_REF_MAXREF.
72 * Provides full memory ordering.
74 * Return: False if the attempt to acquire a reference failed. This happens
75 * when the last reference has been put already. True if a reference
76 * was successfully acquired
78 static __always_inline __must_check
bool file_ref_get(file_ref_t
*ref
)
81 * Unconditionally increase the reference count with full
82 * ordering. The saturation and dead zones provide enough
85 * If this indicates negative the file in question the fail can
86 * be freed and immediately reused due to SLAB_TYPSAFE_BY_RCU.
87 * Hence, unconditionally altering the file reference count to
88 * e.g., reset the file reference count back to the middle of
89 * the deadzone risk end up marking someone else's file as dead
92 * It would be possible to do a careful:
94 * cnt = atomic_long_inc_return();
95 * if (likely(cnt >= 0))
98 * and then something like:
100 * if (cnt >= FILE_REF_RELEASE)
101 * atomic_long_try_cmpxchg(&ref->refcnt, &cnt, FILE_REF_DEAD),
103 * to set the value back to the middle of the deadzone. But it's
104 * practically impossible to go from FILE_REF_DEAD to
105 * FILE_REF_ONEREF. It would need 2305843009213693952/2^61
106 * file_ref_get()s to resurrect such a dead file.
108 return !atomic_long_add_negative(1, &ref
->refcnt
);
112 * file_ref_inc - Acquire one reference on a file
113 * @ref: Pointer to the reference count
115 * Acquire an additional reference on a file. Warns if the caller didn't
116 * already hold a reference.
118 static __always_inline
void file_ref_inc(file_ref_t
*ref
)
120 long prior
= atomic_long_fetch_inc_relaxed(&ref
->refcnt
);
121 WARN_ONCE(prior
< 0, "file_ref_inc() on a released file reference");
125 * file_ref_put -- Release a file reference
126 * @ref: Pointer to the reference count
128 * Provides release memory ordering, such that prior loads and stores
129 * are done before, and provides an acquire ordering on success such
130 * that free() must come after.
132 * Return: True if this was the last reference with no future references
133 * possible. This signals the caller that it can safely release
134 * the object which is protected by the reference counter.
135 * False if there are still active references or the put() raced
136 * with a concurrent get()/put() pair. Caller is not allowed to
137 * release the protected object.
139 static __always_inline __must_check
bool file_ref_put(file_ref_t
*ref
)
144 * While files are SLAB_TYPESAFE_BY_RCU and thus file_ref_put()
145 * calls don't risk UAFs when a file is recyclyed, it is still
146 * vulnerable to UAFs caused by freeing the whole slab page once
147 * it becomes unused. Prevent file_ref_put() from being
148 * preempted protects against this.
152 * Unconditionally decrease the reference count. The saturation
153 * and dead zones provide enough tolerance for this. If this
154 * fails then we need to handle the last reference drop and
155 * cases inside the saturation and dead zones.
157 cnt
= atomic_long_dec_return(&ref
->refcnt
);
160 return __file_ref_put(ref
, cnt
);
164 * file_ref_read - Read the number of file references
165 * @ref: Pointer to the reference count
167 * Return: The number of held references (0 ... N)
169 static inline unsigned long file_ref_read(file_ref_t
*ref
)
171 unsigned long c
= atomic_long_read(&ref
->refcnt
);
173 /* Return 0 if within the DEAD zone. */
174 return c
>= FILE_REF_RELEASED
? 0 : c
+ 1;