Skip to content

Commit 56eb8be

Browse files
paulmckrcufbq
authored andcommitted
srcu: Pull ->srcu_{un,}lock_count into a new srcu_ctr structure
This commit prepares for array-index-free srcu_read_lock*() by moving the ->srcu_{un,}lock_count fields into a new srcu_ctr structure. This will permit ->srcu_index to be replaced by a per-CPU pointer to this structure. 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 5f9e1bc commit 56eb8be

File tree

2 files changed

+66
-62
lines changed

2 files changed

+66
-62
lines changed

include/linux/srcutree.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,19 @@
1717
struct srcu_node;
1818
struct srcu_struct;
1919

20+
/* One element of the srcu_data srcu_ctrs array. */
21+
struct srcu_ctr {
22+
atomic_long_t srcu_locks; /* Locks per CPU. */
23+
atomic_long_t srcu_unlocks; /* Unlocks per CPU. */
24+
};
25+
2026
/*
2127
* Per-CPU structure feeding into leaf srcu_node, similar in function
2228
* to rcu_node.
2329
*/
2430
struct srcu_data {
2531
/* Read-side state. */
26-
atomic_long_t srcu_lock_count[2]; /* Locks per CPU. */
27-
atomic_long_t srcu_unlock_count[2]; /* Unlocks per CPU. */
32+
struct srcu_ctr srcu_ctrs[2]; /* Locks and unlocks per CPU. */
2833
int srcu_reader_flavor; /* Reader flavor for srcu_struct structure? */
2934
/* Values: SRCU_READ_FLAVOR_.* */
3035

@@ -221,7 +226,7 @@ static inline int __srcu_read_lock_lite(struct srcu_struct *ssp)
221226

222227
RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_lock_lite().");
223228
idx = READ_ONCE(ssp->srcu_idx) & 0x1;
224-
this_cpu_inc(ssp->sda->srcu_lock_count[idx].counter); /* Y */
229+
this_cpu_inc(ssp->sda->srcu_ctrs[idx].srcu_locks.counter); /* Y */
225230
barrier(); /* Avoid leaking the critical section. */
226231
return idx;
227232
}
@@ -240,7 +245,7 @@ static inline int __srcu_read_lock_lite(struct srcu_struct *ssp)
240245
static inline void __srcu_read_unlock_lite(struct srcu_struct *ssp, int idx)
241246
{
242247
barrier(); /* Avoid leaking the critical section. */
243-
this_cpu_inc(ssp->sda->srcu_unlock_count[idx].counter); /* Z */
248+
this_cpu_inc(ssp->sda->srcu_ctrs[idx].srcu_unlocks.counter); /* Z */
244249
RCU_LOCKDEP_WARN(!rcu_is_watching(), "RCU must be watching srcu_read_unlock_lite().");
245250
}
246251

kernel/rcu/srcutree.c

