diff options
Diffstat (limited to 'kernel/rcu/rcutorture.c')
| -rw-r--r-- | kernel/rcu/rcutorture.c | 72 | 
1 files changed, 58 insertions, 14 deletions
| diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 503c2aa845a4..634df26a2c27 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c @@ -357,6 +357,10 @@ struct rcu_torture_ops {  	bool (*poll_gp_state_exp)(unsigned long oldstate);  	void (*cond_sync_exp)(unsigned long oldstate);  	void (*cond_sync_exp_full)(struct rcu_gp_oldstate *rgosp); +	unsigned long (*get_comp_state)(void); +	void (*get_comp_state_full)(struct rcu_gp_oldstate *rgosp); +	bool (*same_gp_state)(unsigned long oldstate1, unsigned long oldstate2); +	bool (*same_gp_state_full)(struct rcu_gp_oldstate *rgosp1, struct rcu_gp_oldstate *rgosp2);  	unsigned long (*get_gp_state)(void);  	void (*get_gp_state_full)(struct rcu_gp_oldstate *rgosp);  	unsigned long (*get_gp_completed)(void); @@ -510,7 +514,7 @@ static unsigned long rcu_no_completed(void)  static void rcu_torture_deferred_free(struct rcu_torture *p)  { -	call_rcu(&p->rtort_rcu, rcu_torture_cb); +	call_rcu_hurry(&p->rtort_rcu, rcu_torture_cb);  }  static void rcu_sync_torture_init(void) @@ -535,6 +539,10 @@ static struct rcu_torture_ops rcu_ops = {  	.deferred_free		= rcu_torture_deferred_free,  	.sync			= synchronize_rcu,  	.exp_sync		= synchronize_rcu_expedited, +	.same_gp_state		= same_state_synchronize_rcu, +	.same_gp_state_full	= same_state_synchronize_rcu_full, +	.get_comp_state		= get_completed_synchronize_rcu, +	.get_comp_state_full	= get_completed_synchronize_rcu_full,  	.get_gp_state		= get_state_synchronize_rcu,  	.get_gp_state_full	= get_state_synchronize_rcu_full,  	.get_gp_completed	= get_completed_synchronize_rcu, @@ -551,7 +559,7 @@ static struct rcu_torture_ops rcu_ops = {  	.start_gp_poll_exp_full	= start_poll_synchronize_rcu_expedited_full,  	.poll_gp_state_exp	= poll_state_synchronize_rcu,  	.cond_sync_exp		= cond_synchronize_rcu_expedited, -	.call			= call_rcu, +	.call			= call_rcu_hurry,  	.cb_barrier		= rcu_barrier,  	.fqs			= rcu_force_quiescent_state,  	.stats			= NULL, @@ -615,10 +623,14 @@ static struct rcu_torture_ops rcu_busted_ops = {  DEFINE_STATIC_SRCU(srcu_ctl);  static struct srcu_struct srcu_ctld;  static struct srcu_struct *srcu_ctlp = &srcu_ctl; +static struct rcu_torture_ops srcud_ops;  static int srcu_torture_read_lock(void) __acquires(srcu_ctlp)  { -	return srcu_read_lock(srcu_ctlp); +	if (cur_ops == &srcud_ops) +		return srcu_read_lock_nmisafe(srcu_ctlp); +	else +		return srcu_read_lock(srcu_ctlp);  }  static void @@ -642,7 +654,10 @@ srcu_read_delay(struct torture_random_state *rrsp, struct rt_read_seg *rtrsp)  static void srcu_torture_read_unlock(int idx) __releases(srcu_ctlp)  { -	srcu_read_unlock(srcu_ctlp, idx); +	if (cur_ops == &srcud_ops) +		srcu_read_unlock_nmisafe(srcu_ctlp, idx); +	else +		srcu_read_unlock(srcu_ctlp, idx);  }  static int torture_srcu_read_lock_held(void) @@ -848,7 +863,7 @@ static void rcu_tasks_torture_deferred_free(struct rcu_torture *p)  static void synchronize_rcu_mult_test(void)  { -	synchronize_rcu_mult(call_rcu_tasks, call_rcu); +	synchronize_rcu_mult(call_rcu_tasks, call_rcu_hurry);  }  static struct rcu_torture_ops tasks_ops = { @@ -1258,13 +1273,15 @@ static void rcu_torture_write_types(void)  	} else if (gp_normal && !cur_ops->deferred_free) {  		pr_alert("%s: gp_normal without primitives.\n", __func__);  	} -	if (gp_poll1 && cur_ops->start_gp_poll && cur_ops->poll_gp_state) { +	if (gp_poll1 && cur_ops->get_comp_state && cur_ops->same_gp_state && +	    cur_ops->start_gp_poll && cur_ops->poll_gp_state) {  		synctype[nsynctypes++] = RTWS_POLL_GET;  		pr_info("%s: Testing polling GPs.\n", __func__);  	} else if (gp_poll && (!cur_ops->start_gp_poll || !cur_ops->poll_gp_state)) {  		pr_alert("%s: gp_poll without primitives.\n", __func__);  	} -	if (gp_poll_full1 && cur_ops->start_gp_poll_full && cur_ops->poll_gp_state_full) { +	if (gp_poll_full1 && cur_ops->get_comp_state_full && cur_ops->same_gp_state_full +	    && cur_ops->start_gp_poll_full && cur_ops->poll_gp_state_full) {  		synctype[nsynctypes++] = RTWS_POLL_GET_FULL;  		pr_info("%s: Testing polling full-state GPs.\n", __func__);  	} else if (gp_poll_full && (!cur_ops->start_gp_poll_full || !cur_ops->poll_gp_state_full)) { @@ -1339,14 +1356,18 @@ rcu_torture_writer(void *arg)  	struct rcu_gp_oldstate cookie_full;  	int expediting = 0;  	unsigned long gp_snap; +	unsigned long gp_snap1;  	struct rcu_gp_oldstate gp_snap_full; +	struct rcu_gp_oldstate gp_snap1_full;  	int i;  	int idx;  	int oldnice = task_nice(current); +	struct rcu_gp_oldstate rgo[NUM_ACTIVE_RCU_POLL_FULL_OLDSTATE];  	struct rcu_torture *rp;  	struct rcu_torture *old_rp;  	static DEFINE_TORTURE_RANDOM(rand);  	bool stutter_waited; +	unsigned long ulo[NUM_ACTIVE_RCU_POLL_OLDSTATE];  	VERBOSE_TOROUT_STRING("rcu_torture_writer task started");  	if (!can_expedite) @@ -1463,20 +1484,43 @@ rcu_torture_writer(void *arg)  				break;  			case RTWS_POLL_GET:  				rcu_torture_writer_state = RTWS_POLL_GET; +				for (i = 0; i < ARRAY_SIZE(ulo); i++) +					ulo[i] = cur_ops->get_comp_state();  				gp_snap = cur_ops->start_gp_poll();  				rcu_torture_writer_state = RTWS_POLL_WAIT; -				while (!cur_ops->poll_gp_state(gp_snap)) +				while (!cur_ops->poll_gp_state(gp_snap)) { +					gp_snap1 = cur_ops->get_gp_state(); +					for (i = 0; i < ARRAY_SIZE(ulo); i++) +						if (cur_ops->poll_gp_state(ulo[i]) || +						    cur_ops->same_gp_state(ulo[i], gp_snap1)) { +							ulo[i] = gp_snap1; +							break; +						} +					WARN_ON_ONCE(i >= ARRAY_SIZE(ulo));  					torture_hrtimeout_jiffies(torture_random(&rand) % 16,  								  &rand); +				}  				rcu_torture_pipe_update(old_rp);  				break;  			case RTWS_POLL_GET_FULL:  				rcu_torture_writer_state = RTWS_POLL_GET_FULL; +				for (i = 0; i < ARRAY_SIZE(rgo); i++) +					cur_ops->get_comp_state_full(&rgo[i]);  				cur_ops->start_gp_poll_full(&gp_snap_full);  				rcu_torture_writer_state = RTWS_POLL_WAIT_FULL; -				while (!cur_ops->poll_gp_state_full(&gp_snap_full)) +				while (!cur_ops->poll_gp_state_full(&gp_snap_full)) { +					cur_ops->get_gp_state_full(&gp_snap1_full); +					for (i = 0; i < ARRAY_SIZE(rgo); i++) +						if (cur_ops->poll_gp_state_full(&rgo[i]) || +						    cur_ops->same_gp_state_full(&rgo[i], +										&gp_snap1_full)) { +							rgo[i] = gp_snap1_full; +							break; +						} +					WARN_ON_ONCE(i >= ARRAY_SIZE(rgo));  					torture_hrtimeout_jiffies(torture_random(&rand) % 16,  								  &rand); +				}  				rcu_torture_pipe_update(old_rp);  				break;  			case RTWS_POLL_GET_EXP: @@ -3388,13 +3432,13 @@ static void rcu_test_debug_objects(void)  	/* Try to queue the rh2 pair of callbacks for the same grace period. */  	preempt_disable(); /* Prevent preemption from interrupting test. */  	rcu_read_lock(); /* Make it impossible to finish a grace period. */ -	call_rcu(&rh1, rcu_torture_leak_cb); /* Start grace period. */ +	call_rcu_hurry(&rh1, rcu_torture_leak_cb); /* Start grace period. */  	local_irq_disable(); /* Make it harder to start a new grace period. */ -	call_rcu(&rh2, rcu_torture_leak_cb); -	call_rcu(&rh2, rcu_torture_err_cb); /* Duplicate callback. */ +	call_rcu_hurry(&rh2, rcu_torture_leak_cb); +	call_rcu_hurry(&rh2, rcu_torture_err_cb); /* Duplicate callback. */  	if (rhp) { -		call_rcu(rhp, rcu_torture_leak_cb); -		call_rcu(rhp, rcu_torture_err_cb); /* Another duplicate callback. */ +		call_rcu_hurry(rhp, rcu_torture_leak_cb); +		call_rcu_hurry(rhp, rcu_torture_err_cb); /* Another duplicate callback. */  	}  	local_irq_enable();  	rcu_read_unlock(); |