rcu_sync: Add CONFIG_PROVE_RCU checks
[deliverable/linux.git] / kernel / rcu / sync.c
CommitLineData
cc44ca84
ON
1/*
2 * RCU-based infrastructure for lightweight reader-writer locking
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, you can access it online at
16 * http://www.gnu.org/licenses/gpl-2.0.html.
17 *
18 * Copyright (c) 2015, Red Hat, Inc.
19 *
20 * Author: Oleg Nesterov <oleg@redhat.com>
21 */
22
23#include <linux/rcu_sync.h>
24#include <linux/sched.h>
25
3a518b76
ON
26#ifdef CONFIG_PROVE_RCU
27#define __INIT_HELD(func) .held = func,
28#else
29#define __INIT_HELD(func)
30#endif
31
82e8c565
ON
32static const struct {
33 void (*sync)(void);
34 void (*call)(struct rcu_head *, void (*)(struct rcu_head *));
3a518b76
ON
35#ifdef CONFIG_PROVE_RCU
36 int (*held)(void);
37#endif
82e8c565
ON
38} gp_ops[] = {
39 [RCU_SYNC] = {
40 .sync = synchronize_rcu,
41 .call = call_rcu,
3a518b76 42 __INIT_HELD(rcu_read_lock_held)
82e8c565
ON
43 },
44 [RCU_SCHED_SYNC] = {
45 .sync = synchronize_sched,
46 .call = call_rcu_sched,
3a518b76 47 __INIT_HELD(rcu_read_lock_sched_held)
82e8c565
ON
48 },
49 [RCU_BH_SYNC] = {
50 .sync = synchronize_rcu_bh,
51 .call = call_rcu_bh,
3a518b76 52 __INIT_HELD(rcu_read_lock_bh_held)
82e8c565
ON
53 },
54};
55
cc44ca84
ON
56enum { GP_IDLE = 0, GP_PENDING, GP_PASSED };
57enum { CB_IDLE = 0, CB_PENDING, CB_REPLAY };
58
59#define rss_lock gp_wait.lock
60
3a518b76
ON
61#ifdef CONFIG_PROVE_RCU
62bool __rcu_sync_is_idle(struct rcu_sync *rsp)
63{
64 WARN_ON(!gp_ops[rsp->gp_type].held());
65 return rsp->gp_state == GP_IDLE;
66}
67#endif
68
cc44ca84
ON
69/**
70 * rcu_sync_init() - Initialize an rcu_sync structure
71 * @rsp: Pointer to rcu_sync structure to be initialized
72 * @type: Flavor of RCU with which to synchronize rcu_sync structure
73 */
74void rcu_sync_init(struct rcu_sync *rsp, enum rcu_sync_type type)
75{
76 memset(rsp, 0, sizeof(*rsp));
77 init_waitqueue_head(&rsp->gp_wait);
82e8c565 78 rsp->gp_type = type;
cc44ca84
ON
79}
80
81/**
82 * rcu_sync_enter() - Force readers onto slowpath
83 * @rsp: Pointer to rcu_sync structure to use for synchronization
84 *
85 * This function is used by updaters who need readers to make use of
86 * a slowpath during the update. After this function returns, all
87 * subsequent calls to rcu_sync_is_idle() will return false, which
88 * tells readers to stay off their fastpaths. A later call to
89 * rcu_sync_exit() re-enables reader slowpaths.
90 *
91 * When called in isolation, rcu_sync_enter() must wait for a grace
92 * period, however, closely spaced calls to rcu_sync_enter() can
93 * optimize away the grace-period wait via a state machine implemented
94 * by rcu_sync_enter(), rcu_sync_exit(), and rcu_sync_func().
95 */
96void rcu_sync_enter(struct rcu_sync *rsp)
97{
98 bool need_wait, need_sync;
99
100 spin_lock_irq(&rsp->rss_lock);
101 need_wait = rsp->gp_count++;
102 need_sync = rsp->gp_state == GP_IDLE;
103 if (need_sync)
104 rsp->gp_state = GP_PENDING;
105 spin_unlock_irq(&rsp->rss_lock);
106
107 BUG_ON(need_wait && need_sync);
108
109 if (need_sync) {
82e8c565 110 gp_ops[rsp->gp_type].sync();
cc44ca84
ON
111 rsp->gp_state = GP_PASSED;
112 wake_up_all(&rsp->gp_wait);
113 } else if (need_wait) {
114 wait_event(rsp->gp_wait, rsp->gp_state == GP_PASSED);
115 } else {
116 /*
117 * Possible when there's a pending CB from a rcu_sync_exit().
118 * Nobody has yet been allowed the 'fast' path and thus we can
119 * avoid doing any sync(). The callback will get 'dropped'.
120 */
121 BUG_ON(rsp->gp_state != GP_PASSED);
122 }
123}
124
125/**
126 * rcu_sync_func() - Callback function managing reader access to fastpath
127 * @rsp: Pointer to rcu_sync structure to use for synchronization
128 *
129 * This function is passed to one of the call_rcu() functions by
130 * rcu_sync_exit(), so that it is invoked after a grace period following the
131 * that invocation of rcu_sync_exit(). It takes action based on events that
132 * have taken place in the meantime, so that closely spaced rcu_sync_enter()
133 * and rcu_sync_exit() pairs need not wait for a grace period.
134 *
135 * If another rcu_sync_enter() is invoked before the grace period
136 * ended, reset state to allow the next rcu_sync_exit() to let the
137 * readers back onto their fastpaths (after a grace period). If both
138 * another rcu_sync_enter() and its matching rcu_sync_exit() are invoked
139 * before the grace period ended, re-invoke call_rcu() on behalf of that
140 * rcu_sync_exit(). Otherwise, set all state back to idle so that readers
141 * can again use their fastpaths.
142 */
143static void rcu_sync_func(struct rcu_head *rcu)
144{
145 struct rcu_sync *rsp = container_of(rcu, struct rcu_sync, cb_head);
146 unsigned long flags;
147
148 BUG_ON(rsp->gp_state != GP_PASSED);
149 BUG_ON(rsp->cb_state == CB_IDLE);
150
151 spin_lock_irqsave(&rsp->rss_lock, flags);
152 if (rsp->gp_count) {
153 /*
154 * A new rcu_sync_begin() has happened; drop the callback.
155 */
156 rsp->cb_state = CB_IDLE;
157 } else if (rsp->cb_state == CB_REPLAY) {
158 /*
159 * A new rcu_sync_exit() has happened; requeue the callback
160 * to catch a later GP.
161 */
162 rsp->cb_state = CB_PENDING;
82e8c565 163 gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func);
cc44ca84
ON
164 } else {
165 /*
166 * We're at least a GP after rcu_sync_exit(); eveybody will now
167 * have observed the write side critical section. Let 'em rip!.
168 */
169 rsp->cb_state = CB_IDLE;
170 rsp->gp_state = GP_IDLE;
171 }
172 spin_unlock_irqrestore(&rsp->rss_lock, flags);
173}
174
175/**
176 * rcu_sync_exit() - Allow readers back onto fast patch after grace period
177 * @rsp: Pointer to rcu_sync structure to use for synchronization
178 *
179 * This function is used by updaters who have completed, and can therefore
180 * now allow readers to make use of their fastpaths after a grace period
181 * has elapsed. After this grace period has completed, all subsequent
182 * calls to rcu_sync_is_idle() will return true, which tells readers that
183 * they can once again use their fastpaths.
184 */
185void rcu_sync_exit(struct rcu_sync *rsp)
186{
187 spin_lock_irq(&rsp->rss_lock);
188 if (!--rsp->gp_count) {
189 if (rsp->cb_state == CB_IDLE) {
190 rsp->cb_state = CB_PENDING;
82e8c565 191 gp_ops[rsp->gp_type].call(&rsp->cb_head, rcu_sync_func);
cc44ca84
ON
192 } else if (rsp->cb_state == CB_PENDING) {
193 rsp->cb_state = CB_REPLAY;
194 }
195 }
196 spin_unlock_irq(&rsp->rss_lock);
197}
This page took 0.048807 seconds and 5 git commands to generate.