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

Configure Feed

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

ucount: use rcuref_t for reference counting

Use rcuref_t for reference counting. This eliminates the cmpxchg loop in
the get and put path. This also eliminates the need to acquire the lock
in the put path because once the final user returns the reference, it can
no longer be obtained anymore.

Use rcuref_t for reference counting.

Link: https://lkml.kernel.org/r/20250203150525.456525-5-bigeasy@linutronix.de
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Paul E. McKenney <paulmck@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Boqun Feng <boqun.feng@gmail.com>
Cc: Joel Fernandes <joel@joelfernandes.org>
Cc: Josh Triplett <josh@joshtriplett.org>
Cc: Lai jiangshan <jiangshanlai@gmail.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Cc: Mengen Sun <mengensun@tencent.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: "Uladzislau Rezki (Sony)" <urezki@gmail.com>
Cc: YueHong Wu <yuehongwu@tencent.com>
Cc: Zqiang <qiang.zhang1211@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>

authored by

Sebastian Andrzej Siewior and committed by
Andrew Morton
b4dc0bee 5f01a22c

+14 -13
+9 -2
include/linux/user_namespace.h
··· 8 8 #include <linux/rculist_nulls.h> 9 9 #include <linux/sched.h> 10 10 #include <linux/workqueue.h> 11 + #include <linux/rcuref.h> 11 12 #include <linux/rwsem.h> 12 13 #include <linux/sysctl.h> 13 14 #include <linux/err.h> ··· 121 120 struct user_namespace *ns; 122 121 kuid_t uid; 123 122 struct rcu_head rcu; 124 - atomic_t count; 123 + rcuref_t count; 125 124 atomic_long_t ucount[UCOUNT_COUNTS]; 126 125 atomic_long_t rlimit[UCOUNT_RLIMIT_COUNTS]; 127 126 }; ··· 134 133 struct ucounts *inc_ucount(struct user_namespace *ns, kuid_t uid, enum ucount_type type); 135 134 void dec_ucount(struct ucounts *ucounts, enum ucount_type type); 136 135 struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid); 137 - struct ucounts * __must_check get_ucounts(struct ucounts *ucounts); 138 136 void put_ucounts(struct ucounts *ucounts); 137 + 138 + static inline struct ucounts * __must_check get_ucounts(struct ucounts *ucounts) 139 + { 140 + if (rcuref_get(&ucounts->count)) 141 + return ucounts; 142 + return NULL; 143 + } 139 144 140 145 static inline long get_rlimit_value(struct ucounts *ucounts, enum rlimit_type type) 141 146 {
+5 -11
kernel/ucount.c
··· 11 11 struct ucounts init_ucounts = { 12 12 .ns = &init_user_ns, 13 13 .uid = GLOBAL_ROOT_UID, 14 - .count = ATOMIC_INIT(1), 14 + .count = RCUREF_INIT(1), 15 15 }; 16 16 17 17 #define UCOUNTS_HASHTABLE_BITS 10 ··· 138 138 guard(rcu)(); 139 139 hlist_nulls_for_each_entry_rcu(ucounts, pos, hashent, node) { 140 140 if (uid_eq(ucounts->uid, uid) && (ucounts->ns == ns)) { 141 - if (atomic_inc_not_zero(&ucounts->count)) 141 + if (rcuref_get(&ucounts->count)) 142 142 return ucounts; 143 143 } 144 144 } ··· 152 152 spin_lock_irq(&ucounts_lock); 153 153 hlist_nulls_add_head_rcu(&ucounts->node, hashent); 154 154 spin_unlock_irq(&ucounts_lock); 155 - } 156 - 157 - struct ucounts *get_ucounts(struct ucounts *ucounts) 158 - { 159 - if (atomic_inc_not_zero(&ucounts->count)) 160 - return ucounts; 161 - return NULL; 162 155 } 163 156 164 157 struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid) ··· 169 176 170 177 new->ns = ns; 171 178 new->uid = uid; 172 - atomic_set(&new->count, 1); 179 + rcuref_init(&new->count, 1); 173 180 174 181 spin_lock_irq(&ucounts_lock); 175 182 ucounts = find_ucounts(ns, uid, hashent); ··· 189 196 { 190 197 unsigned long flags; 191 198 192 - if (atomic_dec_and_lock_irqsave(&ucounts->count, &ucounts_lock, flags)) { 199 + if (rcuref_put(&ucounts->count)) { 200 + spin_lock_irqsave(&ucounts_lock, flags); 193 201 hlist_nulls_del_rcu(&ucounts->node); 194 202 spin_unlock_irqrestore(&ucounts_lock, flags); 195 203