diff options
Diffstat (limited to 'kernel/workqueue.c')
| -rw-r--r-- | kernel/workqueue.c | 36 |
1 files changed, 30 insertions, 6 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 0ee63af30bd1..8edc87185427 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c | |||
| @@ -1916,6 +1916,12 @@ static void send_mayday(struct work_struct *work) | |||
| 1916 | 1916 | ||
| 1917 | /* mayday mayday mayday */ | 1917 | /* mayday mayday mayday */ |
| 1918 | if (list_empty(&pwq->mayday_node)) { | 1918 | if (list_empty(&pwq->mayday_node)) { |
| 1919 | /* | ||
| 1920 | * If @pwq is for an unbound wq, its base ref may be put at | ||
| 1921 | * any time due to an attribute change. Pin @pwq until the | ||
| 1922 | * rescuer is done with it. | ||
| 1923 | */ | ||
| 1924 | get_pwq(pwq); | ||
| 1919 | list_add_tail(&pwq->mayday_node, &wq->maydays); | 1925 | list_add_tail(&pwq->mayday_node, &wq->maydays); |
| 1920 | wake_up_process(wq->rescuer->task); | 1926 | wake_up_process(wq->rescuer->task); |
| 1921 | } | 1927 | } |
| @@ -2398,6 +2404,7 @@ static int rescuer_thread(void *__rescuer) | |||
| 2398 | struct worker *rescuer = __rescuer; | 2404 | struct worker *rescuer = __rescuer; |
| 2399 | struct workqueue_struct *wq = rescuer->rescue_wq; | 2405 | struct workqueue_struct *wq = rescuer->rescue_wq; |
| 2400 | struct list_head *scheduled = &rescuer->scheduled; | 2406 | struct list_head *scheduled = &rescuer->scheduled; |
| 2407 | bool should_stop; | ||
| 2401 | 2408 | ||
| 2402 | set_user_nice(current, RESCUER_NICE_LEVEL); | 2409 | set_user_nice(current, RESCUER_NICE_LEVEL); |
| 2403 | 2410 | ||
| @@ -2409,11 +2416,15 @@ static int rescuer_thread(void *__rescuer) | |||
| 2409 | repeat: | 2416 | repeat: |
| 2410 | set_current_state(TASK_INTERRUPTIBLE); | 2417 | set_current_state(TASK_INTERRUPTIBLE); |
| 2411 | 2418 | ||
| 2412 | if (kthread_should_stop()) { | 2419 | /* |
| 2413 | __set_current_state(TASK_RUNNING); | 2420 | * By the time the rescuer is requested to stop, the workqueue |
| 2414 | rescuer->task->flags &= ~PF_WQ_WORKER; | 2421 | * shouldn't have any work pending, but @wq->maydays may still have |
| 2415 | return 0; | 2422 | * pwq(s) queued. This can happen by non-rescuer workers consuming |
| 2416 | } | 2423 | * all the work items before the rescuer got to them. Go through |
| 2424 | * @wq->maydays processing before acting on should_stop so that the | ||
| 2425 | * list is always empty on exit. | ||
| 2426 | */ | ||
| 2427 | should_stop = kthread_should_stop(); | ||
| 2417 | 2428 | ||
| 2418 | /* see whether any pwq is asking for help */ | 2429 | /* see whether any pwq is asking for help */ |
| 2419 | spin_lock_irq(&wq_mayday_lock); | 2430 | spin_lock_irq(&wq_mayday_lock); |
| @@ -2445,6 +2456,12 @@ repeat: | |||
| 2445 | process_scheduled_works(rescuer); | 2456 | process_scheduled_works(rescuer); |
| 2446 | 2457 | ||
| 2447 | /* | 2458 | /* |
| 2459 | * Put the reference grabbed by send_mayday(). @pool won't | ||
| 2460 | * go away while we're holding its lock. | ||
| 2461 | */ | ||
| 2462 | put_pwq(pwq); | ||
| 2463 | |||
| 2464 | /* | ||
| 2448 | * Leave this pool. If keep_working() is %true, notify a | 2465 | * Leave this pool. If keep_working() is %true, notify a |
| 2449 | * regular worker; otherwise, we end up with 0 concurrency | 2466 | * regular worker; otherwise, we end up with 0 concurrency |
| 2450 | * and stalling the execution. | 2467 | * and stalling the execution. |
| @@ -2459,6 +2476,12 @@ repeat: | |||
| 2459 | 2476 | ||
| 2460 | spin_unlock_irq(&wq_mayday_lock); | 2477 | spin_unlock_irq(&wq_mayday_lock); |
| 2461 | 2478 | ||
| 2479 | if (should_stop) { | ||
| 2480 | __set_current_state(TASK_RUNNING); | ||
| 2481 | rescuer->task->flags &= ~PF_WQ_WORKER; | ||
| 2482 | return 0; | ||
| 2483 | } | ||
| 2484 | |||
| 2462 | /* rescuers should never participate in concurrency management */ | 2485 | /* rescuers should never participate in concurrency management */ |
| 2463 | WARN_ON_ONCE(!(rescuer->flags & WORKER_NOT_RUNNING)); | 2486 | WARN_ON_ONCE(!(rescuer->flags & WORKER_NOT_RUNNING)); |
| 2464 | schedule(); | 2487 | schedule(); |
| @@ -4100,7 +4123,8 @@ static void wq_update_unbound_numa(struct workqueue_struct *wq, int cpu, | |||
| 4100 | if (!pwq) { | 4123 | if (!pwq) { |
| 4101 | pr_warning("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n", | 4124 | pr_warning("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n", |
| 4102 | wq->name); | 4125 | wq->name); |
| 4103 | goto out_unlock; | 4126 | mutex_lock(&wq->mutex); |
| 4127 | goto use_dfl_pwq; | ||
| 4104 | } | 4128 | } |
| 4105 | 4129 | ||
| 4106 | /* | 4130 | /* |
