diff options
Diffstat (limited to 'kernel/workqueue.c')
| -rw-r--r-- | kernel/workqueue.c | 49 | 
1 files changed, 35 insertions, 14 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 11869faa6819..5ca7ce9ce754 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -79,7 +79,9 @@ enum {  	MAX_IDLE_WORKERS_RATIO	= 4,		/* 1/4 of busy can be idle */  	IDLE_WORKER_TIMEOUT	= 300 * HZ,	/* keep idle ones for 5 mins */ -	MAYDAY_INITIAL_TIMEOUT	= HZ / 100,	/* call for help after 10ms */ +	MAYDAY_INITIAL_TIMEOUT  = HZ / 100 >= 2 ? HZ / 100 : 2, +						/* call for help after 10ms +						   (min two ticks) */  	MAYDAY_INTERVAL		= HZ / 10,	/* and then every 100ms */  	CREATE_COOLDOWN		= HZ,		/* time to breath after fail */  	TRUSTEE_COOLDOWN	= HZ / 10,	/* for trustee draining */ @@ -249,10 +251,12 @@ struct workqueue_struct *system_wq __read_mostly;  struct workqueue_struct *system_long_wq __read_mostly;  struct workqueue_struct *system_nrt_wq __read_mostly;  struct workqueue_struct *system_unbound_wq __read_mostly; +struct workqueue_struct *system_freezable_wq __read_mostly;  EXPORT_SYMBOL_GPL(system_wq);  EXPORT_SYMBOL_GPL(system_long_wq);  EXPORT_SYMBOL_GPL(system_nrt_wq);  EXPORT_SYMBOL_GPL(system_unbound_wq); +EXPORT_SYMBOL_GPL(system_freezable_wq);  #define CREATE_TRACE_POINTS  #include <trace/events/workqueue.h> @@ -314,6 +318,11 @@ static inline int __next_wq_cpu(int cpu, const struct cpumask *mask,  static struct debug_obj_descr work_debug_descr; +static void *work_debug_hint(void *addr) +{ +	return ((struct work_struct *) addr)->func; +} +  /*   * fixup_init is called when:   * - an active object is initialized @@ -385,6 +394,7 @@ static int work_fixup_free(void *addr, enum debug_obj_state state)  static struct debug_obj_descr work_debug_descr = {  	.name		= "work_struct", +	.debug_hint	= work_debug_hint,  	.fixup_init	= work_fixup_init,  	.fixup_activate	= work_fixup_activate,  	.fixup_free	= work_fixup_free, @@ -2047,6 +2057,15 @@ repeat:  				move_linked_works(work, scheduled, &n);  		process_scheduled_works(rescuer); + +		/* +		 * Leave this gcwq.  If keep_working() is %true, notify a +		 * regular worker; otherwise, we end up with 0 concurrency +		 * and stalling the execution. +		 */ +		if (keep_working(gcwq)) +			wake_up_worker(gcwq); +  		spin_unlock_irq(&gcwq->lock);  	} @@ -2956,7 +2975,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *name,  	 */  	spin_lock(&workqueue_lock); -	if (workqueue_freezing && wq->flags & WQ_FREEZEABLE) +	if (workqueue_freezing && wq->flags & WQ_FREEZABLE)  		for_each_cwq_cpu(cpu, wq)  			get_cwq(cpu, wq)->max_active = 0; @@ -3068,7 +3087,7 @@ void workqueue_set_max_active(struct workqueue_struct *wq, int max_active)  		spin_lock_irq(&gcwq->lock); -		if (!(wq->flags & WQ_FREEZEABLE) || +		if (!(wq->flags & WQ_FREEZABLE) ||  		    !(gcwq->flags & GCWQ_FREEZING))  			get_cwq(gcwq->cpu, wq)->max_active = max_active; @@ -3318,7 +3337,7 @@ static int __cpuinit trustee_thread(void *__gcwq)  	 * want to get it over with ASAP - spam rescuers, wake up as  	 * many idlers as necessary and create new ones till the  	 * worklist is empty.  Note that if the gcwq is frozen, there -	 * may be frozen works in freezeable cwqs.  Don't declare +	 * may be frozen works in freezable cwqs.  Don't declare  	 * completion while frozen.  	 */  	while (gcwq->nr_workers != gcwq->nr_idle || @@ -3576,9 +3595,9 @@ EXPORT_SYMBOL_GPL(work_on_cpu);  /**   * freeze_workqueues_begin - begin freezing workqueues   * - * Start freezing workqueues.  After this function returns, all - * freezeable workqueues will queue new works to their frozen_works - * list instead of gcwq->worklist. + * Start freezing workqueues.  After this function returns, all freezable + * workqueues will queue new works to their frozen_works list instead of + * gcwq->worklist.   *   * CONTEXT:   * Grabs and releases workqueue_lock and gcwq->lock's. @@ -3604,7 +3623,7 @@ void freeze_workqueues_begin(void)  		list_for_each_entry(wq, &workqueues, list) {  			struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); -			if (cwq && wq->flags & WQ_FREEZEABLE) +			if (cwq && wq->flags & WQ_FREEZABLE)  				cwq->max_active = 0;  		} @@ -3615,7 +3634,7 @@ void freeze_workqueues_begin(void)  }  /** - * freeze_workqueues_busy - are freezeable workqueues still busy? + * freeze_workqueues_busy - are freezable workqueues still busy?   *   * Check whether freezing is complete.  This function must be called   * between freeze_workqueues_begin() and thaw_workqueues(). @@ -3624,8 +3643,8 @@ void freeze_workqueues_begin(void)   * Grabs and releases workqueue_lock.   *   * RETURNS: - * %true if some freezeable workqueues are still busy.  %false if - * freezing is complete. + * %true if some freezable workqueues are still busy.  %false if freezing + * is complete.   */  bool freeze_workqueues_busy(void)  { @@ -3645,7 +3664,7 @@ bool freeze_workqueues_busy(void)  		list_for_each_entry(wq, &workqueues, list) {  			struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); -			if (!cwq || !(wq->flags & WQ_FREEZEABLE)) +			if (!cwq || !(wq->flags & WQ_FREEZABLE))  				continue;  			BUG_ON(cwq->nr_active < 0); @@ -3690,7 +3709,7 @@ void thaw_workqueues(void)  		list_for_each_entry(wq, &workqueues, list) {  			struct cpu_workqueue_struct *cwq = get_cwq(cpu, wq); -			if (!cwq || !(wq->flags & WQ_FREEZEABLE)) +			if (!cwq || !(wq->flags & WQ_FREEZABLE))  				continue;  			/* restore max_active and repopulate worklist */ @@ -3764,8 +3783,10 @@ static int __init init_workqueues(void)  	system_nrt_wq = alloc_workqueue("events_nrt", WQ_NON_REENTRANT, 0);  	system_unbound_wq = alloc_workqueue("events_unbound", WQ_UNBOUND,  					    WQ_UNBOUND_MAX_ACTIVE); +	system_freezable_wq = alloc_workqueue("events_freezable", +					      WQ_FREEZABLE, 0);  	BUG_ON(!system_wq || !system_long_wq || !system_nrt_wq || -	       !system_unbound_wq); +	       !system_unbound_wq || !system_freezable_wq);  	return 0;  }  early_initcall(init_workqueues);  | 