Lines changed: 57 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -116,8 +116,9 @@ do { \
116116
/*
117117
* Initialize SRCU per-CPU data. Note that statically allocated
118118
* srcu_struct structures might already have srcu_read_lock() and
119-
* srcu_read_unlock() running against them. So if the is_static parameter
120-
* is set, don't initialize ->srcu_lock_count[] and ->srcu_unlock_count[].
119+
* srcu_read_unlock() running against them. So if the is_static
120+
* parameter is set, don't initialize ->srcu_ctrs[].srcu_locks and
121+
* ->srcu_ctrs[].srcu_unlocks.
121122
*/
122123
static void init_srcu_struct_data(struct srcu_struct *ssp)
123124
{
@@ -128,8 +129,6 @@ static void init_srcu_struct_data(struct srcu_struct *ssp)
128129
* Initialize the per-CPU srcu_data array, which feeds into the
129130
* leaves of the srcu_node tree.
130131
*/
131-
BUILD_BUG_ON(ARRAY_SIZE(sdp->srcu_lock_count) !=
132-
ARRAY_SIZE(sdp->srcu_unlock_count));
133132
for_each_possible_cpu(cpu) {
134133
sdp = per_cpu_ptr(ssp->sda, cpu);
135134
spin_lock_init(&ACCESS_PRIVATE(sdp, lock));
@@ -429,10 +428,10 @@ static bool srcu_gp_is_expedited(struct srcu_struct *ssp)
429428
}
430429

431430
/*
432-
* Computes approximate total of the readers' ->srcu_lock_count[] values
433-
* for the rank of per-CPU counters specified by idx, and returns true if
434-
* the caller did the proper barrier (gp), and if the count of the locks
435-
* matches that of the unlocks passed in.
431+
* Computes approximate total of the readers' ->srcu_ctrs[].srcu_locks
432+
* values for the rank of per-CPU counters specified by idx, and returns
433+
* true if the caller did the proper barrier (gp), and if the count of
434+
* the locks matches that of the unlocks passed in.
436435
*/
437436
static bool srcu_readers_lock_idx(struct srcu_struct *ssp, int idx, bool gp, unsigned long unlocks)
438437
{
@@ -443,7 +442,7 @@ static bool srcu_readers_lock_idx(struct srcu_struct *ssp, int idx, bool gp, uns
443442
for_each_possible_cpu(cpu) {
444443
struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
445444

446-
sum += atomic_long_read(&sdp->srcu_lock_count[idx]);
445+
sum += atomic_long_read(&sdp->srcu_ctrs[idx].srcu_locks);
447446
if (IS_ENABLED(CONFIG_PROVE_RCU))
448447
mask = mask | READ_ONCE(sdp->srcu_reader_flavor);
449448
}
@@ -455,8 +454,8 @@ static bool srcu_readers_lock_idx(struct srcu_struct *ssp, int idx, bool gp, uns
455454
}
456455

457456
/*
458-
* Returns approximate total of the readers' ->srcu_unlock_count[] values
459-
* for the rank of per-CPU counters specified by idx.
457+
* Returns approximate total of the readers' ->srcu_ctrs[].srcu_unlocks
458+
* values for the rank of per-CPU counters specified by idx.
460459
*/
461460
static unsigned long srcu_readers_unlock_idx(struct srcu_struct *ssp, int idx, unsigned long *rdm)
462461
{
@@ -467,7 +466,7 @@ static unsigned long srcu_readers_unlock_idx(struct srcu_struct *ssp, int idx, u
467466
for_each_possible_cpu(cpu) {
468467
struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
469468

470-
sum += atomic_long_read(&sdp->srcu_unlock_count[idx]);
469+
sum += atomic_long_read(&sdp->srcu_ctrs[idx].srcu_unlocks);
471470
mask = mask | READ_ONCE(sdp->srcu_reader_flavor);
472471
}
473472
WARN_ONCE(IS_ENABLED(CONFIG_PROVE_RCU) && (mask & (mask - 1)),
@@ -510,9 +509,9 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
510509
* been no readers on this index at some point in this function.
511510
* But there might be more readers, as a task might have read
512511
* the current ->srcu_idx but not yet have incremented its CPU's
513-
* ->srcu_lock_count[idx] counter. In fact, it is possible
512+
* ->srcu_ctrs[idx].srcu_locks counter. In fact, it is possible
514513
* that most of the tasks have been preempted between fetching
515-
* ->srcu_idx and incrementing ->srcu_lock_count[idx]. And there
514+
* ->srcu_idx and incrementing ->srcu_ctrs[idx].srcu_locks. And there
516515
* could be almost (ULONG_MAX / sizeof(struct task_struct)) tasks
517516
* in a system whose address space was fully populated with memory.
518517
* Call this quantity Nt.
@@ -521,36 +520,36 @@ static bool srcu_readers_active_idx_check(struct srcu_struct *ssp, int idx)
521520
* code for a long time. That now-preempted updater has already
522521
* flipped ->srcu_idx (possibly during the preceding grace period),
523522
* done an smp_mb() (again, possibly during the preceding grace
524-
* period), and summed up the ->srcu_unlock_count[idx] counters.
523+
* period), and summed up the ->srcu_ctrs[idx].srcu_unlocks counters.
525524
* How many times can a given one of the aforementioned Nt tasks
526-
* increment the old ->srcu_idx value's ->srcu_lock_count[idx]
525+
* increment the old ->srcu_idx value's ->srcu_ctrs[idx].srcu_locks
527526
* counter, in the absence of nesting?
528527
*
529528
* It can clearly do so once, given that it has already fetched
530-
* the old value of ->srcu_idx and is just about to use that value
531-
* to index its increment of ->srcu_lock_count[idx]. But as soon as
532-
* it leaves that SRCU read-side critical section, it will increment
533-
* ->srcu_unlock_count[idx], which must follow the updater's above
534-
* read from that same value. Thus, as soon the reading task does
535-
* an smp_mb() and a later fetch from ->srcu_idx, that task will be
536-
* guaranteed to get the new index. Except that the increment of
537-
* ->srcu_unlock_count[idx] in __srcu_read_unlock() is after the
538-
* smp_mb(), and the fetch from ->srcu_idx in __srcu_read_lock()
539-
* is before the smp_mb(). Thus, that task might not see the new
540-
* value of ->srcu_idx until the -second- __srcu_read_lock(),
541-
* which in turn means that this task might well increment
542-
* ->srcu_lock_count[idx] for the old value of ->srcu_idx twice,
543-
* not just once.
529+
* the old value of ->srcu_idx and is just about to use that
530+
* value to index its increment of ->srcu_ctrs[idx].srcu_locks.
531+
* But as soon as it leaves that SRCU read-side critical section,
532+
* it will increment ->srcu_ctrs[idx].srcu_unlocks, which must
533+
* follow the updater's above read from that same value. Thus,
534+
* as soon the reading task does an smp_mb() and a later fetch from
535+
* ->srcu_idx, that task will be guaranteed to get the new index.
536+
* Except that the increment of ->srcu_ctrs[idx].srcu_unlocks
537+
* in __srcu_read_unlock() is after the smp_mb(), and the fetch
538+
* from ->srcu_idx in __srcu_read_lock() is before the smp_mb().
539+
* Thus, that task might not see the new value of ->srcu_idx until
540+
* the -second- __srcu_read_lock(), which in turn means that this
541+
* task might well increment ->srcu_ctrs[idx].srcu_locks for the
542+
* old value of ->srcu_idx twice, not just once.
544543
*
545544
* However, it is important to note that a given smp_mb() takes
546545
* effect not just for the task executing it, but also for any
547546
* later task running on that same CPU.
548547
*
549-
* That is, there can be almost Nt + Nc further increments of
550-
* ->srcu_lock_count[idx] for the old index, where Nc is the number
551-
* of CPUs. But this is OK because the size of the task_struct
552-
* structure limits the value of Nt and current systems limit Nc
553-
* to a few thousand.
548+
* That is, there can be almost Nt + Nc further increments
549+
* of ->srcu_ctrs[idx].srcu_locks for the old index, where Nc
550+
* is the number of CPUs. But this is OK because the size of
551+
* the task_struct structure limits the value of Nt and current
552+
* systems limit Nc to a few thousand.
554553
*
555554
* OK, but what about nesting? This does impose a limit on
556555
* nesting of half of the size of the task_struct structure
@@ -581,10 +580,10 @@ static bool srcu_readers_active(struct srcu_struct *ssp)
581580
for_each_possible_cpu(cpu) {
582581
struct srcu_data *sdp = per_cpu_ptr(ssp->sda, cpu);
583582

584-
sum += atomic_long_read(&sdp->srcu_lock_count[0]);
585-
sum += atomic_long_read(&sdp->srcu_lock_count[1]);
586-
sum -= atomic_long_read(&sdp->srcu_unlock_count[0]);
587-
sum -= atomic_long_read(&sdp->srcu_unlock_count[1]);
583+
sum += atomic_long_read(&sdp->srcu_ctrs[0].srcu_locks);
584+
sum += atomic_long_read(&sdp->srcu_ctrs[1].srcu_locks);
585+
sum -= atomic_long_read(&sdp->srcu_ctrs[0].srcu_unlocks);
586+
sum -= atomic_long_read(&sdp->srcu_ctrs[1].srcu_unlocks);
588587
}
589588
return sum;
590589
}
@@ -746,7 +745,7 @@ int __srcu_read_lock(struct srcu_struct *ssp)
746745
int idx;
747746

748747
idx = READ_ONCE(ssp->srcu_idx) & 0x1;
749-
this_cpu_inc(ssp->sda->srcu_lock_count[idx].counter);
748+
this_cpu_inc(ssp->sda->srcu_ctrs[idx].srcu_locks.counter);
750749
smp_mb(); /* B */ /* Avoid leaking the critical section. */
751750
return idx;
752751
}
@@ -760,7 +759,7 @@ EXPORT_SYMBOL_GPL(__srcu_read_lock);
760759
void __srcu_read_unlock(struct srcu_struct *ssp, int idx)
761760
{
762761
smp_mb(); /* C */ /* Avoid leaking the critical section. */
763-
this_cpu_inc(ssp->sda->srcu_unlock_count[idx].counter);
762+
this_cpu_inc(ssp->sda->srcu_ctrs[idx].srcu_unlocks.counter);
764763
}
765764
EXPORT_SYMBOL_GPL(__srcu_read_unlock);
766765

@@ -777,7 +776,7 @@ int __srcu_read_lock_nmisafe(struct srcu_struct *ssp)
777776
struct srcu_data *sdp = raw_cpu_ptr(ssp->sda);
778777

779778
idx = READ_ONCE(ssp->srcu_idx) & 0x1;
780-
atomic_long_inc(&sdp->srcu_lock_count[idx]);
779+
atomic_long_inc(&sdp->srcu_ctrs[idx].srcu_locks);
781780
smp_mb__after_atomic(); /* B */ /* Avoid leaking the critical section. */
782781
return idx;
783782
}
@@ -793,7 +792,7 @@ void __srcu_read_unlock_nmisafe(struct srcu_struct *ssp, int idx)
793792
struct srcu_data *sdp = raw_cpu_ptr(ssp->sda);
794793

795794
smp_mb__before_atomic(); /* C */ /* Avoid leaking the critical section. */
796-
atomic_long_inc(&sdp->srcu_unlock_count[idx]);
795+
atomic_long_inc(&sdp->srcu_ctrs[idx].srcu_unlocks);
797796
}
798797
EXPORT_SYMBOL_GPL(__srcu_read_unlock_nmisafe);
799798

@@ -1123,17 +1122,17 @@ static void srcu_flip(struct srcu_struct *ssp)
11231122
/*
11241123
* Because the flip of ->srcu_idx is executed only if the
11251124
* preceding call to srcu_readers_active_idx_check() found that
1126-
* the ->srcu_unlock_count[] and ->srcu_lock_count[] sums matched
1127-
* and because that summing uses atomic_long_read(), there is
1128-
* ordering due to a control dependency between that summing and
1129-
* the WRITE_ONCE() in this call to srcu_flip(). This ordering
1130-
* ensures that if this updater saw a given reader's increment from
1131-
* __srcu_read_lock(), that reader was using a value of ->srcu_idx
1132-
* from before the previous call to srcu_flip(), which should be
1133-
* quite rare. This ordering thus helps forward progress because
1134-
* the grace period could otherwise be delayed by additional
1135-
* calls to __srcu_read_lock() using that old (soon to be new)
1136-
* value of ->srcu_idx.
1125+
* the ->srcu_ctrs[].srcu_unlocks and ->srcu_ctrs[].srcu_locks sums
1126+
* matched and because that summing uses atomic_long_read(),
1127+
* there is ordering due to a control dependency between that
1128+
* summing and the WRITE_ONCE() in this call to srcu_flip().
1129+
* This ordering ensures that if this updater saw a given reader's
1130+
* increment from __srcu_read_lock(), that reader was using a value
1131+
* of ->srcu_idx from before the previous call to srcu_flip(),
1132+
* which should be quite rare. This ordering thus helps forward
1133+
* progress because the grace period could otherwise be delayed
1134+
* by additional calls to __srcu_read_lock() using that old (soon
1135+
* to be new) value of ->srcu_idx.
11371136
*
11381137
* This sum-equality check and ordering also ensures that if
11391138
* a given call to __srcu_read_lock() uses the new value of
@@ -1914,17 +1913,17 @@ void srcu_torture_stats_print(struct srcu_struct *ssp, char *tt, char *tf)
19141913
struct srcu_data *sdp;
19151914

19161915
sdp = per_cpu_ptr(ssp->sda, cpu);
1917-
u0 = data_race(atomic_long_read(&sdp->srcu_unlock_count[!idx]));
1918-
u1 = data_race(atomic_long_read(&sdp->srcu_unlock_count[idx]));
1916+
u0 = data_race(atomic_long_read(&sdp->srcu_ctrs[!idx].srcu_unlocks));
1917+
u1 = data_race(atomic_long_read(&sdp->srcu_ctrs[idx].srcu_unlocks));
19191918

19201919
/*
19211920
* Make sure that a lock is always counted if the corresponding
19221921
* unlock is counted.
19231922
*/
19241923
smp_rmb();
19251924

1926-
l0 = data_race(atomic_long_read(&sdp->srcu_lock_count[!idx]));
1927-
l1 = data_race(atomic_long_read(&sdp->srcu_lock_count[idx]));
1925+
l0 = data_race(atomic_long_read(&sdp->srcu_ctrs[!idx].srcu_locks));
1926+
l1 = data_race(atomic_long_read(&sdp->srcu_ctrs[idx].srcu_locks));
19281927

19291928
c0 = l0 - u0;
19301929
c1 = l1 - u1;

0 commit comments

Comments
 (0)