Skip to content

Commit 7dfb03d

Browse files
committed
Merge branches 'doc.2023.12.13a', 'torture.2023.11.23a', 'fixes.2023.12.13a', 'rcu-tasks.2023.12.12b' and 'srcu.2023.12.13a' into rcu-merge.2023.12.13a
5 parents ad94463 + 90f1015 + dee39c0 + 18966f7 + 3c6b0c1 commit 7dfb03d

File tree

15 files changed

+103
-42
lines changed

15 files changed

+103
-42
lines changed

Documentation/admin-guide/kernel-parameters.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5302,6 +5302,12 @@
53025302
Dump ftrace buffer after reporting RCU CPU
53035303
stall warning.
53045304

5305+
rcupdate.rcu_cpu_stall_notifiers= [KNL]
5306+
Provide RCU CPU stall notifiers, but see the
5307+
warnings in the RCU_CPU_STALL_NOTIFIER Kconfig
5308+
option's help text. TL;DR: You almost certainly
5309+
do not want rcupdate.rcu_cpu_stall_notifiers.
5310+
53055311
rcupdate.rcu_cpu_stall_suppress= [KNL]
53065312
Suppress RCU CPU stall warning messages.
53075313

include/linux/rcu_notifier.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,20 @@
1313
#define RCU_STALL_NOTIFY_NORM 1
1414
#define RCU_STALL_NOTIFY_EXP 2
1515

16-
#ifdef CONFIG_RCU_STALL_COMMON
16+
#if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
1717

1818
#include <linux/notifier.h>
1919
#include <linux/types.h>
2020

2121
int rcu_stall_chain_notifier_register(struct notifier_block *n);
2222
int rcu_stall_chain_notifier_unregister(struct notifier_block *n);
2323

24-
#else // #ifdef CONFIG_RCU_STALL_COMMON
24+
#else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
2525

2626
// No RCU CPU stall warnings in Tiny RCU.
2727
static inline int rcu_stall_chain_notifier_register(struct notifier_block *n) { return -EEXIST; }
2828
static inline int rcu_stall_chain_notifier_unregister(struct notifier_block *n) { return -ENOENT; }
2929

30-
#endif // #else // #ifdef CONFIG_RCU_STALL_COMMON
30+
#endif // #else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
3131

3232
#endif /* __LINUX_RCU_NOTIFIER_H */

include/linux/rcupdate.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,6 @@
3434

3535
#define ULONG_CMP_GE(a, b) (ULONG_MAX / 2 >= (a) - (b))
3636
#define ULONG_CMP_LT(a, b) (ULONG_MAX / 2 < (a) - (b))
37-
#define ulong2long(a) (*(long *)(&(a)))
38-
#define USHORT_CMP_GE(a, b) (USHRT_MAX / 2 >= (unsigned short)((a) - (b)))
39-
#define USHORT_CMP_LT(a, b) (USHRT_MAX / 2 < (unsigned short)((a) - (b)))
4037

4138
/* Exported common interfaces */
4239
void call_rcu(struct rcu_head *head, rcu_callback_t func);
@@ -301,6 +298,11 @@ static inline void rcu_lock_acquire(struct lockdep_map *map)
301298
lock_acquire(map, 0, 0, 2, 0, NULL, _THIS_IP_);
302299
}
303300

