Skip to content

Commit 9a08942

Browse files
author
Frederic Weisbecker
committed
Merge branch 'rcu/misc' into next
- In order to prepare the layout for nohz_full work deferral to user exit, the context tracking state must shrink the counter of transitions to/from RCU not watching. The only possible hazard is to trigger wrap-around more easily, delaying a bit grace periods when that happens. This should be a rare event though. Yet add debugging and torture code to test that assumption. - Fix memory leak on locktorture module - Annotate accesses in rculist_nulls.h to prevent from KCSAN warnings. On recent discussions, we also concluded that all those WRITE_ONCE() and READ_ONCE() on list APIs deserve appropriate comments. Something to be expected for the next cycle. - Provide a script to apply several configs to several commits with torture. - Allow torture to reuse a build directory in order to save needless rebuild time. - Various cleanups.
2 parents a504138 + 82a2244 commit 9a08942

8 files changed

Lines changed: 219 additions & 31 deletions

File tree

include/linux/context_tracking_state.h

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,6 @@ enum ctx_state {
1818
CT_STATE_MAX = 4,
1919
};
2020

21-
/* Odd value for watching, else even. */
22-
#define CT_RCU_WATCHING CT_STATE_MAX
23-
24-
#define CT_STATE_MASK (CT_STATE_MAX - 1)
25-
#define CT_RCU_WATCHING_MASK (~CT_STATE_MASK)
26-
2721
struct context_tracking {
2822
#ifdef CONFIG_CONTEXT_TRACKING_USER
2923
/*
@@ -44,9 +38,45 @@ struct context_tracking {
4438
#endif
4539
};
4640

41+
/*
42+
* We cram two different things within the same atomic variable:
43+
*
44+
* CT_RCU_WATCHING_START CT_STATE_START
45+
* | |
46+
* v v
47+
* MSB [ RCU watching counter ][ context_state ] LSB
48+
* ^ ^
49+
* | |
50+
* CT_RCU_WATCHING_END CT_STATE_END
51+
*
52+
* Bits are used from the LSB upwards, so unused bits (if any) will always be in
53+
* upper bits of the variable.
54+
*/
4755
#ifdef CONFIG_CONTEXT_TRACKING
56+
#define CT_SIZE (sizeof(((struct context_tracking *)0)->state) * BITS_PER_BYTE)
57+
58+
#define CT_STATE_WIDTH bits_per(CT_STATE_MAX - 1)
59+
#define CT_STATE_START 0
60+
#define CT_STATE_END (CT_STATE_START + CT_STATE_WIDTH - 1)
61+
62+
#define CT_RCU_WATCHING_MAX_WIDTH (CT_SIZE - CT_STATE_WIDTH)
63+
#define CT_RCU_WATCHING_WIDTH (IS_ENABLED(CONFIG_RCU_DYNTICKS_TORTURE) ? 2 : CT_RCU_WATCHING_MAX_WIDTH)
64+
#define CT_RCU_WATCHING_START (CT_STATE_END + 1)
65+
#define CT_RCU_WATCHING_END (CT_RCU_WATCHING_START + CT_RCU_WATCHING_WIDTH - 1)
66+
#define CT_RCU_WATCHING BIT(CT_RCU_WATCHING_START)
67+
68+
#define CT_STATE_MASK GENMASK(CT_STATE_END, CT_STATE_START)
69+
#define CT_RCU_WATCHING_MASK GENMASK(CT_RCU_WATCHING_END, CT_RCU_WATCHING_START)
70+
71+
#define CT_UNUSED_WIDTH (CT_RCU_WATCHING_MAX_WIDTH - CT_RCU_WATCHING_WIDTH)
72+
73+
static_assert(CT_STATE_WIDTH +
74+
CT_RCU_WATCHING_WIDTH +
75+
CT_UNUSED_WIDTH ==
76+
CT_SIZE);
77+
4878
DECLARE_PER_CPU(struct context_tracking, context_tracking);
49-
#endif
79+
#endif /* CONFIG_CONTEXT_TRACKING */
5080

5181
#ifdef CONFIG_CONTEXT_TRACKING_USER
5282
static __always_inline int __ct_state(void)

include/linux/rculist_nulls.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ static inline void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n,
138138

139139
if (last) {
140140
WRITE_ONCE(n->next, last->next);
141-
n->pprev = &last->next;
141+
WRITE_ONCE(n->pprev, &last->next);
142142
rcu_assign_pointer(hlist_nulls_next_rcu(last), n);
143143
} else {
144144
hlist_nulls_add_head_rcu(n, h);
@@ -148,8 +148,8 @@ static inline void hlist_nulls_add_tail_rcu(struct hlist_nulls_node *n,
148148
/* after that hlist_nulls_del will work */
149149
static inline void hlist_nulls_add_fake(struct hlist_nulls_node *n)
150150
{
151-
n->pprev = &n->next;
152-
n->next = (struct hlist_nulls_node *)NULLS_MARKER(NULL);
151+
WRITE_ONCE(n->pprev, &n->next);
152+
WRITE_ONCE(n->next, (struct hlist_nulls_node *)NULLS_MARKER(NULL));
153153
}
154154

155155
/**

kernel/locking/locktorture.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,8 +103,8 @@ static const struct kernel_param_ops lt_bind_ops = {
103103
.get = param_get_cpumask,
104104
};
105105

106-
module_param_cb(bind_readers, &lt_bind_ops, &bind_readers, 0644);
107-
module_param_cb(bind_writers, &lt_bind_ops, &bind_writers, 0644);
106+
module_param_cb(bind_readers, &lt_bind_ops, &bind_readers, 0444);
107+
module_param_cb(bind_writers, &lt_bind_ops, &bind_writers, 0444);
108108

109109
long torture_sched_setaffinity(pid_t pid, const struct cpumask *in_mask, bool dowarn);
110110

@@ -1211,6 +1211,10 @@ static void lock_torture_cleanup(void)
12111211
cxt.cur_ops->exit();
12121212
cxt.init_called = false;
12131213
}
1214+
1215+
free_cpumask_var(bind_readers);
1216+
free_cpumask_var(bind_writers);
1217+
12141218
torture_cleanup_end();
12151219
}
12161220

kernel/rcu/Kconfig.debug

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,19 @@ config RCU_STRICT_GRACE_PERIOD
213213
when looking for certain types of RCU usage bugs, for example,
214214
too-short RCU read-side critical sections.
215215

216+
217+
config RCU_DYNTICKS_TORTURE
218+
bool "Minimize RCU dynticks counter size"
219+
depends on RCU_EXPERT && !COMPILE_TEST
220+
default n
221+
help
222+
This option sets the width of the dynticks counter to its
223+
minimum usable value. This minimum width greatly increases
224+
the probability of flushing out bugs involving counter wrap,
225+
but it also increases the probability of extending grace period
226+
durations. This Kconfig option should therefore be avoided in
227+
production due to the consequent increased probability of OOMs.
228+
229+
This has no value for production and is only for testing.
230+
216231
endmenu # "RCU Debugging"

kernel/rcu/rcutorture.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2438,10 +2438,8 @@ static bool rcu_torture_one_read(struct torture_random_state *trsp, long myid)
24382438
newstate = rcutorture_extend_mask(rtors.readstate, trsp);
24392439
WARN_ON_ONCE(newstate & RCUTORTURE_RDR_UPDOWN);
24402440
rcutorture_one_extend(&rtors.readstate, newstate, trsp, rtors.rtrsp++);
2441-
if (!rcu_torture_one_read_start(&rtors, trsp, myid)) {
2442-
rcutorture_one_extend(&rtors.readstate, 0, trsp, rtors.rtrsp);
2441+
if (!rcu_torture_one_read_start(&rtors, trsp, myid))
24432442
return false;
2444-
}
24452443
rtors.rtrsp = rcutorture_loop_extend(&rtors.readstate, trsp, rtors.rtrsp);
24462444
rcu_torture_one_read_end(&rtors, trsp);
24472445
return true;

tools/testing/selftests/rcutorture/bin/kvm-again.sh

Lines changed: 40 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ fi
3131
if ! cp "$oldrun/scenarios" $T/scenarios.oldrun
3232
then
3333
# Later on, can reconstitute this from console.log files.
34-
echo Prior run batches file does not exist: $oldrun/batches
34+
echo Prior run scenarios file does not exist: $oldrun/scenarios
3535
exit 1
3636
fi
3737

@@ -68,7 +68,7 @@ usage () {
6868
echo " --datestamp string"
6969
echo " --dryrun"
7070
echo " --duration minutes | <seconds>s | <hours>h | <days>d"
71-
echo " --link hard|soft|copy"
71+
echo " --link hard|soft|copy|inplace|inplace-force"
7272
echo " --remote"
7373
echo " --rundir /new/res/path"
7474
echo "Command line: $scriptname $args"
@@ -121,7 +121,7 @@ do
121121
shift
122122
;;
123123
--link)
124-
checkarg --link "hard|soft|copy" "$#" "$2" 'hard\|soft\|copy' '^--'
124+
checkarg --link "hard|soft|copy|inplace|inplace-force" "$#" "$2" 'hard\|soft\|copy\|inplace\|inplace-force' '^--'
125125
case "$2" in
126126
copy)
127127
arg_link="cp -R"
@@ -132,6 +132,14 @@ do
132132
soft)
133133
arg_link="cp -Rs"
134134
;;
135+
inplace)
136+
arg_link="inplace"
137+
rundir="$oldrun"
138+
;;
139+
inplace-force)
140+
arg_link="inplace-force"
141+
rundir="$oldrun"
142+
;;
135143
esac
136144
shift
137145
;;
@@ -172,21 +180,37 @@ fi
172180

173181
echo ---- Re-run results directory: $rundir
174182

175-
# Copy old run directory tree over and adjust.
176-
mkdir -p "`dirname "$rundir"`"
177-
if ! $arg_link "$oldrun" "$rundir"
178-
then
179-
echo "Cannot copy from $oldrun to $rundir."
180-
usage
181-
fi
182-
rm -f "$rundir"/*/{console.log,console.log.diags,qemu_pid,qemu-pid,qemu-retval,Warnings,kvm-test-1-run.sh.out,kvm-test-1-run-qemu.sh.out,vmlinux} "$rundir"/log
183-
touch "$rundir/log"
184-
echo $scriptname $args | tee -a "$rundir/log"
185-
echo $oldrun > "$rundir/re-run"
186-
if ! test -d "$rundir/../../bin"
183+
if test "$oldrun" != "$rundir"
187184
then
188-
$arg_link "$oldrun/../../bin" "$rundir/../.."
185+
# Copy old run directory tree over and adjust.
186+
mkdir -p "`dirname "$rundir"`"
187+
if ! $arg_link "$oldrun" "$rundir"
188+
then
189+
echo "Cannot copy from $oldrun to $rundir."
190+
usage
191+
fi
192+
rm -f "$rundir"/*/{console.log,console.log.diags,qemu_pid,qemu-pid,qemu-retval,Warnings,kvm-test-1-run.sh.out,kvm-test-1-run-qemu.sh.out,vmlinux} "$rundir"/log
193+
touch "$rundir/log"
194+
echo $scriptname $args | tee -a "$rundir/log"
195+
echo $oldrun > "$rundir/re-run"
196+
if ! test -d "$rundir/../../bin"
197+
then
198+
$arg_link "$oldrun/../../bin" "$rundir/../.."
199+
fi
200+
else
201+
# Check for a run having already happened.
202+
find "$rundir" -name console.log -print > $T/oldrun-console.log
203+
if test -s $T/oldrun-console.log
204+
then
205+
echo Run already took place in $rundir
206+
if test "$arg_link" = inplace
207+
then
208+
usage
209+
fi
210+
fi
189211
fi
212+
213+
# Find runs to be done based on their qemu-cmd files.
190214
for i in $rundir/*/qemu-cmd
191215
do
192216
cp "$i" $T
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/bin/bash
2+
# SPDX-License-Identifier: GPL-2.0+
3+
#
4+
# Usage: kvm-series.sh config-list commit-id-list [ kvm.sh parameters ]
5+
#
6+
# Tests the specified list of unadorned configs ("TREE01 SRCU-P" but not
7+
# "CFLIST" or "3*TRACE01") and an indication of a set of commits to test,
8+
# then runs each commit through the specified list of commits using kvm.sh.
9+
# The runs are grouped into a -series/config/commit directory tree.
10+
# Each run defaults to a duration of one minute.
11+
#
12+
# Run in top-level Linux source directory. Please note that this is in
13+
# no way a replacement for "git bisect"!!!
14+
#
15+
# This script is intended to replace kvm-check-branches.sh by providing
16+
# ease of use and faster execution.
17+
18+
T="`mktemp -d ${TMPDIR-/tmp}/kvm-series.sh.XXXXXX`"
19+
trap 'rm -rf $T' 0
20+
21+
scriptname=$0
22+
args="$*"
23+
24+
config_list="${1}"
25+
if test -z "${config_list}"
26+
then
27+
echo "$0: Need a quoted list of --config arguments for first argument."
28+
exit 1
29+
fi
30+
if test -z "${config_list}" || echo "${config_list}" | grep -q '\*'
31+
then
32+
echo "$0: Repetition ('*') not allowed in config list."
33+
exit 1
34+
fi
35+
36+
commit_list="${2}"
37+
if test -z "${commit_list}"
38+
then
39+
echo "$0: Need a list of commits (e.g., HEAD^^^..) for second argument."
40+
exit 2
41+
fi
42+
git log --pretty=format:"%h" "${commit_list}" > $T/commits
43+
ret=$?
44+
if test "${ret}" -ne 0
45+
then
46+
echo "$0: Invalid commit list ('${commit_list}')."
47+
exit 2
48+
fi
49+
sha1_list=`cat $T/commits`
50+
51+
shift
52+
shift
53+
54+
RCUTORTURE="`pwd`/tools/testing/selftests/rcutorture"; export RCUTORTURE
55+
PATH=${RCUTORTURE}/bin:$PATH; export PATH
56+
. functions.sh
57+
58+
ret=0
59+
nfail=0
60+
nsuccess=0
61+
faillist=
62+
successlist=
63+
cursha1="`git rev-parse --abbrev-ref HEAD`"
64+
ds="`date +%Y.%m.%d-%H.%M.%S`-series"
65+
startdate="`date`"
66+
starttime="`get_starttime`"
67+
68+
echo " --- " $scriptname $args | tee -a $T/log
69+
echo " --- Results directory: " $ds | tee -a $T/log
70+
71+
for config in ${config_list}
72+
do
73+
sha_n=0
74+
for sha in ${sha1_list}
75+
do
76+
sha1=${sha_n}.${sha} # Enable "sort -k1nr" to list commits in order.
77+
echo Starting ${config}/${sha1} at `date` | tee -a $T/log
78+
git checkout "${sha}"
79+
time tools/testing/selftests/rcutorture/bin/kvm.sh --configs "$config" --datestamp "$ds/${config}/${sha1}" --duration 1 "$@"
80+
curret=$?
81+
if test "${curret}" -ne 0
82+
then
83+
nfail=$((nfail+1))
84+
faillist="$faillist ${config}/${sha1}(${curret})"
85+
else
86+
nsuccess=$((nsuccess+1))
87+
successlist="$successlist ${config}/${sha1}"
88+
# Successful run, so remove large files.
89+
rm -f ${RCUTORTURE}/$ds/${config}/${sha1}/{vmlinux,bzImage,System.map,Module.symvers}
90+
fi
91+
if test "${ret}" -eq 0
92+
then
93+
ret=${curret}
94+
fi
95+
sha_n=$((sha_n+1))
96+
done
97+
done
98+
git checkout "${cursha1}"
99+
100+
echo ${nsuccess} SUCCESSES: | tee -a $T/log
101+
echo ${successlist} | fmt | tee -a $T/log
102+
echo | tee -a $T/log
103+
echo ${nfail} FAILURES: | tee -a $T/log
104+
echo ${faillist} | fmt | tee -a $T/log
105+
if test -n "${faillist}"
106+
then
107+
echo | tee -a $T/log
108+
echo Failures across commits: | tee -a $T/log
109+
echo ${faillist} | tr ' ' '\012' | sed -e 's,^[^/]*/,,' -e 's/([0-9]*)//' |
110+
sort | uniq -c | sort -k2n | tee -a $T/log
111+
fi
112+
echo Started at $startdate, ended at `date`, duration `get_starttime_duration $starttime`. | tee -a $T/log
113+
echo Summary: Successes: ${nsuccess} Failures: ${nfail} | tee -a $T/log
114+
cp $T/log tools/testing/selftests/rcutorture/res/${ds}
115+
116+
exit "${ret}"

tools/testing/selftests/rcutorture/configs/rcu/TREE04

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
1616
CONFIG_RCU_EXPERT=y
1717
CONFIG_RCU_EQS_DEBUG=y
1818
CONFIG_RCU_LAZY=y
19+
CONFIG_RCU_DYNTICKS_TORTURE=y

0 commit comments

Comments
 (0)