Skip to content

Commit 821ca6f

Browse files
paulmckrcufbq
authored andcommitted
srcu: Make Tree SRCU updates independent of ->srcu_idx
This commit makes Tree SRCU updates independent of ->srcu_idx, then drop ->srcu_idx. Signed-off-by: Paul E. McKenney <[email protected]> Cc: Alexei Starovoitov <[email protected]> Cc: Andrii Nakryiko <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Kent Overstreet <[email protected]> Cc: <[email protected]> Signed-off-by: Boqun Feng <[email protected]>
1 parent 795e7ef commit 821ca6f

File tree

2 files changed

+34
-35
lines changed

2 files changed

+34
-35
lines changed

include/linux/srcutree.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ struct srcu_usage {
100100
* Per-SRCU-domain structure, similar in function to rcu_state.
101101
*/
102102
struct srcu_struct {
103-
unsigned int srcu_idx; /* Current rdr array element. */
104103
struct srcu_ctr __percpu *srcu_ctrp;
105104
struct srcu_data __percpu *sda; /* Per-CPU srcu_data array. */
106105
struct lockdep_map dep_map;

kernel/rcu/srcutree.c

Lines changed: 34 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,6 @@ static int init_srcu_struct_fields(struct srcu_struct *ssp, bool is_static)
246246
ssp->srcu_sup->node = NULL;
247247
mutex_init(&ssp->srcu_sup->srcu_cb_mutex);
248248
mutex_init(&ssp->srcu_sup->srcu_gp_mutex);
249-
ssp->srcu_idx = 0;
250249
ssp->srcu_sup->srcu_gp_seq = SRCU_GP_SEQ_INITIAL_VAL;
251250
ssp->srcu_sup->srcu_barrier_seq = 0;
252251
mutex_init(&ssp->srcu_sup->srcu_barrier_mutex);
@@ -510,38 +509,39 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
510509
* If the locks are the same as the unlocks, then there must have
511510
* been no readers on this index at some point in this function.
512511
* But there might be more readers, as a task might have read
513-
* the current ->srcu_idx but not yet have incremented its CPU's
512+
* the current ->srcu_ctrp but not yet have incremented its CPU's
514513
* ->srcu_ctrs[idx].srcu_locks counter. In fact, it is possible
515514
* that most of the tasks have been preempted between fetching
516-
* ->srcu_idx and incrementing ->srcu_ctrs[idx].srcu_locks. And there
517-
* could be almost (ULONG_MAX / sizeof(struct task_struct)) tasks
518-
* in a system whose address space was fully populated with memory.
519-
* Call this quantity Nt.
515+
* ->srcu_ctrp and incrementing ->srcu_ctrs[idx].srcu_locks. And
516+
* there could be almost (ULONG_MAX / sizeof(struct task_struct))
517+
* tasks in a system whose address space was fully populated
518+
* with memory. Call this quantity Nt.
520519
*
521-
* So suppose that the updater is preempted at this point in the
522-
* code for a long time. That now-preempted updater has already
523-
* flipped ->srcu_idx (possibly during the preceding grace period),
524-
* done an smp_mb() (again, possibly during the preceding grace
525-
* period), and summed up the ->srcu_ctrs[idx].srcu_unlocks counters.
526-
* How many times can a given one of the aforementioned Nt tasks
527-
* increment the old ->srcu_idx value's ->srcu_ctrs[idx].srcu_locks
528-
* counter, in the absence of nesting?
520+
* So suppose that the updater is preempted at this
521+
* point in the code for a long time. That now-preempted
522+
* updater has already flipped ->srcu_ctrp (possibly during
523+
* the preceding grace period), done an smp_mb() (again,
524+
* possibly during the preceding grace period), and summed up
525+
* the ->srcu_ctrs[idx].srcu_unlocks counters. How many times
526+
* can a given one of the aforementioned Nt tasks increment the
527+
* old ->srcu_ctrp value's ->srcu_ctrs[idx].srcu_locks counter,
528+
* in the absence of nesting?
529529
*
530530
* It can clearly do so once, given that it has already fetched
531-
* the old value of ->srcu_idx and is just about to use that
531+
* the old value of ->srcu_ctrp and is just about to use that
532532
* value to index its increment of ->srcu_ctrs[idx].srcu_locks.
533533
* But as soon as it leaves that SRCU read-side critical section,
534534
* it will increment ->srcu_ctrs[idx].srcu_unlocks, which must
535-
* follow the updater's above read from that same value. Thus,
536-
* as soon the reading task does an smp_mb() and a later fetch from
537-
* ->srcu_idx, that task will be guaranteed to get the new index.
535+
* follow the updater's above read from that same value. Thus,
536+
as soon the reading task does an smp_mb() and a later fetch from
537+
* ->srcu_ctrp, that task will be guaranteed to get the new index.
538538
* Except that the increment of ->srcu_ctrs[idx].srcu_unlocks
539539
* in __srcu_read_unlock() is after the smp_mb(), and the fetch
540-
* from ->srcu_idx in __srcu_read_lock() is before the smp_mb().
541-
* Thus, that task might not see the new value of ->srcu_idx until
540+
* from ->srcu_ctrp in __srcu_read_lock() is before the smp_mb().
541+
* Thus, that task might not see the new value of ->srcu_ctrp until
542542
* the -second- __srcu_read_lock(), which in turn means that this
543543
* task might well increment ->srcu_ctrs[idx].srcu_locks for the
544-
* old value of ->srcu_idx twice, not just once.
544+
* old value of ->srcu_ctrp twice, not just once.
545545
*
546546
* However, it is important to note that a given smp_mb() takes
547547
* effect not just for the task executing it, but also for any
@@ -1095,7 +1095,7 @@ static void srcu_funnel_gp_start(struct srcu_struct *ssp, struct srcu_data *sdp,
10951095
/*
10961096
* Wait until all readers counted by array index idx complete, but
10971097
* loop an additional time if there is an expedited grace period pending.
1098-
* The caller must ensure that ->srcu_idx is not changed while checking.
1098+
* The caller must ensure that ->srcu_ctrp is not changed while checking.
10991099
*/
11001100
static bool try_check_zero(struct srcu_struct *ssp, int idx, int trycount)
11011101
{
@@ -1113,30 +1113,30 @@ static bool try_check_zero(struct srcu_struct *ssp, int idx, int trycount)
11131113
}
11141114

11151115
/*
1116-
* Increment the ->srcu_idx counter so that future SRCU readers will
1116+
* Increment the ->srcu_ctrp counter so that future SRCU readers will
11171117
* use the other rank of the ->srcu_(un)lock_count[] arrays. This allows
11181118
* us to wait for pre-existing readers in a starvation-free manner.
11191119
*/
11201120
static void srcu_flip(struct srcu_struct *ssp)
11211121
{
11221122
/*
1123-
* Because the flip of ->srcu_idx is executed only if the
1123+
* Because the flip of ->srcu_ctrp is executed only if the
11241124
* preceding call to srcu_readers_active_idx_check() found that
11251125
* the ->srcu_ctrs[].srcu_unlocks and ->srcu_ctrs[].srcu_locks sums
11261126
* matched and because that summing uses atomic_long_read(),
11271127
* there is ordering due to a control dependency between that
11281128
* summing and the WRITE_ONCE() in this call to srcu_flip().
11291129
* This ordering ensures that if this updater saw a given reader's
11301130
* increment from __srcu_read_lock(), that reader was using a value
1131-
* of ->srcu_idx from before the previous call to srcu_flip(),
1131+
* of ->srcu_ctrp from before the previous call to srcu_flip(),
11321132
* which should be quite rare. This ordering thus helps forward
11331133
* progress because the grace period could otherwise be delayed
11341134
* by additional calls to __srcu_read_lock() using that old (soon
1135-
* to be new) value of ->srcu_idx.
1135+
* to be new) value of ->srcu_ctrp.
11361136
*
11371137
* This sum-equality check and ordering also ensures that if
11381138
* a given call to __srcu_read_lock() uses the new value of
1139-
* ->srcu_idx, this updater's earlier scans cannot have seen
1139+
* ->srcu_ctrp, this updater's earlier scans cannot have seen
11401140
* that reader's increments, which is all to the good, because
11411141
* this grace period need not wait on that reader. After all,
11421142
* if those earlier scans had seen that reader, there would have
@@ -1151,7 +1151,6 @@ static void srcu_flip(struct srcu_struct *ssp)
11511151
*/
11521152
smp_mb(); /* E */ /* Pairs with B and C. */
11531153

1154-
WRITE_ONCE(ssp->srcu_idx, ssp->srcu_idx + 1); // Flip the counter.
11551154
WRITE_ONCE(ssp->srcu_ctrp,
11561155
&ssp->sda->srcu_ctrs[!(ssp->srcu_ctrp - &ssp->sda->srcu_ctrs[0])]);
11571156

@@ -1466,8 +1465,9 @@ EXPORT_SYMBOL_GPL(synchronize_srcu_expedited);
14661465
*
14671466
* Wait for the count to drain to zero of both indexes. To avoid the
14681467
* possible starvation of synchronize_srcu(), it waits for the count of
1469-
* the index=((->srcu_idx & 1) ^ 1) to drain to zero at first,
1470-
* and then flip the srcu_idx and wait for the count of the other index.
1468+
* the index=!(ssp->srcu_ctrp - &ssp->sda->srcu_ctrs[0]) to drain to zero
1469+
* at first, and then flip the ->srcu_ctrp and wait for the count of the
1470+
* other index.
14711471
*
14721472
* Can block; must be called from process context.
14731473
*
@@ -1693,7 +1693,7 @@ static void srcu_advance_state(struct srcu_struct *ssp)
16931693

16941694
/*
16951695
* Because readers might be delayed for an extended period after
1696-
* fetching ->srcu_idx for their index, at any point in time there
1696+
* fetching ->srcu_ctrp for their index, at any point in time there
16971697
* might well be readers using both idx=0 and idx=1. We therefore
16981698
* need to wait for readers to clear from both index values before
16991699
* invoking a callback.
@@ -1721,7 +1721,7 @@ static void srcu_advance_state(struct srcu_struct *ssp)
17211721
}
17221722

17231723
if (rcu_seq_state(READ_ONCE(ssp->srcu_sup->srcu_gp_seq)) == SRCU_STATE_SCAN1) {
1724-
idx = 1 ^ (ssp->srcu_idx & 1);
1724+
idx = !(ssp->srcu_ctrp - &ssp->sda->srcu_ctrs[0]);
17251725
if (!try_check_zero(ssp, idx, 1)) {
17261726
mutex_unlock(&ssp->srcu_sup->srcu_gp_mutex);
17271727
return; /* readers present, retry later. */
@@ -1739,7 +1739,7 @@ static void srcu_advance_state(struct srcu_struct *ssp)
17391739
* SRCU read-side critical sections are normally short,
17401740
* so check at least twice in quick succession after a flip.
17411741
*/
1742-
idx = 1 ^ (ssp->srcu_idx & 1);
1742+
idx = !(ssp->srcu_ctrp - &ssp->sda->srcu_ctrs[0]);
17431743
if (!try_check_zero(ssp, idx, 2)) {
17441744
mutex_unlock(&ssp->srcu_sup->srcu_gp_mutex);
17451745
return; /* readers present, retry later. */
@@ -1897,7 +1897,7 @@ void srcu_torture_stats_print(struct srcu_struct *ssp, char *tt, char *tf)
18971897
int ss_state = READ_ONCE(ssp->srcu_sup->srcu_size_state);
18981898
int ss_state_idx = ss_state;
18991899

1900-
idx = ssp->srcu_idx & 0x1;
1900+
idx = ssp->srcu_ctrp - &ssp->sda->srcu_ctrs[0];
19011901
if (ss_state < 0 || ss_state >= ARRAY_SIZE(srcu_size_state_name))
19021902
ss_state_idx = ARRAY_SIZE(srcu_size_state_name) - 1;
19031903
pr_alert("%s%s Tree SRCU g%ld state %d (%s)",

0 commit comments

Comments
 (0)