301+
static inline void rcu_try_lock_acquire(struct lockdep_map *map)
302+
{
303+
lock_acquire(map, 0, 1, 2, 0, NULL, _THIS_IP_);
304+
}
305+
304306
static inline void rcu_lock_release(struct lockdep_map *map)
305307
{
306308
lock_release(map, _THIS_IP_);
@@ -315,6 +317,7 @@ int rcu_read_lock_any_held(void);
315317
#else /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */
316318

317319
# define rcu_lock_acquire(a) do { } while (0)
320+
# define rcu_try_lock_acquire(a) do { } while (0)
318321
# define rcu_lock_release(a) do { } while (0)
319322

320323
static inline int rcu_read_lock_held(void)

include/linux/srcu.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ static inline int srcu_read_lock_nmisafe(struct srcu_struct *ssp) __acquires(ssp
229229

230230
srcu_check_nmi_safety(ssp, true);
231231
retval = __srcu_read_lock_nmisafe(ssp);
232-
rcu_lock_acquire(&ssp->dep_map);
232+
rcu_try_lock_acquire(&ssp->dep_map);
233233
return retval;
234234
}
235235

kernel/locking/locktorture.c

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ struct call_rcu_chain {
124124
struct rcu_head crc_rh;
125125
bool crc_stop;
126126
};
127-
struct call_rcu_chain *call_rcu_chain;
127+
struct call_rcu_chain *call_rcu_chain_list;
128128

129129
/* Forward reference. */
130130
static void lock_torture_cleanup(void);
@@ -1074,12 +1074,12 @@ static int call_rcu_chain_init(void)
10741074

10751075
if (call_rcu_chains <= 0)
10761076
return 0;
1077-
call_rcu_chain = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain), GFP_KERNEL);
1078-
if (!call_rcu_chain)
1077+
call_rcu_chain_list = kcalloc(call_rcu_chains, sizeof(*call_rcu_chain_list), GFP_KERNEL);
1078+
if (!call_rcu_chain_list)
10791079
return -ENOMEM;
10801080
for (i = 0; i < call_rcu_chains; i++) {
1081-
call_rcu_chain[i].crc_stop = false;
1082-
call_rcu(&call_rcu_chain[i].crc_rh, call_rcu_chain_cb);
1081+
call_rcu_chain_list[i].crc_stop = false;
1082+
call_rcu(&call_rcu_chain_list[i].crc_rh, call_rcu_chain_cb);
10831083
}
10841084
return 0;
10851085
}
@@ -1089,13 +1089,13 @@ static void call_rcu_chain_cleanup(void)
10891089
{
10901090
int i;
10911091

1092-
if (!call_rcu_chain)
1092+
if (!call_rcu_chain_list)
10931093
return;
10941094
for (i = 0; i < call_rcu_chains; i++)
1095-
smp_store_release(&call_rcu_chain[i].crc_stop, true);
1095+
smp_store_release(&call_rcu_chain_list[i].crc_stop, true);
10961096
rcu_barrier();
1097-
kfree(call_rcu_chain);
1098-
call_rcu_chain = NULL;
1097+
kfree(call_rcu_chain_list);
1098+
call_rcu_chain_list = NULL;
10991099
}
11001100

11011101
static void lock_torture_cleanup(void)

kernel/rcu/Kconfig.debug

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,31 @@ config RCU_CPU_STALL_CPUTIME
105105
The boot option rcupdate.rcu_cpu_stall_cputime has the same function
106106
as this one, but will override this if it exists.
107107

108+
config RCU_CPU_STALL_NOTIFIER
109+
bool "Provide RCU CPU-stall notifiers"
110+
depends on RCU_STALL_COMMON
111+
depends on DEBUG_KERNEL
112+
depends on RCU_EXPERT
113+
default n
114+
help
115+
WARNING: You almost certainly do not want this!!!
116+
117+
Enable RCU CPU-stall notifiers, which are invoked just before
118+
printing the RCU CPU stall warning. As such, bugs in notifier
119+
callbacks can prevent stall warnings from being printed.
120+
And the whole reason that a stall warning is being printed is
121+
that something is hung up somewhere. Therefore, the notifier
122+
callbacks must be written extremely carefully, preferably
123+
containing only lockless code. After all, it is quite possible
124+
that the whole reason that the RCU CPU stall is happening in
125+
the first place is that someone forgot to release whatever lock
126+
that you are thinking of acquiring. In which case, having your
127+
notifier callback acquire that lock will hang, preventing the
128+
RCU CPU stall warning from appearing.
129+
130+
Say Y here if you want RCU CPU stall notifiers (you don't want them)
131+
Say N if you are unsure.
132+
108133
config RCU_TRACE
109134
bool "Enable tracing for RCU"
110135
depends on DEBUG_KERNEL

kernel/rcu/rcu.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,8 @@ static inline bool rcu_stall_is_suppressed_at_boot(void)
262262
return rcu_cpu_stall_suppress_at_boot && !rcu_inkernel_boot_has_ended();
263263
}
264264

265+
extern int rcu_cpu_stall_notifiers;
266+
265267
#ifdef CONFIG_RCU_STALL_COMMON
266268

