diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/ksysfs.c | 22 | ||||
-rw-r--r-- | kernel/rcu/srcu.c | 2 | ||||
-rw-r--r-- | kernel/rcu/tree.c | 6 | ||||
-rw-r--r-- | kernel/rcu/tree_plugin.h | 6 | ||||
-rw-r--r-- | kernel/rcu/update.c | 12 |
5 files changed, 45 insertions, 3 deletions
diff --git a/kernel/ksysfs.c b/kernel/ksysfs.c index e83b26464061..b4e2fa52d8bc 100644 --- a/kernel/ksysfs.c +++ b/kernel/ksysfs.c | |||
@@ -20,7 +20,7 @@ | |||
20 | #include <linux/capability.h> | 20 | #include <linux/capability.h> |
21 | #include <linux/compiler.h> | 21 | #include <linux/compiler.h> |
22 | 22 | ||
23 | #include <linux/rcupdate.h> /* rcu_expedited */ | 23 | #include <linux/rcupdate.h> /* rcu_expedited and rcu_normal */ |
24 | 24 | ||
25 | #define KERNEL_ATTR_RO(_name) \ | 25 | #define KERNEL_ATTR_RO(_name) \ |
26 | static struct kobj_attribute _name##_attr = __ATTR_RO(_name) | 26 | static struct kobj_attribute _name##_attr = __ATTR_RO(_name) |
@@ -148,7 +148,7 @@ int rcu_expedited; | |||
148 | static ssize_t rcu_expedited_show(struct kobject *kobj, | 148 | static ssize_t rcu_expedited_show(struct kobject *kobj, |
149 | struct kobj_attribute *attr, char *buf) | 149 | struct kobj_attribute *attr, char *buf) |
150 | { | 150 | { |
151 | return sprintf(buf, "%d\n", rcu_expedited); | 151 | return sprintf(buf, "%d\n", READ_ONCE(rcu_expedited)); |
152 | } | 152 | } |
153 | static ssize_t rcu_expedited_store(struct kobject *kobj, | 153 | static ssize_t rcu_expedited_store(struct kobject *kobj, |
154 | struct kobj_attribute *attr, | 154 | struct kobj_attribute *attr, |
@@ -161,6 +161,23 @@ static ssize_t rcu_expedited_store(struct kobject *kobj, | |||
161 | } | 161 | } |
162 | KERNEL_ATTR_RW(rcu_expedited); | 162 | KERNEL_ATTR_RW(rcu_expedited); |
163 | 163 | ||
164 | int rcu_normal; | ||
165 | static ssize_t rcu_normal_show(struct kobject *kobj, | ||
166 | struct kobj_attribute *attr, char *buf) | ||
167 | { | ||
168 | return sprintf(buf, "%d\n", READ_ONCE(rcu_normal)); | ||
169 | } | ||
170 | static ssize_t rcu_normal_store(struct kobject *kobj, | ||
171 | struct kobj_attribute *attr, | ||
172 | const char *buf, size_t count) | ||
173 | { | ||
174 | if (kstrtoint(buf, 0, &rcu_normal)) | ||
175 | return -EINVAL; | ||
176 | |||
177 | return count; | ||
178 | } | ||
179 | KERNEL_ATTR_RW(rcu_normal); | ||
180 | |||
164 | /* | 181 | /* |
165 | * Make /sys/kernel/notes give the raw contents of our kernel .notes section. | 182 | * Make /sys/kernel/notes give the raw contents of our kernel .notes section. |
166 | */ | 183 | */ |
@@ -203,6 +220,7 @@ static struct attribute * kernel_attrs[] = { | |||
203 | &vmcoreinfo_attr.attr, | 220 | &vmcoreinfo_attr.attr, |
204 | #endif | 221 | #endif |
205 | &rcu_expedited_attr.attr, | 222 | &rcu_expedited_attr.attr, |
223 | &rcu_normal_attr.attr, | ||
206 | NULL | 224 | NULL |
207 | }; | 225 | }; |
208 | 226 | ||
diff --git a/kernel/rcu/srcu.c b/kernel/rcu/srcu.c index a63a1ea5a41b..9b9cdd549caa 100644 --- a/kernel/rcu/srcu.c +++ b/kernel/rcu/srcu.c | |||
@@ -489,7 +489,7 @@ static void __synchronize_srcu(struct srcu_struct *sp, int trycount) | |||
489 | */ | 489 | */ |
490 | void synchronize_srcu(struct srcu_struct *sp) | 490 | void synchronize_srcu(struct srcu_struct *sp) |
491 | { | 491 | { |
492 | __synchronize_srcu(sp, rcu_gp_is_expedited() | 492 | __synchronize_srcu(sp, (rcu_gp_is_expedited() && !rcu_gp_is_normal()) |
493 | ? SYNCHRONIZE_SRCU_EXP_TRYCOUNT | 493 | ? SYNCHRONIZE_SRCU_EXP_TRYCOUNT |
494 | : SYNCHRONIZE_SRCU_TRYCOUNT); | 494 | : SYNCHRONIZE_SRCU_TRYCOUNT); |
495 | } | 495 | } |
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 6a652d1f3d7f..489992997c06 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -3841,6 +3841,12 @@ void synchronize_sched_expedited(void) | |||
3841 | if (rcu_blocking_is_gp()) | 3841 | if (rcu_blocking_is_gp()) |
3842 | return; | 3842 | return; |
3843 | 3843 | ||
3844 | /* If expedited grace periods are prohibited, fall back to normal. */ | ||
3845 | if (rcu_gp_is_normal()) { | ||
3846 | wait_rcu_gp(call_rcu_sched); | ||
3847 | return; | ||
3848 | } | ||
3849 | |||
3844 | /* Take a snapshot of the sequence number. */ | 3850 | /* Take a snapshot of the sequence number. */ |
3845 | s = rcu_exp_gp_seq_snap(rsp); | 3851 | s = rcu_exp_gp_seq_snap(rsp); |
3846 | 3852 | ||
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h index 57ba873d2f18..d45df3781551 100644 --- a/kernel/rcu/tree_plugin.h +++ b/kernel/rcu/tree_plugin.h | |||
@@ -746,6 +746,12 @@ void synchronize_rcu_expedited(void) | |||
746 | struct rcu_state *rsp = rcu_state_p; | 746 | struct rcu_state *rsp = rcu_state_p; |
747 | unsigned long s; | 747 | unsigned long s; |
748 | 748 | ||
749 | /* If expedited grace periods are prohibited, fall back to normal. */ | ||
750 | if (rcu_gp_is_normal()) { | ||
751 | wait_rcu_gp(call_rcu); | ||
752 | return; | ||
753 | } | ||
754 | |||
749 | s = rcu_exp_gp_seq_snap(rsp); | 755 | s = rcu_exp_gp_seq_snap(rsp); |
750 | 756 | ||
751 | rnp_unlock = exp_funnel_lock(rsp, s); | 757 | rnp_unlock = exp_funnel_lock(rsp, s); |
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c index 5f748c5a40f0..8fccda3a794d 100644 --- a/kernel/rcu/update.c +++ b/kernel/rcu/update.c | |||
@@ -61,6 +61,7 @@ MODULE_ALIAS("rcupdate"); | |||
61 | #define MODULE_PARAM_PREFIX "rcupdate." | 61 | #define MODULE_PARAM_PREFIX "rcupdate." |
62 | 62 | ||
63 | module_param(rcu_expedited, int, 0); | 63 | module_param(rcu_expedited, int, 0); |
64 | module_param(rcu_normal, int, 0); | ||
64 | 65 | ||
65 | #if defined(CONFIG_DEBUG_LOCK_ALLOC) && defined(CONFIG_PREEMPT_COUNT) | 66 | #if defined(CONFIG_DEBUG_LOCK_ALLOC) && defined(CONFIG_PREEMPT_COUNT) |
66 | /** | 67 | /** |
@@ -113,6 +114,17 @@ EXPORT_SYMBOL(rcu_read_lock_sched_held); | |||
113 | 114 | ||
114 | #ifndef CONFIG_TINY_RCU | 115 | #ifndef CONFIG_TINY_RCU |
115 | 116 | ||
117 | /* | ||
118 | * Should expedited grace-period primitives always fall back to their | ||
119 | * non-expedited counterparts? Intended for use within RCU. Note | ||
120 | * that if the user specifies both rcu_expedited and rcu_normal, then | ||
121 | * rcu_normal wins. | ||
122 | */ | ||
123 | bool rcu_gp_is_normal(void) | ||
124 | { | ||
125 | return READ_ONCE(rcu_normal); | ||
126 | } | ||
127 | |||
116 | static atomic_t rcu_expedited_nesting = | 128 | static atomic_t rcu_expedited_nesting = |
117 | ATOMIC_INIT(IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT) ? 1 : 0); | 129 | ATOMIC_INIT(IS_ENABLED(CONFIG_RCU_EXPEDITE_BOOT) ? 1 : 0); |
118 | 130 | ||