@@ -55,22 +55,24 @@ MODULE_DESCRIPTION("Read-Copy Update module-based torture test facility");
55
55
MODULE_LICENSE ("GPL" );
56
56
MODULE_AUTHOR (
"Paul E. McKenney <[email protected] > and Josh Triplett <[email protected] >" );
57
57
58
- /* Bits for ->extendables field, extendables param, and related definitions. */
59
- #define RCUTORTURE_RDR_SHIFT_1 8 /* Put SRCU index in upper bits. */
60
- #define RCUTORTURE_RDR_MASK_1 (0xff << RCUTORTURE_RDR_SHIFT_1)
61
- #define RCUTORTURE_RDR_SHIFT_2 16 /* Put SRCU index in upper bits. */
62
- #define RCUTORTURE_RDR_MASK_2 (0xff << RCUTORTURE_RDR_SHIFT_2)
63
- #define RCUTORTURE_RDR_BH 0x01 /* Extend readers by disabling bh. */
64
- #define RCUTORTURE_RDR_IRQ 0x02 /* ... disabling interrupts. */
65
- #define RCUTORTURE_RDR_PREEMPT 0x04 /* ... disabling preemption. */
66
- #define RCUTORTURE_RDR_RBH 0x08 /* ... rcu_read_lock_bh(). */
67
- #define RCUTORTURE_RDR_SCHED 0x10 /* ... rcu_read_lock_sched(). */
68
- #define RCUTORTURE_RDR_RCU_1 0x20 /* ... entering another RCU reader. */
69
- #define RCUTORTURE_RDR_RCU_2 0x40 /* ... entering another RCU reader. */
70
- #define RCUTORTURE_RDR_NBITS 7 /* Number of bits defined above. */
71
- #define RCUTORTURE_MAX_EXTEND \
58
+ // Bits for ->extendables field, extendables param, and related definitions.
59
+ #define RCUTORTURE_RDR_SHIFT_1 8 // Put SRCU index in upper bits.
60
+ #define RCUTORTURE_RDR_MASK_1 (0xff << RCUTORTURE_RDR_SHIFT_1)
61
+ #define RCUTORTURE_RDR_SHIFT_2 16 // Put SRCU index in upper bits.
62
+ #define RCUTORTURE_RDR_MASK_2 (0xff << RCUTORTURE_RDR_SHIFT_2)
63
+ #define RCUTORTURE_RDR_BH 0x01 // Extend readers by disabling bh.
64
+ #define RCUTORTURE_RDR_IRQ 0x02 // ... disabling interrupts.
65
+ #define RCUTORTURE_RDR_PREEMPT 0x04 // ... disabling preemption.
66
+ #define RCUTORTURE_RDR_RBH 0x08 // ... rcu_read_lock_bh().
67
+ #define RCUTORTURE_RDR_SCHED 0x10 // ... rcu_read_lock_sched().
68
+ #define RCUTORTURE_RDR_RCU_1 0x20 // ... entering another RCU reader.
69
+ #define RCUTORTURE_RDR_RCU_2 0x40 // ... entering another RCU reader.
70
+ #define RCUTORTURE_RDR_UPDOWN 0x80 // ... up-read from task, down-read from timer.
71
+ // Note: Manual start, automatic end.
72
+ #define RCUTORTURE_RDR_NBITS 8 // Number of bits defined above.
73
+ #define RCUTORTURE_MAX_EXTEND \
72
74
(RCUTORTURE_RDR_BH | RCUTORTURE_RDR_IRQ | RCUTORTURE_RDR_PREEMPT | \
73
- RCUTORTURE_RDR_RBH | RCUTORTURE_RDR_SCHED)
75
+ RCUTORTURE_RDR_RBH | RCUTORTURE_RDR_SCHED) // Intentionally omit RCUTORTURE_RDR_UPDOWN.
74
76
#define RCUTORTURE_RDR_ALLBITS \
75
77
(RCUTORTURE_MAX_EXTEND | RCUTORTURE_RDR_RCU_1 | RCUTORTURE_RDR_RCU_2 | \
76
78
RCUTORTURE_RDR_MASK_1 | RCUTORTURE_RDR_MASK_2)
@@ -110,6 +112,7 @@ torture_param(bool, gp_sync, false, "Use synchronous GP wait primitives");
110
112
torture_param (int , irqreader , 1 , "Allow RCU readers from irq handlers" );
111
113
torture_param (int , leakpointer , 0 , "Leak pointer dereferences from readers" );
112
114
torture_param (int , n_barrier_cbs , 0 , "# of callbacks/kthreads for barrier testing" );
115
+ torture_param (int , n_up_down , 32 , "# of concurrent up/down hrtimer-based RCU readers" );
113
116
torture_param (int , nfakewriters , 4 , "Number of RCU fake writer threads" );
114
117
torture_param (int , nreaders , -1 , "Number of RCU reader threads" );
115
118
torture_param (int , object_debug , 0 , "Enable debug-object double call_rcu() testing" );
@@ -156,6 +159,7 @@ static int nrealfakewriters;
156
159
static struct task_struct * writer_task ;
157
160
static struct task_struct * * fakewriter_tasks ;
158
161
static struct task_struct * * reader_tasks ;
162
+ static struct task_struct * updown_task ;
159
163
static struct task_struct * * nocb_tasks ;
160
164
static struct task_struct * stats_task ;
161
165
static struct task_struct * fqs_task ;
@@ -378,6 +382,8 @@ struct rcu_torture_ops {
378
382
void (* readunlock )(int idx );
379
383
int (* readlock_held )(void ); // lockdep.
380
384
int (* readlock_nesting )(void ); // actual nesting, if available, -1 if not.
385
+ int (* down_read )(void );
386
+ void (* up_read )(int idx );
381
387
unsigned long (* get_gp_seq )(void );
382
388
unsigned long (* gp_diff )(unsigned long new , unsigned long old );
383
389
void (* deferred_free )(struct rcu_torture * p );
@@ -427,6 +433,7 @@ struct rcu_torture_ops {
427
433
int no_pi_lock ;
428
434
int debug_objects ;
429
435
int start_poll_irqsoff ;
436
+ int have_up_down ;
430
437
const char * name ;
431
438
};
432
439
@@ -762,6 +769,50 @@ static int torture_srcu_read_lock_held(void)
762
769
return srcu_read_lock_held (srcu_ctlp );
763
770
}
764
771
772
+ static bool srcu_torture_have_up_down (void )
773
+ {
774
+ int rf = reader_flavor ;
775
+
776
+ if (!rf )
777
+ rf = SRCU_READ_FLAVOR_NORMAL ;
778
+ return !!(cur_ops -> have_up_down & rf );
779
+ }
780
+
781
+ static int srcu_torture_down_read (void )
782
+ {
783
+ int idx ;
784
+ struct srcu_ctr __percpu * scp ;
785
+
786
+ WARN_ON_ONCE (reader_flavor & ~SRCU_READ_FLAVOR_ALL );
787
+ WARN_ON_ONCE (reader_flavor & (reader_flavor - 1 ));
788
+
789
+ if ((reader_flavor & SRCU_READ_FLAVOR_NORMAL ) || !(reader_flavor & SRCU_READ_FLAVOR_ALL )) {
790
+ idx = srcu_down_read (srcu_ctlp );
791
+ WARN_ON_ONCE (idx & ~0x1 );
792
+ return idx ;
793
+ }
794
+ if (reader_flavor & SRCU_READ_FLAVOR_FAST ) {
795
+ scp = srcu_down_read_fast (srcu_ctlp );
796
+ idx = __srcu_ptr_to_ctr (srcu_ctlp , scp );
797
+ WARN_ON_ONCE (idx & ~0x1 );
798
+ return idx << 3 ;
799
+ }
800
+ WARN_ON_ONCE (1 );
801
+ return 0 ;
802
+ }
803
+
804
+ static void srcu_torture_up_read (int idx )
805
+ {
806
+ WARN_ON_ONCE ((reader_flavor && (idx & ~reader_flavor )) || (!reader_flavor && (idx & ~0x1 )));
807
+ if (reader_flavor & SRCU_READ_FLAVOR_FAST )
808
+ srcu_up_read_fast (srcu_ctlp , __srcu_ctr_to_ptr (srcu_ctlp , (idx & 0x8 ) >> 3 ));
809
+ else if ((reader_flavor & SRCU_READ_FLAVOR_NORMAL ) ||
810
+ !(reader_flavor & SRCU_READ_FLAVOR_ALL ))
811
+ srcu_up_read (srcu_ctlp , idx & 0x1 );
812
+ else
813
+ WARN_ON_ONCE (1 );
814
+ }
815
+
765
816
static unsigned long srcu_torture_completed (void )
766
817
{
767
818
return srcu_batches_completed (srcu_ctlp );
@@ -819,6 +870,8 @@ static struct rcu_torture_ops srcu_ops = {
819
870
.readlock = srcu_torture_read_lock ,
820
871
.read_delay = srcu_read_delay ,
821
872
.readunlock = srcu_torture_read_unlock ,
873
+ .down_read = srcu_torture_down_read ,
874
+ .up_read = srcu_torture_up_read ,
822
875
.readlock_held = torture_srcu_read_lock_held ,
823
876
.get_gp_seq = srcu_torture_completed ,
824
877
.gp_diff = rcu_seq_diff ,
@@ -839,6 +892,8 @@ static struct rcu_torture_ops srcu_ops = {
839
892
.irq_capable = 1 ,
840
893
.no_pi_lock = IS_ENABLED (CONFIG_TINY_SRCU ),
841
894
.debug_objects = 1 ,
895
+ .have_up_down = IS_ENABLED (CONFIG_TINY_SRCU )
896
+ ? 0 : SRCU_READ_FLAVOR_NORMAL | SRCU_READ_FLAVOR_FAST ,
842
897
.name = "srcu"
843
898
};
844
899
@@ -864,6 +919,8 @@ static struct rcu_torture_ops srcud_ops = {
864
919
.read_delay = srcu_read_delay ,
865
920
.readunlock = srcu_torture_read_unlock ,
866
921
.readlock_held = torture_srcu_read_lock_held ,
922
+ .down_read = srcu_torture_down_read ,
923
+ .up_read = srcu_torture_up_read ,
867
924
.get_gp_seq = srcu_torture_completed ,
868
925
.gp_diff = rcu_seq_diff ,
869
926
.deferred_free = srcu_torture_deferred_free ,
@@ -883,6 +940,8 @@ static struct rcu_torture_ops srcud_ops = {
883
940
.irq_capable = 1 ,
884
941
.no_pi_lock = IS_ENABLED (CONFIG_TINY_SRCU ),
885
942
.debug_objects = 1 ,
943
+ .have_up_down = IS_ENABLED (CONFIG_TINY_SRCU )
944
+ ? 0 : SRCU_READ_FLAVOR_NORMAL | SRCU_READ_FLAVOR_FAST ,
886
945
.name = "srcud"
887
946
};
888
947
@@ -1994,7 +2053,7 @@ static void rcutorture_one_extend(int *readstate, int newstate, bool insoftirq,
1994
2053
1995
2054
first = idxold1 == 0 ;
1996
2055
WARN_ON_ONCE (idxold2 < 0 );
1997
- WARN_ON_ONCE (idxold2 & ~RCUTORTURE_RDR_ALLBITS );
2056
+ WARN_ON_ONCE (idxold2 & ~( RCUTORTURE_RDR_ALLBITS | RCUTORTURE_RDR_UPDOWN ) );
1998
2057
rcutorture_one_extend_check ("before change" , idxold1 , statesnew , statesold , insoftirq );
1999
2058
rtrsp -> rt_readstate = newstate ;
2000
2059
@@ -2070,6 +2129,11 @@ static void rcutorture_one_extend(int *readstate, int newstate, bool insoftirq,
2070
2129
if (lockit )
2071
2130
raw_spin_unlock_irqrestore (& current -> pi_lock , flags );
2072
2131
}
2132
+ if (statesold & RCUTORTURE_RDR_UPDOWN ) {
2133
+ cur_ops -> up_read ((idxold1 & RCUTORTURE_RDR_MASK_1 ) >> RCUTORTURE_RDR_SHIFT_1 );
2134
+ WARN_ON_ONCE (idxnew1 != -1 );
2135
+ idxold1 = 0 ;
2136
+ }
2073
2137
2074
2138
/* Delay if neither beginning nor end and there was a change. */
2075
2139
if ((statesnew || statesold ) && * readstate && newstate )
@@ -2210,7 +2274,8 @@ static bool rcu_torture_one_read_start(struct rcu_torture_one_read_state *rtorsp
2210
2274
rtorsp -> started = cur_ops -> get_gp_seq ();
2211
2275
rtorsp -> ts = rcu_trace_clock_local ();
2212
2276
rtorsp -> p = rcu_dereference_check (rcu_torture_current ,
2213
- !cur_ops -> readlock_held || cur_ops -> readlock_held ());
2277
+ !cur_ops -> readlock_held || cur_ops -> readlock_held () ||
2278
+ (rtorsp -> readstate & RCUTORTURE_RDR_UPDOWN ));
2214
2279
if (rtorsp -> p == NULL ) {
2215
2280
/* Wait for rcu_torture_writer to get underway */
2216
2281
rcutorture_one_extend (& rtorsp -> readstate , 0 , myid < 0 , trsp , rtorsp -> rtrsp );
@@ -2379,6 +2444,121 @@ rcu_torture_reader(void *arg)
2379
2444
return 0 ;
2380
2445
}
2381
2446
2447
+ struct rcu_torture_one_read_state_updown {
2448
+ struct hrtimer rtorsu_hrt ;
2449
+ bool rtorsu_inuse ;
2450
+ struct torture_random_state rtorsu_trs ;
2451
+ struct rcu_torture_one_read_state rtorsu_rtors ;
2452
+ };
2453
+
2454
+ static struct rcu_torture_one_read_state_updown * updownreaders ;
2455
+ static DEFINE_TORTURE_RANDOM (rcu_torture_updown_rand );
2456
+ static int rcu_torture_updown (void * arg );
2457
+
2458
+ static enum hrtimer_restart rcu_torture_updown_hrt (struct hrtimer * hrtp )
2459
+ {
2460
+ struct rcu_torture_one_read_state_updown * rtorsup ;
2461
+
2462
+ rtorsup = container_of (hrtp , struct rcu_torture_one_read_state_updown , rtorsu_hrt );
2463
+ rcu_torture_one_read_end (& rtorsup -> rtorsu_rtors , & rtorsup -> rtorsu_trs , -1 );
2464
+ smp_store_release (& rtorsup -> rtorsu_inuse , false);
2465
+ return HRTIMER_NORESTART ;
2466
+ }
2467
+
2468
+ static int rcu_torture_updown_init (void )
2469
+ {
2470
+ int i ;
2471
+ struct torture_random_state * rand = & rcu_torture_updown_rand ;
2472
+ int ret ;
2473
+
2474
+ if (n_up_down < 0 )
2475
+ return 0 ;
2476
+ if (!srcu_torture_have_up_down ()) {
2477
+ VERBOSE_TOROUT_STRING ("rcu_torture_updown_init: Disabling up/down reader tests due to lack of primitives" );
2478
+ return 0 ;
2479
+ }
2480
+ updownreaders = kcalloc (n_up_down , sizeof (* updownreaders ), GFP_KERNEL );
2481
+ if (!updownreaders ) {
2482
+ VERBOSE_TOROUT_STRING ("rcu_torture_updown_init: Out of memory, disabling up/down reader tests" );
2483
+ return - ENOMEM ;
2484
+ }
2485
+ for (i = 0 ; i < n_up_down ; i ++ ) {
2486
+ init_rcu_torture_one_read_state (& updownreaders [i ].rtorsu_rtors , rand );
2487
+ hrtimer_setup (& updownreaders [i ].rtorsu_hrt , rcu_torture_updown_hrt , CLOCK_MONOTONIC ,
2488
+ HRTIMER_MODE_REL | HRTIMER_MODE_SOFT );
2489
+ torture_random_init (& updownreaders [i ].rtorsu_trs );
2490
+ init_rcu_torture_one_read_state (& updownreaders [i ].rtorsu_rtors ,
2491
+ & updownreaders [i ].rtorsu_trs );
2492
+ }
2493
+ ret = torture_create_kthread (rcu_torture_updown , rand , updown_task );
2494
+ if (ret ) {
2495
+ kfree (updownreaders );
2496
+ updownreaders = NULL ;
2497
+ }
2498
+ return ret ;
2499
+ }
2500
+
2501
+ static void rcu_torture_updown_cleanup (void )
2502
+ {
2503
+ struct rcu_torture_one_read_state_updown * rtorsup ;
2504
+
2505
+ for (rtorsup = updownreaders ; rtorsup < & updownreaders [n_up_down ]; rtorsup ++ ) {
2506
+ if (!smp_load_acquire (& rtorsup -> rtorsu_inuse ))
2507
+ continue ;
2508
+ if (!hrtimer_cancel (& rtorsup -> rtorsu_hrt ))
2509
+ WARN_ON_ONCE (rtorsup -> rtorsu_inuse );
2510
+
2511
+ }
2512
+ kfree (updownreaders );
2513
+ updownreaders = NULL ;
2514
+ }
2515
+
2516
+ /*
2517
+ * RCU torture up/down reader kthread, starting RCU readers in kthread
2518
+ * context and ending them in hrtimer handlers. Otherwise similar to
2519
+ * rcu_torture_reader().
2520
+ */
2521
+ static int
2522
+ rcu_torture_updown (void * arg )
2523
+ {
2524
+ int idx ;
2525
+ int rawidx ;
2526
+ struct rcu_torture_one_read_state_updown * rtorsup ;
2527
+ ktime_t t ;
2528
+
2529
+ VERBOSE_TOROUT_STRING ("rcu_torture_updown task started" );
2530
+ do {
2531
+ for (rtorsup = updownreaders ; rtorsup < & updownreaders [n_up_down ]; rtorsup ++ ) {
2532
+ if (torture_must_stop ())
2533
+ break ;
2534
+ if (smp_load_acquire (& rtorsup -> rtorsu_inuse ))
2535
+ continue ;
2536
+ init_rcu_torture_one_read_state (& rtorsup -> rtorsu_rtors ,
2537
+ & rtorsup -> rtorsu_trs );
2538
+ rawidx = cur_ops -> down_read ();
2539
+ idx = (rawidx << RCUTORTURE_RDR_SHIFT_1 ) & RCUTORTURE_RDR_MASK_1 ;
2540
+ rtorsup -> rtorsu_rtors .readstate = idx | RCUTORTURE_RDR_UPDOWN ;
2541
+ rtorsup -> rtorsu_rtors .rtrsp ++ ;
2542
+ if (!rcu_torture_one_read_start (& rtorsup -> rtorsu_rtors ,
2543
+ & rtorsup -> rtorsu_trs , -1 )) {
2544
+ schedule_timeout_idle (HZ );
2545
+ continue ;
2546
+ }
2547
+ smp_store_release (& rtorsup -> rtorsu_inuse , true);
2548
+ t = torture_random (& rtorsup -> rtorsu_trs ) & 0xfffff ; // One per million.
2549
+ if (t < 10 * 1000 )
2550
+ t = 200 * 1000 * 1000 ;
2551
+ hrtimer_start (& rtorsup -> rtorsu_hrt , t ,
2552
+ HRTIMER_MODE_REL | HRTIMER_MODE_SOFT );
2553
+ }
2554
+ torture_hrtimeout_ms (1 , 1000 , & rcu_torture_updown_rand );
2555
+ stutter_wait ("rcu_torture_updown" );
2556
+ } while (!torture_must_stop ());
2557
+ rcu_torture_updown_cleanup ();
2558
+ torture_kthread_stopping ("rcu_torture_updown" );
2559
+ return 0 ;
2560
+ }
2561
+
2382
2562
/*
2383
2563
* Randomly Toggle CPUs' callback-offload state. This uses hrtimers to
2384
2564
* increase race probabilities and fuzzes the interval between toggling.
@@ -2633,7 +2813,7 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
2633
2813
"reader_flavor=%x "
2634
2814
"nocbs_nthreads=%d nocbs_toggle=%d "
2635
2815
"test_nmis=%d "
2636
- "preempt_duration=%d preempt_interval=%d\n" ,
2816
+ "preempt_duration=%d preempt_interval=%d n_up_down=%d \n" ,
2637
2817
torture_type , tag , nrealreaders , nrealfakewriters ,
2638
2818
stat_interval , verbose , test_no_idle_hz , shuffle_interval ,
2639
2819
stutter , irqreader , fqs_duration , fqs_holdoff , fqs_stutter ,
@@ -2647,7 +2827,7 @@ rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, const char *tag)
2647
2827
reader_flavor ,
2648
2828
nocbs_nthreads , nocbs_toggle ,
2649
2829
test_nmis ,
2650
- preempt_duration , preempt_interval );
2830
+ preempt_duration , preempt_interval , n_up_down );
2651
2831
}
2652
2832
2653
2833
static int rcutorture_booster_cleanup (unsigned int cpu )
@@ -3750,6 +3930,10 @@ rcu_torture_cleanup(void)
3750
3930
nocb_tasks = NULL ;
3751
3931
}
3752
3932
3933
+ if (updown_task ) {
3934
+ torture_stop_kthread (rcu_torture_updown , updown_task );
3935
+ updown_task = NULL ;
3936
+ }
3753
3937
if (reader_tasks ) {
3754
3938
for (i = 0 ; i < nrealreaders ; i ++ )
3755
3939
torture_stop_kthread (rcu_torture_reader ,
@@ -4284,6 +4468,9 @@ rcu_torture_init(void)
4284
4468
if (torture_init_error (firsterr ))
4285
4469
goto unwind ;
4286
4470
4471
+ firsterr = rcu_torture_updown_init ();
4472
+ if (torture_init_error (firsterr ))
4473
+ goto unwind ;
4287
4474
nrealnocbers = nocbs_nthreads ;
4288
4475
if (WARN_ON (nrealnocbers < 0 ))
4289
4476
nrealnocbers = 1 ;
0 commit comments