diff options
Diffstat (limited to 'kernel/rcutorture.c')
| -rw-r--r-- | kernel/rcutorture.c | 72 | 
1 files changed, 44 insertions, 28 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index e66b34ab755..25b15033c61 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c @@ -49,8 +49,7 @@  #include <asm/byteorder.h>  MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and " -	      "Josh Triplett <josh@freedesktop.org>"); +MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and Josh Triplett <josh@freedesktop.org>");  static int nreaders = -1;	/* # reader threads, defaults to 2*ncpus */  static int nfakewriters = 4;	/* # fake writer threads */ @@ -206,6 +205,7 @@ static unsigned long boost_starttime;	/* jiffies of next boost test start. */  DEFINE_MUTEX(boost_mutex);		/* protect setting boost_starttime */  					/*  and boost task create/destroy. */  static atomic_t barrier_cbs_count;	/* Barrier callbacks registered. */ +static bool barrier_phase;		/* Test phase. */  static atomic_t barrier_cbs_invoked;	/* Barrier callbacks invoked. */  static wait_queue_head_t *barrier_cbs_wq; /* Coordinate barrier testing. */  static DECLARE_WAIT_QUEUE_HEAD(barrier_wq); @@ -407,8 +407,9 @@ rcu_torture_cb(struct rcu_head *p)  	if (++rp->rtort_pipe_count >= RCU_TORTURE_PIPE_LEN) {  		rp->rtort_mbtest = 0;  		rcu_torture_free(rp); -	} else +	} else {  		cur_ops->deferred_free(rp); +	}  }  static int rcu_no_completed(void) @@ -635,6 +636,17 @@ static void srcu_torture_synchronize(void)  	synchronize_srcu(&srcu_ctl);  } +static void srcu_torture_call(struct rcu_head *head, +			      void (*func)(struct rcu_head *head)) +{ +	call_srcu(&srcu_ctl, head, func); +} + +static void srcu_torture_barrier(void) +{ +	srcu_barrier(&srcu_ctl); +} +  static int srcu_torture_stats(char *page)  {  	int cnt = 0; @@ -661,8 +673,8 @@ static struct rcu_torture_ops srcu_ops = {  	.completed	= srcu_torture_completed,  	.deferred_free	= srcu_torture_deferred_free,  	.sync		= srcu_torture_synchronize, -	.call		= NULL, -	.cb_barrier	= NULL, +	.call		= srcu_torture_call, +	.cb_barrier	= srcu_torture_barrier,  	.stats		= srcu_torture_stats,  	.name		= "srcu"  }; @@ -1013,7 +1025,11 @@ rcu_torture_fakewriter(void *arg)  	do {  		schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);  		udelay(rcu_random(&rand) & 0x3ff); -		cur_ops->sync(); +		if (cur_ops->cb_barrier != NULL && +		    rcu_random(&rand) % (nfakewriters * 8) == 0) +			cur_ops->cb_barrier(); +		else +			cur_ops->sync();  		rcu_stutter_wait("rcu_torture_fakewriter");  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); @@ -1183,27 +1199,27 @@ rcu_torture_printk(char *page)  	}  	cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);  	cnt += sprintf(&page[cnt], -		       "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d " -		       "rtmbe: %d rtbke: %ld rtbre: %ld " -		       "rtbf: %ld rtb: %ld nt: %ld " -		       "onoff: %ld/%ld:%ld/%ld " -		       "barrier: %ld/%ld:%ld", +		       "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d ",  		       rcu_torture_current,  		       rcu_torture_current_version,  		       list_empty(&rcu_torture_freelist),  		       atomic_read(&n_rcu_torture_alloc),  		       atomic_read(&n_rcu_torture_alloc_fail), -		       atomic_read(&n_rcu_torture_free), +		       atomic_read(&n_rcu_torture_free)); +	cnt += sprintf(&page[cnt], "rtmbe: %d rtbke: %ld rtbre: %ld ",  		       atomic_read(&n_rcu_torture_mberror),  		       n_rcu_torture_boost_ktrerror, -		       n_rcu_torture_boost_rterror, +		       n_rcu_torture_boost_rterror); +	cnt += sprintf(&page[cnt], "rtbf: %ld rtb: %ld nt: %ld ",  		       n_rcu_torture_boost_failure,  		       n_rcu_torture_boosts, -		       n_rcu_torture_timers, +		       n_rcu_torture_timers); +	cnt += sprintf(&page[cnt], "onoff: %ld/%ld:%ld/%ld ",  		       n_online_successes,  		       n_online_attempts,  		       n_offline_successes, -		       n_offline_attempts, +		       n_offline_attempts); +	cnt += sprintf(&page[cnt], "barrier: %ld/%ld:%ld",  		       n_barrier_successes,  		       n_barrier_attempts,  		       n_rcu_torture_barrier_error); @@ -1445,8 +1461,7 @@ rcu_torture_shutdown(void *arg)  		delta = shutdown_time - jiffies_snap;  		if (verbose)  			printk(KERN_ALERT "%s" TORTURE_FLAG -			       "rcu_torture_shutdown task: %lu " -			       "jiffies remaining\n", +			       "rcu_torture_shutdown task: %lu jiffies remaining\n",  			       torture_type, delta);  		schedule_timeout_interruptible(delta);  		jiffies_snap = ACCESS_ONCE(jiffies); @@ -1498,8 +1513,7 @@ rcu_torture_onoff(void *arg)  			if (cpu_down(cpu) == 0) {  				if (verbose)  					printk(KERN_ALERT "%s" TORTURE_FLAG -					       "rcu_torture_onoff task: " -					       "offlined %d\n", +					       "rcu_torture_onoff task: offlined %d\n",  					       torture_type, cpu);  				n_offline_successes++;  			} @@ -1512,8 +1526,7 @@ rcu_torture_onoff(void *arg)  			if (cpu_up(cpu) == 0) {  				if (verbose)  					printk(KERN_ALERT "%s" TORTURE_FLAG -					       "rcu_torture_onoff task: " -					       "onlined %d\n", +					       "rcu_torture_onoff task: onlined %d\n",  					       torture_type, cpu);  				n_online_successes++;  			} @@ -1631,6 +1644,7 @@ void rcu_torture_barrier_cbf(struct rcu_head *rcu)  static int rcu_torture_barrier_cbs(void *arg)  {  	long myid = (long)arg; +	bool lastphase = 0;  	struct rcu_head rcu;  	init_rcu_head_on_stack(&rcu); @@ -1638,9 +1652,11 @@ static int rcu_torture_barrier_cbs(void *arg)  	set_user_nice(current, 19);  	do {  		wait_event(barrier_cbs_wq[myid], -			   atomic_read(&barrier_cbs_count) == n_barrier_cbs || +			   barrier_phase != lastphase ||  			   kthread_should_stop() ||  			   fullstop != FULLSTOP_DONTSTOP); +		lastphase = barrier_phase; +		smp_mb(); /* ensure barrier_phase load before ->call(). */  		if (kthread_should_stop() || fullstop != FULLSTOP_DONTSTOP)  			break;  		cur_ops->call(&rcu, rcu_torture_barrier_cbf); @@ -1665,7 +1681,8 @@ static int rcu_torture_barrier(void *arg)  	do {  		atomic_set(&barrier_cbs_invoked, 0);  		atomic_set(&barrier_cbs_count, n_barrier_cbs); -		/* wake_up() path contains the required barriers. */ +		smp_mb(); /* Ensure barrier_phase after prior assignments. */ +		barrier_phase = !barrier_phase;  		for (i = 0; i < n_barrier_cbs; i++)  			wake_up(&barrier_cbs_wq[i]);  		wait_event(barrier_wq, @@ -1684,7 +1701,7 @@ static int rcu_torture_barrier(void *arg)  		schedule_timeout_interruptible(HZ / 10);  	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);  	VERBOSE_PRINTK_STRING("rcu_torture_barrier task stopping"); -	rcutorture_shutdown_absorb("rcu_torture_barrier_cbs"); +	rcutorture_shutdown_absorb("rcu_torture_barrier");  	while (!kthread_should_stop())  		schedule_timeout_interruptible(1);  	return 0; @@ -1908,8 +1925,8 @@ rcu_torture_init(void)  	static struct rcu_torture_ops *torture_ops[] =  		{ &rcu_ops, &rcu_sync_ops, &rcu_expedited_ops,  		  &rcu_bh_ops, &rcu_bh_sync_ops, &rcu_bh_expedited_ops, -		  &srcu_ops, &srcu_sync_ops, &srcu_raw_ops, -		  &srcu_raw_sync_ops, &srcu_expedited_ops, +		  &srcu_ops, &srcu_sync_ops, &srcu_expedited_ops, +		  &srcu_raw_ops, &srcu_raw_sync_ops,  		  &sched_ops, &sched_sync_ops, &sched_expedited_ops, };  	mutex_lock(&fullstop_mutex); @@ -1931,8 +1948,7 @@ rcu_torture_init(void)  		return -EINVAL;  	}  	if (cur_ops->fqs == NULL && fqs_duration != 0) { -		printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero " -				  "fqs_duration, fqs disabled.\n"); +		printk(KERN_ALERT "rcu-torture: ->fqs NULL and non-zero fqs_duration, fqs disabled.\n");  		fqs_duration = 0;  	}  	if (cur_ops->init)  |