xref: /freebsd/sys/compat/linuxkpi/common/src/linux_rcu.c (revision 1f827dab9ec542a8872cd8b4b2e9407930b0463e)
11a01b4e5SHans Petter Selasky /*-
21a01b4e5SHans Petter Selasky  * Copyright (c) 2016 Matt Macy (mmacy@nextbsd.org)
31a01b4e5SHans Petter Selasky  * All rights reserved.
41a01b4e5SHans Petter Selasky  *
51a01b4e5SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
61a01b4e5SHans Petter Selasky  * modification, are permitted provided that the following conditions
71a01b4e5SHans Petter Selasky  * are met:
81a01b4e5SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
91a01b4e5SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
101a01b4e5SHans Petter Selasky  *    disclaimer.
111a01b4e5SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
121a01b4e5SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
131a01b4e5SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
141a01b4e5SHans Petter Selasky  *
151a01b4e5SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
161a01b4e5SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
171a01b4e5SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
181a01b4e5SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
191a01b4e5SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
201a01b4e5SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
211a01b4e5SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
221a01b4e5SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
231a01b4e5SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
241a01b4e5SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
251a01b4e5SHans Petter Selasky  */
261a01b4e5SHans Petter Selasky 
271a01b4e5SHans Petter Selasky #include <sys/cdefs.h>
281a01b4e5SHans Petter Selasky __FBSDID("$FreeBSD$");
291a01b4e5SHans Petter Selasky 
301a01b4e5SHans Petter Selasky #include <sys/types.h>
311a01b4e5SHans Petter Selasky #include <sys/systm.h>
321a01b4e5SHans Petter Selasky #include <sys/malloc.h>
331a01b4e5SHans Petter Selasky #include <sys/kernel.h>
341a01b4e5SHans Petter Selasky #include <sys/lock.h>
351a01b4e5SHans Petter Selasky #include <sys/mutex.h>
361a01b4e5SHans Petter Selasky #include <sys/proc.h>
371a01b4e5SHans Petter Selasky #include <sys/sched.h>
381a01b4e5SHans Petter Selasky #include <sys/smp.h>
391a01b4e5SHans Petter Selasky #include <sys/queue.h>
401a01b4e5SHans Petter Selasky #include <sys/taskqueue.h>
411a01b4e5SHans Petter Selasky 
421a01b4e5SHans Petter Selasky #include <ck_epoch.h>
431a01b4e5SHans Petter Selasky 
441a01b4e5SHans Petter Selasky #include <linux/rcupdate.h>
451a01b4e5SHans Petter Selasky #include <linux/srcu.h>
461a01b4e5SHans Petter Selasky #include <linux/slab.h>
471a01b4e5SHans Petter Selasky #include <linux/kernel.h>
481a01b4e5SHans Petter Selasky 
49*1f827dabSHans Petter Selasky struct callback_head;
50*1f827dabSHans Petter Selasky struct writer_epoch_record {
51*1f827dabSHans Petter Selasky 	ck_epoch_record_t epoch_record;
52*1f827dabSHans Petter Selasky 	struct mtx head_lock;
53*1f827dabSHans Petter Selasky 	struct mtx sync_lock;
541a01b4e5SHans Petter Selasky 	struct task task;
55*1f827dabSHans Petter Selasky 	STAILQ_HEAD(, callback_head) head;
56*1f827dabSHans Petter Selasky } __aligned(CACHE_LINE_SIZE);
57*1f827dabSHans Petter Selasky 
58*1f827dabSHans Petter Selasky struct callback_head {
59*1f827dabSHans Petter Selasky 	STAILQ_ENTRY(callback_head) entry;
60*1f827dabSHans Petter Selasky 	rcu_callback_t func;
61*1f827dabSHans Petter Selasky };
62*1f827dabSHans Petter Selasky 
63*1f827dabSHans Petter Selasky struct srcu_epoch_record {
64*1f827dabSHans Petter Selasky 	ck_epoch_record_t epoch_record;
65*1f827dabSHans Petter Selasky 	struct mtx read_lock;
66*1f827dabSHans Petter Selasky 	struct mtx sync_lock;
671a01b4e5SHans Petter Selasky };
681a01b4e5SHans Petter Selasky 
691a01b4e5SHans Petter Selasky /*
701a01b4e5SHans Petter Selasky  * Verify that "struct rcu_head" is big enough to hold "struct
711a01b4e5SHans Petter Selasky  * callback_head". This has been done to avoid having to add special
721a01b4e5SHans Petter Selasky  * compile flags for including ck_epoch.h to all clients of the
731a01b4e5SHans Petter Selasky  * LinuxKPI.
741a01b4e5SHans Petter Selasky  */
751a01b4e5SHans Petter Selasky CTASSERT(sizeof(struct rcu_head) >= sizeof(struct callback_head));
761a01b4e5SHans Petter Selasky 
77*1f827dabSHans Petter Selasky /*
78*1f827dabSHans Petter Selasky  * Verify that "epoch_record" is at beginning of "struct
79*1f827dabSHans Petter Selasky  * writer_epoch_record":
80*1f827dabSHans Petter Selasky  */
81*1f827dabSHans Petter Selasky CTASSERT(offsetof(struct writer_epoch_record, epoch_record) == 0);
82*1f827dabSHans Petter Selasky 
83*1f827dabSHans Petter Selasky /*
84*1f827dabSHans Petter Selasky  * Verify that "epoch_record" is at beginning of "struct
85*1f827dabSHans Petter Selasky  * srcu_epoch_record":
86*1f827dabSHans Petter Selasky  */
87*1f827dabSHans Petter Selasky CTASSERT(offsetof(struct srcu_epoch_record, epoch_record) == 0);
88*1f827dabSHans Petter Selasky 
891a01b4e5SHans Petter Selasky static ck_epoch_t linux_epoch;
901a01b4e5SHans Petter Selasky static MALLOC_DEFINE(M_LRCU, "lrcu", "Linux RCU");
91*1f827dabSHans Petter Selasky static DPCPU_DEFINE(ck_epoch_record_t *, linux_reader_epoch_record);
92*1f827dabSHans Petter Selasky static DPCPU_DEFINE(struct writer_epoch_record *, linux_writer_epoch_record);
93*1f827dabSHans Petter Selasky 
94*1f827dabSHans Petter Selasky static void linux_rcu_cleaner_func(void *, int);
951a01b4e5SHans Petter Selasky 
961a01b4e5SHans Petter Selasky static void
971a01b4e5SHans Petter Selasky linux_rcu_runtime_init(void *arg __unused)
981a01b4e5SHans Petter Selasky {
991a01b4e5SHans Petter Selasky 	int i;
1001a01b4e5SHans Petter Selasky 
1011a01b4e5SHans Petter Selasky 	ck_epoch_init(&linux_epoch);
1021a01b4e5SHans Petter Selasky 
103*1f827dabSHans Petter Selasky 	/* setup reader records */
1041a01b4e5SHans Petter Selasky 	CPU_FOREACH(i) {
105*1f827dabSHans Petter Selasky 		ck_epoch_record_t *record;
106*1f827dabSHans Petter Selasky 
1071a01b4e5SHans Petter Selasky 		record = malloc(sizeof(*record), M_LRCU, M_WAITOK | M_ZERO);
1081a01b4e5SHans Petter Selasky 		ck_epoch_register(&linux_epoch, record);
109*1f827dabSHans Petter Selasky 
110*1f827dabSHans Petter Selasky 		DPCPU_ID_SET(i, linux_reader_epoch_record, record);
1111a01b4e5SHans Petter Selasky 	}
1121a01b4e5SHans Petter Selasky 
113*1f827dabSHans Petter Selasky 	/* setup writer records */
114*1f827dabSHans Petter Selasky 	CPU_FOREACH(i) {
115*1f827dabSHans Petter Selasky 		struct writer_epoch_record *record;
116*1f827dabSHans Petter Selasky 
1171a01b4e5SHans Petter Selasky 		record = malloc(sizeof(*record), M_LRCU, M_WAITOK | M_ZERO);
118*1f827dabSHans Petter Selasky 
119*1f827dabSHans Petter Selasky 		ck_epoch_register(&linux_epoch, &record->epoch_record);
120*1f827dabSHans Petter Selasky 		mtx_init(&record->head_lock, "LRCU-HEAD", NULL, MTX_DEF);
121*1f827dabSHans Petter Selasky 		mtx_init(&record->sync_lock, "LRCU-SYNC", NULL, MTX_DEF);
122*1f827dabSHans Petter Selasky 		TASK_INIT(&record->task, 0, linux_rcu_cleaner_func, record);
123*1f827dabSHans Petter Selasky 		STAILQ_INIT(&record->head);
124*1f827dabSHans Petter Selasky 
125*1f827dabSHans Petter Selasky 		DPCPU_ID_SET(i, linux_writer_epoch_record, record);
1261a01b4e5SHans Petter Selasky 	}
1271a01b4e5SHans Petter Selasky }
1281a01b4e5SHans Petter Selasky SYSINIT(linux_rcu_runtime, SI_SUB_LOCK, SI_ORDER_SECOND, linux_rcu_runtime_init, NULL);
1291a01b4e5SHans Petter Selasky 
1301a01b4e5SHans Petter Selasky static void
1311a01b4e5SHans Petter Selasky linux_rcu_runtime_uninit(void *arg __unused)
1321a01b4e5SHans Petter Selasky {
133*1f827dabSHans Petter Selasky 	ck_stack_entry_t *cursor;
134*1f827dabSHans Petter Selasky 	ck_stack_entry_t *next;
1351a01b4e5SHans Petter Selasky 	int i;
1361a01b4e5SHans Petter Selasky 
137*1f827dabSHans Petter Selasky 	/* make sure all callbacks have been called */
138*1f827dabSHans Petter Selasky 	linux_rcu_barrier();
1391a01b4e5SHans Petter Selasky 
140*1f827dabSHans Petter Selasky 	/* destroy all writer record mutexes */
1411a01b4e5SHans Petter Selasky 	CPU_FOREACH(i) {
142*1f827dabSHans Petter Selasky 		struct writer_epoch_record *record;
143*1f827dabSHans Petter Selasky 
144*1f827dabSHans Petter Selasky 		record = DPCPU_ID_GET(i, linux_writer_epoch_record);
145*1f827dabSHans Petter Selasky 
146*1f827dabSHans Petter Selasky 		mtx_destroy(&record->head_lock);
147*1f827dabSHans Petter Selasky 		mtx_destroy(&record->sync_lock);
148*1f827dabSHans Petter Selasky 	}
149*1f827dabSHans Petter Selasky 
150*1f827dabSHans Petter Selasky 	/* free all registered reader and writer records */
151*1f827dabSHans Petter Selasky 	CK_STACK_FOREACH_SAFE(&linux_epoch.records, cursor, next) {
152*1f827dabSHans Petter Selasky 		ck_epoch_record_t *record;
153*1f827dabSHans Petter Selasky 
154*1f827dabSHans Petter Selasky 		record = container_of(cursor,
155*1f827dabSHans Petter Selasky 		    struct ck_epoch_record, record_next);
1561a01b4e5SHans Petter Selasky 		free(record, M_LRCU);
1571a01b4e5SHans Petter Selasky 	}
1581a01b4e5SHans Petter Selasky }
1591a01b4e5SHans Petter Selasky SYSUNINIT(linux_rcu_runtime, SI_SUB_LOCK, SI_ORDER_SECOND, linux_rcu_runtime_uninit, NULL);
1601a01b4e5SHans Petter Selasky 
161*1f827dabSHans Petter Selasky static inline struct srcu_epoch_record *
162*1f827dabSHans Petter Selasky linux_srcu_get_record(void)
1631a01b4e5SHans Petter Selasky {
164*1f827dabSHans Petter Selasky 	struct srcu_epoch_record *record;
1651a01b4e5SHans Petter Selasky 
166*1f827dabSHans Petter Selasky 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
167*1f827dabSHans Petter Selasky 	    "linux_srcu_get_record() might sleep");
168*1f827dabSHans Petter Selasky 
169*1f827dabSHans Petter Selasky 	/*
170*1f827dabSHans Petter Selasky 	 * NOTE: The only records that are unregistered and can be
171*1f827dabSHans Petter Selasky 	 * recycled are srcu_epoch_records.
172*1f827dabSHans Petter Selasky 	 */
173*1f827dabSHans Petter Selasky 	record = (struct srcu_epoch_record *)ck_epoch_recycle(&linux_epoch);
174*1f827dabSHans Petter Selasky 	if (__predict_true(record != NULL))
1751a01b4e5SHans Petter Selasky 		return (record);
1761a01b4e5SHans Petter Selasky 
1771a01b4e5SHans Petter Selasky 	record = malloc(sizeof(*record), M_LRCU, M_WAITOK | M_ZERO);
178*1f827dabSHans Petter Selasky 	mtx_init(&record->read_lock, "SRCU-READ", NULL, MTX_DEF | MTX_NOWITNESS);
179*1f827dabSHans Petter Selasky 	mtx_init(&record->sync_lock, "SRCU-SYNC", NULL, MTX_DEF | MTX_NOWITNESS);
180*1f827dabSHans Petter Selasky 	ck_epoch_register(&linux_epoch, &record->epoch_record);
181*1f827dabSHans Petter Selasky 
1821a01b4e5SHans Petter Selasky 	return (record);
1831a01b4e5SHans Petter Selasky }
1841a01b4e5SHans Petter Selasky 
185*1f827dabSHans Petter Selasky static inline void
186*1f827dabSHans Petter Selasky linux_rcu_synchronize_sub(struct writer_epoch_record *record)
1871a01b4e5SHans Petter Selasky {
188*1f827dabSHans Petter Selasky 
189*1f827dabSHans Petter Selasky 	/* protect access to epoch_record */
190*1f827dabSHans Petter Selasky 	mtx_lock(&record->sync_lock);
191*1f827dabSHans Petter Selasky 	ck_epoch_synchronize(&record->epoch_record);
192*1f827dabSHans Petter Selasky 	mtx_unlock(&record->sync_lock);
193*1f827dabSHans Petter Selasky }
194*1f827dabSHans Petter Selasky 
195*1f827dabSHans Petter Selasky static void
196*1f827dabSHans Petter Selasky linux_rcu_cleaner_func(void *context, int pending __unused)
197*1f827dabSHans Petter Selasky {
198*1f827dabSHans Petter Selasky 	struct writer_epoch_record *record;
1991a01b4e5SHans Petter Selasky 	struct callback_head *rcu;
200*1f827dabSHans Petter Selasky 	STAILQ_HEAD(, callback_head) head;
201*1f827dabSHans Petter Selasky 
202*1f827dabSHans Petter Selasky 	record = context;
203*1f827dabSHans Petter Selasky 
204*1f827dabSHans Petter Selasky 	/* move current callbacks into own queue */
205*1f827dabSHans Petter Selasky 	mtx_lock(&record->head_lock);
206*1f827dabSHans Petter Selasky 	STAILQ_INIT(&head);
207*1f827dabSHans Petter Selasky 	STAILQ_CONCAT(&head, &record->head);
208*1f827dabSHans Petter Selasky 	mtx_unlock(&record->head_lock);
209*1f827dabSHans Petter Selasky 
210*1f827dabSHans Petter Selasky 	/* synchronize */
211*1f827dabSHans Petter Selasky 	linux_rcu_synchronize_sub(record);
212*1f827dabSHans Petter Selasky 
213*1f827dabSHans Petter Selasky 	/* dispatch all callbacks, if any */
214*1f827dabSHans Petter Selasky 	while ((rcu = STAILQ_FIRST(&head)) != NULL) {
2151a01b4e5SHans Petter Selasky 		uintptr_t offset;
2161a01b4e5SHans Petter Selasky 
217*1f827dabSHans Petter Selasky 		STAILQ_REMOVE_HEAD(&head, entry);
2181a01b4e5SHans Petter Selasky 
2191a01b4e5SHans Petter Selasky 		offset = (uintptr_t)rcu->func;
2201a01b4e5SHans Petter Selasky 
2211a01b4e5SHans Petter Selasky 		if (offset < LINUX_KFREE_RCU_OFFSET_MAX)
2221a01b4e5SHans Petter Selasky 			kfree((char *)rcu - offset);
2231a01b4e5SHans Petter Selasky 		else
2241a01b4e5SHans Petter Selasky 			rcu->func((struct rcu_head *)rcu);
2251a01b4e5SHans Petter Selasky 	}
2261a01b4e5SHans Petter Selasky }
2271a01b4e5SHans Petter Selasky 
2281a01b4e5SHans Petter Selasky void
2291a01b4e5SHans Petter Selasky linux_rcu_read_lock(void)
2301a01b4e5SHans Petter Selasky {
2311a01b4e5SHans Petter Selasky 	ck_epoch_record_t *record;
2321a01b4e5SHans Petter Selasky 
233*1f827dabSHans Petter Selasky 	/*
234*1f827dabSHans Petter Selasky 	 * Pin thread to current CPU so that the unlock code gets the
235*1f827dabSHans Petter Selasky 	 * same per-CPU reader epoch record:
236*1f827dabSHans Petter Selasky 	 */
2371a01b4e5SHans Petter Selasky 	sched_pin();
2381a01b4e5SHans Petter Selasky 
239*1f827dabSHans Petter Selasky 	record = DPCPU_GET(linux_reader_epoch_record);
240*1f827dabSHans Petter Selasky 
241*1f827dabSHans Petter Selasky 	/*
242*1f827dabSHans Petter Selasky 	 * Use a critical section to prevent recursion inside
243*1f827dabSHans Petter Selasky 	 * ck_epoch_begin(). Else this function supports recursion.
244*1f827dabSHans Petter Selasky 	 */
245*1f827dabSHans Petter Selasky 	critical_enter();
2461a01b4e5SHans Petter Selasky 	ck_epoch_begin(record, NULL);
247*1f827dabSHans Petter Selasky 	critical_exit();
2481a01b4e5SHans Petter Selasky }
2491a01b4e5SHans Petter Selasky 
2501a01b4e5SHans Petter Selasky void
2511a01b4e5SHans Petter Selasky linux_rcu_read_unlock(void)
2521a01b4e5SHans Petter Selasky {
2531a01b4e5SHans Petter Selasky 	ck_epoch_record_t *record;
2541a01b4e5SHans Petter Selasky 
255*1f827dabSHans Petter Selasky 	record = DPCPU_GET(linux_reader_epoch_record);
256*1f827dabSHans Petter Selasky 
257*1f827dabSHans Petter Selasky 	/*
258*1f827dabSHans Petter Selasky 	 * Use a critical section to prevent recursion inside
259*1f827dabSHans Petter Selasky 	 * ck_epoch_end(). Else this function supports recursion.
260*1f827dabSHans Petter Selasky 	 */
261*1f827dabSHans Petter Selasky 	critical_enter();
2621a01b4e5SHans Petter Selasky 	ck_epoch_end(record, NULL);
263*1f827dabSHans Petter Selasky 	critical_exit();
264*1f827dabSHans Petter Selasky 
2651a01b4e5SHans Petter Selasky 	sched_unpin();
2661a01b4e5SHans Petter Selasky }
2671a01b4e5SHans Petter Selasky 
2681a01b4e5SHans Petter Selasky void
2691a01b4e5SHans Petter Selasky linux_synchronize_rcu(void)
2701a01b4e5SHans Petter Selasky {
271*1f827dabSHans Petter Selasky 	linux_rcu_synchronize_sub(DPCPU_GET(linux_writer_epoch_record));
2721a01b4e5SHans Petter Selasky }
2731a01b4e5SHans Petter Selasky 
2741a01b4e5SHans Petter Selasky void
2751a01b4e5SHans Petter Selasky linux_rcu_barrier(void)
2761a01b4e5SHans Petter Selasky {
277*1f827dabSHans Petter Selasky 	int i;
2781a01b4e5SHans Petter Selasky 
279*1f827dabSHans Petter Selasky 	CPU_FOREACH(i) {
280*1f827dabSHans Petter Selasky 		struct writer_epoch_record *record;
281*1f827dabSHans Petter Selasky 
282*1f827dabSHans Petter Selasky 		record = DPCPU_ID_GET(i, linux_writer_epoch_record);
283*1f827dabSHans Petter Selasky 
284*1f827dabSHans Petter Selasky 		linux_rcu_synchronize_sub(record);
285*1f827dabSHans Petter Selasky 
286*1f827dabSHans Petter Selasky 		/* wait for callbacks to complete */
287*1f827dabSHans Petter Selasky 		taskqueue_drain(taskqueue_fast, &record->task);
288*1f827dabSHans Petter Selasky 	}
2891a01b4e5SHans Petter Selasky }
2901a01b4e5SHans Petter Selasky 
2911a01b4e5SHans Petter Selasky void
2921a01b4e5SHans Petter Selasky linux_call_rcu(struct rcu_head *context, rcu_callback_t func)
2931a01b4e5SHans Petter Selasky {
294*1f827dabSHans Petter Selasky 	struct callback_head *rcu = (struct callback_head *)context;
295*1f827dabSHans Petter Selasky 	struct writer_epoch_record *record;
2961a01b4e5SHans Petter Selasky 
297*1f827dabSHans Petter Selasky 	record = DPCPU_GET(linux_writer_epoch_record);
2981a01b4e5SHans Petter Selasky 
299*1f827dabSHans Petter Selasky 	mtx_lock(&record->head_lock);
300*1f827dabSHans Petter Selasky 	rcu->func = func;
301*1f827dabSHans Petter Selasky 	STAILQ_INSERT_TAIL(&record->head, rcu, entry);
302*1f827dabSHans Petter Selasky 	taskqueue_enqueue(taskqueue_fast, &record->task);
303*1f827dabSHans Petter Selasky 	mtx_unlock(&record->head_lock);
3041a01b4e5SHans Petter Selasky }
3051a01b4e5SHans Petter Selasky 
3061a01b4e5SHans Petter Selasky int
3071a01b4e5SHans Petter Selasky init_srcu_struct(struct srcu_struct *srcu)
3081a01b4e5SHans Petter Selasky {
309*1f827dabSHans Petter Selasky 	struct srcu_epoch_record *record;
3101a01b4e5SHans Petter Selasky 
311*1f827dabSHans Petter Selasky 	record = linux_srcu_get_record();
3121a01b4e5SHans Petter Selasky 	srcu->ss_epoch_record = record;
3131a01b4e5SHans Petter Selasky 	return (0);
3141a01b4e5SHans Petter Selasky }
3151a01b4e5SHans Petter Selasky 
3161a01b4e5SHans Petter Selasky void
3171a01b4e5SHans Petter Selasky cleanup_srcu_struct(struct srcu_struct *srcu)
3181a01b4e5SHans Petter Selasky {
319*1f827dabSHans Petter Selasky 	struct srcu_epoch_record *record;
3201a01b4e5SHans Petter Selasky 
3211a01b4e5SHans Petter Selasky 	record = srcu->ss_epoch_record;
3221a01b4e5SHans Petter Selasky 	srcu->ss_epoch_record = NULL;
323*1f827dabSHans Petter Selasky 
324*1f827dabSHans Petter Selasky 	ck_epoch_unregister(&record->epoch_record);
3251a01b4e5SHans Petter Selasky }
3261a01b4e5SHans Petter Selasky 
3271a01b4e5SHans Petter Selasky int
3281a01b4e5SHans Petter Selasky srcu_read_lock(struct srcu_struct *srcu)
3291a01b4e5SHans Petter Selasky {
330*1f827dabSHans Petter Selasky 	struct srcu_epoch_record *record;
331*1f827dabSHans Petter Selasky 
332*1f827dabSHans Petter Selasky 	record = srcu->ss_epoch_record;
333*1f827dabSHans Petter Selasky 
334*1f827dabSHans Petter Selasky 	mtx_lock(&record->read_lock);
335*1f827dabSHans Petter Selasky 	ck_epoch_begin(&record->epoch_record, NULL);
336*1f827dabSHans Petter Selasky 	mtx_unlock(&record->read_lock);
337*1f827dabSHans Petter Selasky 
3381a01b4e5SHans Petter Selasky 	return (0);
3391a01b4e5SHans Petter Selasky }
3401a01b4e5SHans Petter Selasky 
3411a01b4e5SHans Petter Selasky void
3421a01b4e5SHans Petter Selasky srcu_read_unlock(struct srcu_struct *srcu, int key __unused)
3431a01b4e5SHans Petter Selasky {
344*1f827dabSHans Petter Selasky 	struct srcu_epoch_record *record;
345*1f827dabSHans Petter Selasky 
346*1f827dabSHans Petter Selasky 	record = srcu->ss_epoch_record;
347*1f827dabSHans Petter Selasky 
348*1f827dabSHans Petter Selasky 	mtx_lock(&record->read_lock);
349*1f827dabSHans Petter Selasky 	ck_epoch_end(&record->epoch_record, NULL);
350*1f827dabSHans Petter Selasky 	mtx_unlock(&record->read_lock);
3511a01b4e5SHans Petter Selasky }
3521a01b4e5SHans Petter Selasky 
3531a01b4e5SHans Petter Selasky void
3541a01b4e5SHans Petter Selasky synchronize_srcu(struct srcu_struct *srcu)
3551a01b4e5SHans Petter Selasky {
356*1f827dabSHans Petter Selasky 	struct srcu_epoch_record *record;
357*1f827dabSHans Petter Selasky 
358*1f827dabSHans Petter Selasky 	record = srcu->ss_epoch_record;
359*1f827dabSHans Petter Selasky 
360*1f827dabSHans Petter Selasky 	mtx_lock(&record->sync_lock);
361*1f827dabSHans Petter Selasky 	ck_epoch_synchronize(&record->epoch_record);
362*1f827dabSHans Petter Selasky 	mtx_unlock(&record->sync_lock);
363*1f827dabSHans Petter Selasky }
364*1f827dabSHans Petter Selasky 
365*1f827dabSHans Petter Selasky void
366*1f827dabSHans Petter Selasky srcu_barrier(struct srcu_struct *srcu)
367*1f827dabSHans Petter Selasky {
368*1f827dabSHans Petter Selasky 	struct srcu_epoch_record *record;
369*1f827dabSHans Petter Selasky 
370*1f827dabSHans Petter Selasky 	record = srcu->ss_epoch_record;
371*1f827dabSHans Petter Selasky 
372*1f827dabSHans Petter Selasky 	mtx_lock(&record->sync_lock);
373*1f827dabSHans Petter Selasky 	ck_epoch_barrier(&record->epoch_record);
374*1f827dabSHans Petter Selasky 	mtx_unlock(&record->sync_lock);
3751a01b4e5SHans Petter Selasky }
376