diff options
author | Oleg Nesterov <oleg@redhat.com> | 2015-08-21 13:42:44 -0400 |
---|---|---|
committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2015-10-06 14:25:04 -0400 |
commit | cc44ca848f5e517aeca9f5eabbe13609a3f71450 (patch) | |
tree | 4380962c131d6585f347aee962b0280176ae4bdd /include/linux/rcu_sync.h | |
parent | 3836f5337f74fedc15981688c3c31dbf4293ae84 (diff) |
rcu: Create rcu_sync infrastructure
The rcu_sync infrastructure can be thought of as infrastructure to be
used to implement reader-writer primitives having extremely lightweight
readers during times when there are no writers. The first use is in
the percpu_rwsem used by the VFS subsystem.
This infrastructure is functionally equivalent to
struct rcu_sync_struct {
atomic_t counter;
};
/* Check possibility of fast-path read-side operations. */
static inline bool rcu_sync_is_idle(struct rcu_sync_struct *rss)
{
return atomic_read(&rss->counter) == 0;
}
/* Tell readers to use slowpaths. */
static inline void rcu_sync_enter(struct rcu_sync_struct *rss)
{
atomic_inc(&rss->counter);
synchronize_sched();
}
/* Allow readers to once again use fastpaths. */
static inline void rcu_sync_exit(struct rcu_sync_struct *rss)
{
synchronize_sched();
atomic_dec(&rss->counter);
}
The main difference is that it records the state and only calls
synchronize_sched() if required. At least some of the calls to
synchronize_sched() will be optimized away when rcu_sync_enter() and
rcu_sync_exit() are invoked repeatedly in quick succession.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Diffstat (limited to 'include/linux/rcu_sync.h')
-rw-r--r-- | include/linux/rcu_sync.h | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/include/linux/rcu_sync.h b/include/linux/rcu_sync.h new file mode 100644 index 000000000000..cb044df2e21c --- /dev/null +++ b/include/linux/rcu_sync.h | |||
@@ -0,0 +1,94 @@ | |||
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 | #ifndef _LINUX_RCU_SYNC_H_ | ||
24 | #define _LINUX_RCU_SYNC_H_ | ||
25 | |||
26 | #include <linux/wait.h> | ||
27 | #include <linux/rcupdate.h> | ||
28 | |||
29 | /* Structure to mediate between updaters and fastpath-using readers. */ | ||
30 | struct rcu_sync { | ||
31 | int gp_state; | ||
32 | int gp_count; | ||
33 | wait_queue_head_t gp_wait; | ||
34 | |||
35 | int cb_state; | ||
36 | struct rcu_head cb_head; | ||
37 | |||
38 | void (*sync)(void); | ||
39 | void (*call)(struct rcu_head *, void (*)(struct rcu_head *)); | ||
40 | }; | ||
41 | |||
42 | #define ___RCU_SYNC_INIT(name) \ | ||
43 | .gp_state = 0, \ | ||
44 | .gp_count = 0, \ | ||
45 | .gp_wait = __WAIT_QUEUE_HEAD_INITIALIZER(name.gp_wait), \ | ||
46 | .cb_state = 0 | ||
47 | |||
48 | #define __RCU_SCHED_SYNC_INIT(name) { \ | ||
49 | ___RCU_SYNC_INIT(name), \ | ||
50 | .sync = synchronize_sched, \ | ||
51 | .call = call_rcu_sched, \ | ||
52 | } | ||
53 | |||
54 | #define __RCU_BH_SYNC_INIT(name) { \ | ||
55 | ___RCU_SYNC_INIT(name), \ | ||
56 | .sync = synchronize_rcu_bh, \ | ||
57 | .call = call_rcu_bh, \ | ||
58 | } | ||
59 | |||
60 | #define __RCU_SYNC_INIT(name) { \ | ||
61 | ___RCU_SYNC_INIT(name), \ | ||
62 | .sync = synchronize_rcu, \ | ||
63 | .call = call_rcu, \ | ||
64 | } | ||
65 | |||
66 | #define DEFINE_RCU_SCHED_SYNC(name) \ | ||
67 | struct rcu_sync name = __RCU_SCHED_SYNC_INIT(name) | ||
68 | |||
69 | #define DEFINE_RCU_BH_SYNC(name) \ | ||
70 | struct rcu_sync name = __RCU_BH_SYNC_INIT(name) | ||
71 | |||
72 | #define DEFINE_RCU_SYNC(name) \ | ||
73 | struct rcu_sync name = __RCU_SYNC_INIT(name) | ||
74 | |||
75 | /** | ||
76 | * rcu_sync_is_idle() - Are readers permitted to use their fastpaths? | ||
77 | * @rsp: Pointer to rcu_sync structure to use for synchronization | ||
78 | * | ||
79 | * Returns true if readers are permitted to use their fastpaths. | ||
80 | * Must be invoked within an RCU read-side critical section whose | ||
81 | * flavor matches that of the rcu_sync struture. | ||
82 | */ | ||
83 | static inline bool rcu_sync_is_idle(struct rcu_sync *rsp) | ||
84 | { | ||
85 | return !rsp->gp_state; /* GP_IDLE */ | ||
86 | } | ||
87 | |||
88 | enum rcu_sync_type { RCU_SYNC, RCU_SCHED_SYNC, RCU_BH_SYNC }; | ||
89 | |||
90 | extern void rcu_sync_init(struct rcu_sync *, enum rcu_sync_type); | ||
91 | extern void rcu_sync_enter(struct rcu_sync *); | ||
92 | extern void rcu_sync_exit(struct rcu_sync *); | ||
93 | |||
94 | #endif /* _LINUX_RCU_SYNC_H_ */ | ||