267269
extern int rcu_cpu_stall_ftrace_dump;
@@ -659,10 +661,10 @@ static inline bool rcu_cpu_beenfullyonline(int cpu) { return true; }
659661
bool rcu_cpu_beenfullyonline(int cpu);
660662
#endif
661663

662-
#ifdef CONFIG_RCU_STALL_COMMON
664+
#if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
663665
int rcu_stall_notifier_call_chain(unsigned long val, void *v);
664-
#else // #ifdef CONFIG_RCU_STALL_COMMON
666+
#else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
665667
static inline int rcu_stall_notifier_call_chain(unsigned long val, void *v) { return NOTIFY_DONE; }
666-
#endif // #else // #ifdef CONFIG_RCU_STALL_COMMON
668+
#endif // #else // #if defined(CONFIG_RCU_STALL_COMMON) && defined(CONFIG_RCU_CPU_STALL_NOTIFIER)
667669

668670
#endif /* __LINUX_RCU_H */

kernel/rcu/rcutorture.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,10 +2450,12 @@ static int rcu_torture_stall(void *args)
24502450
unsigned long stop_at;
24512451

24522452
VERBOSE_TOROUT_STRING("rcu_torture_stall task started");
2453-
ret = rcu_stall_chain_notifier_register(&rcu_torture_stall_block);
2454-
if (ret)
2455-
pr_info("%s: rcu_stall_chain_notifier_register() returned %d, %sexpected.\n",
2456-
__func__, ret, !IS_ENABLED(CONFIG_RCU_STALL_COMMON) ? "un" : "");
2453+
if (rcu_cpu_stall_notifiers) {
2454+
ret = rcu_stall_chain_notifier_register(&rcu_torture_stall_block);
2455+
if (ret)
2456+
pr_info("%s: rcu_stall_chain_notifier_register() returned %d, %sexpected.\n",
2457+
__func__, ret, !IS_ENABLED(CONFIG_RCU_STALL_COMMON) ? "un" : "");
2458+
}
24572459
if (stall_cpu_holdoff > 0) {
24582460
VERBOSE_TOROUT_STRING("rcu_torture_stall begin holdoff");
24592461
schedule_timeout_interruptible(stall_cpu_holdoff * HZ);
@@ -2497,7 +2499,7 @@ static int rcu_torture_stall(void *args)
24972499
cur_ops->readunlock(idx);
24982500
}
24992501
pr_alert("%s end.\n", __func__);
2500-
if (!ret) {
2502+
if (rcu_cpu_stall_notifiers && !ret) {
25012503
ret = rcu_stall_chain_notifier_unregister(&rcu_torture_stall_block);
25022504
if (ret)
25032505
pr_info("%s: rcu_stall_chain_notifier_unregister() returned %d.\n", __func__, ret);
@@ -3872,7 +3874,9 @@ rcu_torture_init(void)
38723874
}
38733875
if (fqs_duration < 0)
38743876
fqs_duration = 0;
3875-
if (fqs_duration) {
3877+
if (fqs_holdoff < 0)
3878+
fqs_holdoff = 0;
3879+
if (fqs_duration && fqs_holdoff) {
38763880
/* Create the fqs thread */
38773881
firsterr = torture_create_kthread(rcu_torture_fqs, NULL,
38783882
fqs_task);

kernel/rcu/srcutree.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -772,20 +772,10 @@ EXPORT_SYMBOL_GPL(__srcu_read_unlock_nmisafe);
772772
*/
773773
static void srcu_gp_start(struct srcu_struct *ssp)
774774
{
775-
struct srcu_data *sdp;
776775
int state;
777776

778-
if (smp_load_acquire(&ssp->srcu_sup->srcu_size_state) < SRCU_SIZE_WAIT_BARRIER)
779-
sdp = per_cpu_ptr(ssp->sda, get_boot_cpu_id());
780-
else
781-
sdp = this_cpu_ptr(ssp->sda);
782777
lockdep_assert_held(&ACCESS_PRIVATE(ssp->srcu_sup, lock));
783778
WARN_ON_ONCE(ULONG_CMP_GE(ssp->srcu_sup->srcu_gp_seq, ssp->srcu_sup->srcu_gp_seq_needed));
784-
spin_lock_rcu_node(sdp); /* Interrupts already disabled. */
785-
rcu_segcblist_advance(&sdp->srcu_cblist,
786-
rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
787-
WARN_ON_ONCE(!rcu_segcblist_segempty(&sdp->srcu_cblist, RCU_NEXT_TAIL));
788-
spin_unlock_rcu_node(sdp); /* Interrupts remain disabled. */
789779
WRITE_ONCE(ssp->srcu_sup->srcu_gp_start, jiffies);
790780
WRITE_ONCE(ssp->srcu_sup->srcu_n_exp_nodelay, 0);
791781
smp_mb(); /* Order prior store to ->srcu_gp_seq_needed vs. GP start. */
@@ -1271,9 +1261,11 @@ static unsigned long srcu_gp_start_if_needed(struct srcu_struct *ssp,
12711261
* period (gp_num = X + 8). So acceleration fails.
12721262
*/
12731263
s = rcu_seq_snap(&ssp->srcu_sup->srcu_gp_seq);
1274-
rcu_segcblist_advance(&sdp->srcu_cblist,
1275-
rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
1276-
WARN_ON_ONCE(!rcu_segcblist_accelerate(&sdp->srcu_cblist, s) && rhp);
1264+
if (rhp) {
1265+
rcu_segcblist_advance(&sdp->srcu_cblist,
1266+
rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
1267+
WARN_ON_ONCE(!rcu_segcblist_accelerate(&sdp->srcu_cblist, s));
1268+
}
12771269
if (ULONG_CMP_LT(sdp->srcu_gp_seq_needed, s)) {
12781270
sdp->srcu_gp_seq_needed = s;
12791271
needgp = true;
@@ -1723,6 +1715,11 @@ static void srcu_invoke_callbacks(struct work_struct *work)
17231715
WARN_ON_ONCE(!rcu_segcblist_segempty(&sdp->srcu_cblist, RCU_NEXT_TAIL));
17241716
rcu_segcblist_advance(&sdp->srcu_cblist,
17251717
rcu_seq_current(&ssp->srcu_sup->srcu_gp_seq));
1718+
/*
1719+
* Although this function is theoretically re-entrant, concurrent
1720+
* callbacks invocation is disallowed to avoid executing an SRCU barrier
1721+
* too early.
1722+
*/
17261723
if (sdp->srcu_cblist_invoking ||
17271724
!rcu_segcblist_ready_cbs(&sdp->srcu_cblist)) {
17281725
spin_unlock_irq_rcu_node(sdp);
@@ -1753,6 +1750,7 @@ static void srcu_invoke_callbacks(struct work_struct *work)
17531750
sdp->srcu_cblist_invoking = false;
17541751
more = rcu_segcblist_ready_cbs(&sdp->srcu_cblist);
17551752
spin_unlock_irq_rcu_node(sdp);
1753+
/* An SRCU barrier or callbacks from previous nesting work pending */
17561754
if (more)
17571755
srcu_schedule_cbs_sdp(sdp, 0);
17581756
}

kernel/rcu/tasks.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -975,7 +975,7 @@ static void check_holdout_task(struct task_struct *t,
975975
t->rcu_tasks_nvcsw != READ_ONCE(t->nvcsw) ||
976976
!rcu_tasks_is_holdout(t) ||
977977
(IS_ENABLED(CONFIG_NO_HZ_FULL) &&
978-
!is_idle_task(t) && t->rcu_tasks_idle_cpu >= 0)) {
978+
!is_idle_task(t) && READ_ONCE(t->rcu_tasks_idle_cpu) >= 0)) {
979979
WRITE_ONCE(t->rcu_tasks_holdout, false);
980980
list_del_init(&t->rcu_tasks_holdout_list);
981981
put_task_struct(t);
@@ -993,7 +993,7 @@ static void check_holdout_task(struct task_struct *t,
993993
t, ".I"[is_idle_task(t)],
994994
"N."[cpu < 0 || !tick_nohz_full_cpu(cpu)],
995995
t->rcu_tasks_nvcsw, t->nvcsw, t->rcu_tasks_holdout,
996-
t->rcu_tasks_idle_cpu, cpu);
996+
data_race(t->rcu_tasks_idle_cpu), cpu);
997997
sched_show_task(t);
998998
}
999999

0 commit comments

Comments
 (0)