diff options
Diffstat (limited to 'kernel/rcu/tree.c')
| -rw-r--r-- | kernel/rcu/tree.c | 84 | 
1 files changed, 26 insertions, 58 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index b043af7b0212..618ec9152e5e 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -3379,29 +3379,26 @@ static void kfree_rcu_work(struct work_struct *work)  }  /* - * Schedule the kfree batch RCU work to run in workqueue context after a GP. - * - * This function is invoked by kfree_rcu_monitor() when the KFREE_DRAIN_JIFFIES - * timeout has been reached. + * This function is invoked after the KFREE_DRAIN_JIFFIES timeout.   */ -static inline bool queue_kfree_rcu_work(struct kfree_rcu_cpu *krcp) +static void kfree_rcu_monitor(struct work_struct *work)  { -	struct kfree_rcu_cpu_work *krwp; -	bool repeat = false; +	struct kfree_rcu_cpu *krcp = container_of(work, +		struct kfree_rcu_cpu, monitor_work.work); +	unsigned long flags;  	int i, j; -	lockdep_assert_held(&krcp->lock); +	raw_spin_lock_irqsave(&krcp->lock, flags); +	// Attempt to start a new batch.  	for (i = 0; i < KFREE_N_BATCHES; i++) { -		krwp = &(krcp->krw_arr[i]); +		struct kfree_rcu_cpu_work *krwp = &(krcp->krw_arr[i]); -		/* -		 * Try to detach bkvhead or head and attach it over any -		 * available corresponding free channel. It can be that -		 * a previous RCU batch is in progress, it means that -		 * immediately to queue another one is not possible so -		 * return false to tell caller to retry. -		 */ +		// Try to detach bkvhead or head and attach it over any +		// available corresponding free channel. It can be that +		// a previous RCU batch is in progress, it means that +		// immediately to queue another one is not possible so +		// in that case the monitor work is rearmed.  		if ((krcp->bkvhead[0] && !krwp->bkvhead_free[0]) ||  			(krcp->bkvhead[1] && !krwp->bkvhead_free[1]) ||  				(krcp->head && !krwp->head_free)) { @@ -3423,57 +3420,28 @@ static inline bool queue_kfree_rcu_work(struct kfree_rcu_cpu *krcp)  			WRITE_ONCE(krcp->count, 0); -			/* -			 * One work is per one batch, so there are three -			 * "free channels", the batch can handle. It can -			 * be that the work is in the pending state when -			 * channels have been detached following by each -			 * other. -			 */ +			// One work is per one batch, so there are three +			// "free channels", the batch can handle. It can +			// be that the work is in the pending state when +			// channels have been detached following by each +			// other.  			queue_rcu_work(system_wq, &krwp->rcu_work);  		} - -		// Repeat if any "free" corresponding channel is still busy. -		if (krcp->bkvhead[0] || krcp->bkvhead[1] || krcp->head) -			repeat = true;  	} -	return !repeat; -} - -static inline void kfree_rcu_drain_unlock(struct kfree_rcu_cpu *krcp, -					  unsigned long flags) -{ -	// Attempt to start a new batch. -	if (queue_kfree_rcu_work(krcp)) { -		// Success! Our job is done here. +	// If there is nothing to detach, it means that our job is +	// successfully done here. In case of having at least one +	// of the channels that is still busy we should rearm the +	// work to repeat an attempt. Because previous batches are +	// still in progress. +	if (!krcp->bkvhead[0] && !krcp->bkvhead[1] && !krcp->head)  		krcp->monitor_todo = false; -		raw_spin_unlock_irqrestore(&krcp->lock, flags); -		return; -	} +	else +		schedule_delayed_work(&krcp->monitor_work, KFREE_DRAIN_JIFFIES); -	// Previous RCU batch still in progress, try again later. -	schedule_delayed_work(&krcp->monitor_work, KFREE_DRAIN_JIFFIES);  	raw_spin_unlock_irqrestore(&krcp->lock, flags);  } -/* - * This function is invoked after the KFREE_DRAIN_JIFFIES timeout. - * It invokes kfree_rcu_drain_unlock() to attempt to start another batch. - */ -static void kfree_rcu_monitor(struct work_struct *work) -{ -	unsigned long flags; -	struct kfree_rcu_cpu *krcp = container_of(work, struct kfree_rcu_cpu, -						 monitor_work.work); - -	raw_spin_lock_irqsave(&krcp->lock, flags); -	if (krcp->monitor_todo) -		kfree_rcu_drain_unlock(krcp, flags); -	else -		raw_spin_unlock_irqrestore(&krcp->lock, flags); -} -  static enum hrtimer_restart  schedule_page_work_fn(struct hrtimer *t)  {  | 
