linux_rcu.c revision 1.6 1 /* $NetBSD: linux_rcu.c,v 1.6 2021/12/19 12:40:03 riastradh Exp $ */
2
3 /*-
4 * Copyright (c) 2018 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Taylor R. Campbell.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: linux_rcu.c,v 1.6 2021/12/19 12:40:03 riastradh Exp $");
34
35 #include <sys/param.h>
36 #include <sys/types.h>
37
38 #include <sys/condvar.h>
39 #include <sys/cpu.h>
40 #include <sys/kthread.h>
41 #include <sys/lockdebug.h>
42 #include <sys/mutex.h>
43 #include <sys/sdt.h>
44 #include <sys/xcall.h>
45
46 #include <linux/rcupdate.h>
47 #include <linux/slab.h>
48
49 SDT_PROBE_DEFINE0(sdt, linux, rcu, synchronize__start);
50 SDT_PROBE_DEFINE1(sdt, linux, rcu, synchronize__cpu, "unsigned"/*cpu*/);
51 SDT_PROBE_DEFINE0(sdt, linux, rcu, synchronize__done);
52 SDT_PROBE_DEFINE0(sdt, linux, rcu, barrier__start);
53 SDT_PROBE_DEFINE0(sdt, linux, rcu, barrier__done);
54 SDT_PROBE_DEFINE2(sdt, linux, rcu, call__queue,
55 "struct rcu_head *"/*head*/, "void (*)(struct rcu_head *)"/*callback*/);
56 SDT_PROBE_DEFINE2(sdt, linux, rcu, call__run,
57 "struct rcu_head *"/*head*/, "void (*)(struct rcu_head *)"/*callback*/);
58 SDT_PROBE_DEFINE2(sdt, linux, rcu, call__done,
59 "struct rcu_head *"/*head*/, "void (*)(struct rcu_head *)"/*callback*/);
60 SDT_PROBE_DEFINE2(sdt, linux, rcu, kfree__queue,
61 "struct rcu_head *"/*head*/, "void *"/*obj*/);
62 SDT_PROBE_DEFINE2(sdt, linux, rcu, kfree__free,
63 "struct rcu_head *"/*head*/, "void *"/*obj*/);
64 SDT_PROBE_DEFINE2(sdt, linux, rcu, kfree__done,
65 "struct rcu_head *"/*head*/, "void *"/*obj*/);
66
67 static struct {
68 kmutex_t lock;
69 kcondvar_t cv;
70 struct rcu_head *first_callback;
71 struct rcu_head *first_kfree;
72 struct lwp *lwp;
73 uint64_t gen;
74 bool dying;
75 } gc __cacheline_aligned;
76
77 static void
78 synchronize_rcu_xc(void *a, void *b)
79 {
80
81 SDT_PROBE1(sdt, linux, rcu, synchronize__cpu, cpu_index(curcpu()));
82 }
83
84 /*
85 * synchronize_rcu()
86 *
87 * Wait for any pending RCU read section on every CPU to complete
88 * by triggering on every CPU activity that is blocked by an RCU
89 * read section.
90 *
91 * May sleep. (Practically guaranteed to sleep!)
92 */
93 void
94 synchronize_rcu(void)
95 {
96
97 SDT_PROBE0(sdt, linux, rcu, synchronize__start);
98 xc_wait(xc_broadcast(0, &synchronize_rcu_xc, NULL, NULL));
99 SDT_PROBE0(sdt, linux, rcu, synchronize__done);
100 }
101
102 /*
103 * synchronize_rcu_expedited()
104 *
105 * Wait for any pending RCU read section on every CPU to complete
106 * by triggering on every CPU activity that is blocked by an RCU
107 * read section. Try to get an answer faster than
108 * synchronize_rcu, at the cost of more activity triggered on
109 * other CPUs.
110 *
111 * May sleep. (Practically guaranteed to sleep!)
112 */
113 void
114 synchronize_rcu_expedited(void)
115 {
116
117 synchronize_rcu();
118 }
119
120 /*
121 * cookie = get_state_synchronize_rcu(), cond_synchronize_rcu(cookie)
122 *
123 * Optimization for synchronize_rcu -- skip if it has already
124 * happened between get_state_synchronize_rcu and
125 * cond_synchronize_rcu. get_state_synchronize_rcu implies a full
126 * SMP memory barrier (membar_sync).
127 */
128 unsigned long
129 get_state_synchronize_rcu(void)
130 {
131
132 membar_sync();
133 return 0;
134 }
135
136 void
137 cond_synchronize_rcu(unsigned long cookie)
138 {
139
140 synchronize_rcu();
141 }
142
143 /*
144 * rcu_barrier()
145 *
146 * Wait for all pending RCU callbacks to complete.
147 *
148 * Does not imply, and is not implied by, synchronize_rcu.
149 */
150 void
151 rcu_barrier(void)
152 {
153 uint64_t gen;
154
155 SDT_PROBE0(sdt, linux, rcu, barrier__start);
156 mutex_enter(&gc.lock);
157 if (gc.first_callback != NULL || gc.first_kfree != NULL) {
158 gen = gc.gen;
159 do {
160 cv_wait(&gc.cv, &gc.lock);
161 } while (gc.gen == gen);
162 }
163 mutex_exit(&gc.lock);
164 SDT_PROBE0(sdt, linux, rcu, barrier__done);
165 }
166
167 /*
168 * call_rcu(head, callback)
169 *
170 * Arrange to call callback(head) after any pending RCU read
171 * sections on every CPU is complete. Return immediately.
172 */
173 void
174 call_rcu(struct rcu_head *head, void (*callback)(struct rcu_head *))
175 {
176
177 head->rcuh_u.callback = callback;
178
179 mutex_enter(&gc.lock);
180 head->rcuh_next = gc.first_callback;
181 gc.first_callback = head;
182 cv_broadcast(&gc.cv);
183 SDT_PROBE2(sdt, linux, rcu, call__queue, head, callback);
184 mutex_exit(&gc.lock);
185 }
186
187 /*
188 * _kfree_rcu(head, obj)
189 *
190 * kfree_rcu helper: schedule kfree(obj) using head for storage.
191 */
192 void
193 _kfree_rcu(struct rcu_head *head, void *obj)
194 {
195
196 LOCKDEBUG_MEM_CHECK(obj, ((struct linux_malloc *)obj - 1)->lm_size);
197
198 head->rcuh_u.obj = obj;
199
200 mutex_enter(&gc.lock);
201 head->rcuh_next = gc.first_kfree;
202 gc.first_kfree = head;
203 cv_broadcast(&gc.cv);
204 SDT_PROBE2(sdt, linux, rcu, kfree__queue, head, obj);
205 mutex_exit(&gc.lock);
206 }
207
208 static void
209 gc_thread(void *cookie)
210 {
211 struct rcu_head *head_callback, *head_kfree, *head, *next;
212
213 mutex_enter(&gc.lock);
214 for (;;) {
215 /* Start with no work. */
216 bool work = false;
217
218 /* Grab the list of callbacks. */
219 if ((head_callback = gc.first_callback) != NULL) {
220 gc.first_callback = NULL;
221 work = true;
222 }
223
224 /* Grab the list of objects to kfree. */
225 if ((head_kfree = gc.first_kfree) != NULL) {
226 gc.first_kfree = NULL;
227 work = true;
228 }
229
230 /*
231 * If no work, then either stop, if we're dying, or
232 * wait for work, if not.
233 */
234 if (!work) {
235 if (gc.dying)
236 break;
237 cv_wait(&gc.cv, &gc.lock);
238 continue;
239 }
240
241 /* We have work to do. Drop the lock to do it. */
242 mutex_exit(&gc.lock);
243
244 /* Wait for activity on all CPUs. */
245 synchronize_rcu();
246
247 /* Call the callbacks. */
248 for (head = head_callback; head != NULL; head = next) {
249 void (*callback)(struct rcu_head *) =
250 head->rcuh_u.callback;
251 next = head->rcuh_next;
252 SDT_PROBE2(sdt, linux, rcu, call__run,
253 head, callback);
254 (*callback)(head);
255 /*
256 * Can't dereference head or invoke
257 * callback after this point.
258 */
259 SDT_PROBE2(sdt, linux, rcu, call__done,
260 head, callback);
261 }
262
263 /* Free the objects to kfree. */
264 for (head = head_kfree; head != NULL; head = next) {
265 void *obj = head->rcuh_u.obj;
266 next = head->rcuh_next;
267 SDT_PROBE2(sdt, linux, rcu, kfree__free, head, obj);
268 kfree(obj);
269 /* Can't dereference head or obj after this point. */
270 SDT_PROBE2(sdt, linux, rcu, kfree__done, head, obj);
271 }
272
273 /* Return to the lock. */
274 mutex_enter(&gc.lock);
275
276 /* Finished a batch of work. Notify rcu_barrier. */
277 gc.gen++;
278 cv_broadcast(&gc.cv);
279
280 /*
281 * Limit ourselves to one batch per tick, in an attempt
282 * to make the batches larger.
283 *
284 * XXX We should maybe also limit the size of each
285 * batch.
286 */
287 (void)kpause("lxrcubat", /*intr*/false, /*timo*/1, &gc.lock);
288 }
289 KASSERT(gc.first_callback == NULL);
290 KASSERT(gc.first_kfree == NULL);
291 mutex_exit(&gc.lock);
292
293 kthread_exit(0);
294 }
295
296 void
297 init_rcu_head(struct rcu_head *head)
298 {
299 }
300
301 void
302 destroy_rcu_head(struct rcu_head *head)
303 {
304 }
305
306 int
307 linux_rcu_gc_init(void)
308 {
309 int error;
310
311 mutex_init(&gc.lock, MUTEX_DEFAULT, IPL_VM);
312 cv_init(&gc.cv, "lnxrcugc");
313 gc.first_callback = NULL;
314 gc.first_kfree = NULL;
315 gc.gen = 0;
316 gc.dying = false;
317
318 error = kthread_create(PRI_NONE,
319 KTHREAD_MPSAFE|KTHREAD_TS|KTHREAD_MUSTJOIN, NULL, &gc_thread, NULL,
320 &gc.lwp, "lnxrcugc");
321 if (error)
322 goto fail;
323
324 /* Success! */
325 return 0;
326
327 fail: cv_destroy(&gc.cv);
328 mutex_destroy(&gc.lock);
329 return error;
330 }
331
332 void
333 linux_rcu_gc_fini(void)
334 {
335
336 mutex_enter(&gc.lock);
337 gc.dying = true;
338 cv_broadcast(&gc.cv);
339 mutex_exit(&gc.lock);
340
341 kthread_join(gc.lwp);
342 gc.lwp = NULL;
343 KASSERT(gc.first_callback == NULL);
344 KASSERT(gc.first_kfree == NULL);
345 cv_destroy(&gc.cv);
346 mutex_destroy(&gc.lock);
347 }
348