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