Merge branch 'for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Jun 2014 21:56:49 +0000 (14:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Jun 2014 21:56:49 +0000 (14:56 -0700)
Pull workqueue updates from Tejun Heo:
 "Lai simplified worker destruction path and internal workqueue locking
  and there are some other minor changes.

  Except for the removal of some long-deprecated interfaces which
  haven't had any in-kernel user for quite a while, there shouldn't be
  any difference to workqueue users"

* 'for-3.16' of git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq:
  kernel/workqueue.c: pr_warning/pr_warn & printk/pr_info
  workqueue: remove the confusing POOL_FREEZING
  workqueue: rename first_worker() to first_idle_worker()
  workqueue: remove unused work_clear_pending()
  workqueue: remove unused WORK_CPU_END
  workqueue: declare system_highpri_wq
  workqueue: use generic attach/detach routine for rescuers
  workqueue: separate pool-attaching code out from create_worker()
  workqueue: rename manager_mutex to attach_mutex
  workqueue: narrow the protection range of manager_mutex
  workqueue: convert worker_idr to worker_ida
  workqueue: separate iteration role from worker_idr
  workqueue: destroy worker directly in the idle timeout handler
  workqueue: async worker destruction
  workqueue: destroy_worker() should destroy idle workers only
  workqueue: use manager lock only to protect worker_idr
  workqueue: Remove deprecated system_nrt[_freezable]_wq
  workqueue: Remove deprecated flush[_delayed]_work_sync()
  kernel/workqueue.c: pr_warning/pr_warn & printk/pr_info
  workqueue: simplify wq_update_unbound_numa() by jumping to use_dfl_pwq if the target cpumask equals wq's

1  2 
kernel/workqueue.c

diff --combined kernel/workqueue.c
@@@ -65,15 -65,12 +65,12 @@@ enum 
         * be executing on any CPU.  The pool behaves as an unbound one.
         *
         * Note that DISASSOCIATED should be flipped only while holding
-        * manager_mutex to avoid changing binding state while
-        * create_worker() is in progress.
+        * attach_mutex to avoid changing binding state while
+        * worker_attach_to_pool() is in progress.
         */
-       POOL_MANAGE_WORKERS     = 1 << 0,       /* need to manage workers */
        POOL_DISASSOCIATED      = 1 << 2,       /* cpu can't serve workers */
-       POOL_FREEZING           = 1 << 3,       /* freeze in progress */
  
        /* worker flags */
-       WORKER_STARTED          = 1 << 0,       /* started */
        WORKER_DIE              = 1 << 1,       /* die die die */
        WORKER_IDLE             = 1 << 2,       /* is idle */
        WORKER_PREP             = 1 << 3,       /* preparing to run works */
  
        /*
         * Rescue workers are used only on emergencies and shared by
 -       * all cpus.  Give -20.
 +       * all cpus.  Give MIN_NICE.
         */
 -      RESCUER_NICE_LEVEL      = -20,
 -      HIGHPRI_NICE_LEVEL      = -20,
 +      RESCUER_NICE_LEVEL      = MIN_NICE,
 +      HIGHPRI_NICE_LEVEL      = MIN_NICE,
  
        WQ_NAME_LEN             = 24,
  };
   *    cpu or grabbing pool->lock is enough for read access.  If
   *    POOL_DISASSOCIATED is set, it's identical to L.
   *
-  * MG: pool->manager_mutex and pool->lock protected.  Writes require both
-  *     locks.  Reads can happen under either lock.
+  * A: pool->attach_mutex protected.
   *
   * PL: wq_pool_mutex protected.
   *
@@@ -163,8 -159,11 +159,11 @@@ struct worker_pool 
  
        /* see manage_workers() for details on the two manager mutexes */
        struct mutex            manager_arb;    /* manager arbitration */
-       struct mutex            manager_mutex;  /* manager exclusion */
-       struct idr              worker_idr;     /* MG: worker IDs and iteration */
+       struct mutex            attach_mutex;   /* attach/detach exclusion */
+       struct list_head        workers;        /* A: attached workers */
+       struct completion       *detach_completion; /* all workers detached */
+       struct ida              worker_ida;     /* worker IDs for task name */
  
        struct workqueue_attrs  *attrs;         /* I: worker attributes */
        struct hlist_node       hash_node;      /* PL: unbound_pool_hash node */
@@@ -340,16 -339,6 +339,6 @@@ static void copy_workqueue_attrs(struc
                           lockdep_is_held(&wq->mutex),                 \
                           "sched RCU or wq->mutex should be held")
  
- #ifdef CONFIG_LOCKDEP
- #define assert_manager_or_pool_lock(pool)                             \
-       WARN_ONCE(debug_locks &&                                        \
-                 !lockdep_is_held(&(pool)->manager_mutex) &&           \
-                 !lockdep_is_held(&(pool)->lock),                      \
-                 "pool->manager_mutex or ->lock should be held")
- #else
- #define assert_manager_or_pool_lock(pool)     do { } while (0)
- #endif
  #define for_each_cpu_worker_pool(pool, cpu)                           \
        for ((pool) = &per_cpu(cpu_worker_pools, cpu)[0];               \
             (pool) < &per_cpu(cpu_worker_pools, cpu)[NR_STD_WORKER_POOLS]; \
  /**
   * for_each_pool_worker - iterate through all workers of a worker_pool
   * @worker: iteration cursor
-  * @wi: integer used for iteration
   * @pool: worker_pool to iterate workers of
   *
-  * This must be called with either @pool->manager_mutex or ->lock held.
+  * This must be called with @pool->attach_mutex.
   *
   * The if/else clause exists only for the lockdep assertion and can be
   * ignored.
   */
- #define for_each_pool_worker(worker, wi, pool)                                \
-       idr_for_each_entry(&(pool)->worker_idr, (worker), (wi))         \
-               if (({ assert_manager_or_pool_lock((pool)); false; })) { } \
+ #define for_each_pool_worker(worker, pool)                            \
+       list_for_each_entry((worker), &(pool)->workers, node)           \
+               if (({ lockdep_assert_held(&pool->attach_mutex); false; })) { } \
                else
  
  /**
@@@ -763,13 -751,6 +751,6 @@@ static bool need_to_create_worker(struc
        return need_more_worker(pool) && !may_start_working(pool);
  }
  
- /* Do I need to be the manager? */
- static bool need_to_manage_workers(struct worker_pool *pool)
- {
-       return need_to_create_worker(pool) ||
-               (pool->flags & POOL_MANAGE_WORKERS);
- }
  /* Do we have too many workers and should some go away? */
  static bool too_many_workers(struct worker_pool *pool)
  {
   * Wake up functions.
   */
  
- /* Return the first worker.  Safe with preemption disabled */
- static struct worker *first_worker(struct worker_pool *pool)
+ /* Return the first idle worker.  Safe with preemption disabled */
+ static struct worker *first_idle_worker(struct worker_pool *pool)
  {
        if (unlikely(list_empty(&pool->idle_list)))
                return NULL;
   */
  static void wake_up_worker(struct worker_pool *pool)
  {
-       struct worker *worker = first_worker(pool);
+       struct worker *worker = first_idle_worker(pool);
  
        if (likely(worker))
                wake_up_process(worker->task);
@@@ -885,7 -866,7 +866,7 @@@ struct task_struct *wq_worker_sleeping(
         */
        if (atomic_dec_and_test(&pool->nr_running) &&
            !list_empty(&pool->worklist))
-               to_wakeup = first_worker(pool);
+               to_wakeup = first_idle_worker(pool);
        return to_wakeup ? to_wakeup->task : NULL;
  }
  
@@@ -1621,70 -1602,6 +1602,6 @@@ static void worker_leave_idle(struct wo
        list_del_init(&worker->entry);
  }
  
- /**
-  * worker_maybe_bind_and_lock - try to bind %current to worker_pool and lock it
-  * @pool: target worker_pool
-  *
-  * Bind %current to the cpu of @pool if it is associated and lock @pool.
-  *
-  * Works which are scheduled while the cpu is online must at least be
-  * scheduled to a worker which is bound to the cpu so that if they are
-  * flushed from cpu callbacks while cpu is going down, they are
-  * guaranteed to execute on the cpu.
-  *
-  * This function is to be used by unbound workers and rescuers to bind
-  * themselves to the target cpu and may race with cpu going down or
-  * coming online.  kthread_bind() can't be used because it may put the
-  * worker to already dead cpu and set_cpus_allowed_ptr() can't be used
-  * verbatim as it's best effort and blocking and pool may be
-  * [dis]associated in the meantime.
-  *
-  * This function tries set_cpus_allowed() and locks pool and verifies the
-  * binding against %POOL_DISASSOCIATED which is set during
-  * %CPU_DOWN_PREPARE and cleared during %CPU_ONLINE, so if the worker
-  * enters idle state or fetches works without dropping lock, it can
-  * guarantee the scheduling requirement described in the first paragraph.
-  *
-  * CONTEXT:
-  * Might sleep.  Called without any lock but returns with pool->lock
-  * held.
-  *
-  * Return:
-  * %true if the associated pool is online (@worker is successfully
-  * bound), %false if offline.
-  */
- static bool worker_maybe_bind_and_lock(struct worker_pool *pool)
- __acquires(&pool->lock)
- {
-       while (true) {
-               /*
-                * The following call may fail, succeed or succeed
-                * without actually migrating the task to the cpu if
-                * it races with cpu hotunplug operation.  Verify
-                * against POOL_DISASSOCIATED.
-                */
-               if (!(pool->flags & POOL_DISASSOCIATED))
-                       set_cpus_allowed_ptr(current, pool->attrs->cpumask);
-               spin_lock_irq(&pool->lock);
-               if (pool->flags & POOL_DISASSOCIATED)
-                       return false;
-               if (task_cpu(current) == pool->cpu &&
-                   cpumask_equal(&current->cpus_allowed, pool->attrs->cpumask))
-                       return true;
-               spin_unlock_irq(&pool->lock);
-               /*
-                * We've raced with CPU hot[un]plug.  Give it a breather
-                * and retry migration.  cond_resched() is required here;
-                * otherwise, we might deadlock against cpu_stop trying to
-                * bring down the CPU on non-preemptive kernel.
-                */
-               cpu_relax();
-               cond_resched();
-       }
- }
  static struct worker *alloc_worker(void)
  {
        struct worker *worker;
        if (worker) {
                INIT_LIST_HEAD(&worker->entry);
                INIT_LIST_HEAD(&worker->scheduled);
+               INIT_LIST_HEAD(&worker->node);
                /* on creation a worker is in !idle && prep state */
                worker->flags = WORKER_PREP;
        }
        return worker;
  }
  
+ /**
+  * worker_attach_to_pool() - attach a worker to a pool
+  * @worker: worker to be attached
+  * @pool: the target pool
+  *
+  * Attach @worker to @pool.  Once attached, the %WORKER_UNBOUND flag and
+  * cpu-binding of @worker are kept coordinated with the pool across
+  * cpu-[un]hotplugs.
+  */
+ static void worker_attach_to_pool(struct worker *worker,
+                                  struct worker_pool *pool)
+ {
+       mutex_lock(&pool->attach_mutex);
+       /*
+        * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any
+        * online CPUs.  It'll be re-applied when any of the CPUs come up.
+        */
+       set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
+       /*
+        * The pool->attach_mutex ensures %POOL_DISASSOCIATED remains
+        * stable across this function.  See the comments above the
+        * flag definition for details.
+        */
+       if (pool->flags & POOL_DISASSOCIATED)
+               worker->flags |= WORKER_UNBOUND;
+       list_add_tail(&worker->node, &pool->workers);
+       mutex_unlock(&pool->attach_mutex);
+ }
+ /**
+  * worker_detach_from_pool() - detach a worker from its pool
+  * @worker: worker which is attached to its pool
+  * @pool: the pool @worker is attached to
+  *
+  * Undo the attaching which had been done in worker_attach_to_pool().  The
+  * caller worker shouldn't access to the pool after detached except it has
+  * other reference to the pool.
+  */
+ static void worker_detach_from_pool(struct worker *worker,
+                                   struct worker_pool *pool)
+ {
+       struct completion *detach_completion = NULL;
+       mutex_lock(&pool->attach_mutex);
+       list_del(&worker->node);
+       if (list_empty(&pool->workers))
+               detach_completion = pool->detach_completion;
+       mutex_unlock(&pool->attach_mutex);
+       if (detach_completion)
+               complete(detach_completion);
+ }
  /**
   * create_worker - create a new workqueue worker
   * @pool: pool the new worker will belong to
   *
-  * Create a new worker which is bound to @pool.  The returned worker
-  * can be started by calling start_worker() or destroyed using
-  * destroy_worker().
+  * Create a new worker which is attached to @pool.  The new worker must be
+  * started by start_worker().
   *
   * CONTEXT:
   * Might sleep.  Does GFP_KERNEL allocations.
@@@ -1719,19 -1693,8 +1693,8 @@@ static struct worker *create_worker(str
        int id = -1;
        char id_buf[16];
  
-       lockdep_assert_held(&pool->manager_mutex);
-       /*
-        * ID is needed to determine kthread name.  Allocate ID first
-        * without installing the pointer.
-        */
-       idr_preload(GFP_KERNEL);
-       spin_lock_irq(&pool->lock);
-       id = idr_alloc(&pool->worker_idr, NULL, 0, 0, GFP_NOWAIT);
-       spin_unlock_irq(&pool->lock);
-       idr_preload_end();
+       /* ID is needed to determine kthread name */
+       id = ida_simple_get(&pool->worker_ida, 0, 0, GFP_KERNEL);
        if (id < 0)
                goto fail;
  
        /* prevent userland from meddling with cpumask of workqueue workers */
        worker->task->flags |= PF_NO_SETAFFINITY;
  
-       /*
-        * set_cpus_allowed_ptr() will fail if the cpumask doesn't have any
-        * online CPUs.  It'll be re-applied when any of the CPUs come up.
-        */
-       set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
-       /*
-        * The caller is responsible for ensuring %POOL_DISASSOCIATED
-        * remains stable across this function.  See the comments above the
-        * flag definition for details.
-        */
-       if (pool->flags & POOL_DISASSOCIATED)
-               worker->flags |= WORKER_UNBOUND;
-       /* successful, commit the pointer to idr */
-       spin_lock_irq(&pool->lock);
-       idr_replace(&pool->worker_idr, worker, worker->id);
-       spin_unlock_irq(&pool->lock);
+       /* successful, attach the worker to the pool */
+       worker_attach_to_pool(worker, pool);
  
        return worker;
  
  fail:
-       if (id >= 0) {
-               spin_lock_irq(&pool->lock);
-               idr_remove(&pool->worker_idr, id);
-               spin_unlock_irq(&pool->lock);
-       }
+       if (id >= 0)
+               ida_simple_remove(&pool->worker_ida, id);
        kfree(worker);
        return NULL;
  }
   */
  static void start_worker(struct worker *worker)
  {
-       worker->flags |= WORKER_STARTED;
        worker->pool->nr_workers++;
        worker_enter_idle(worker);
        wake_up_process(worker->task);
@@@ -1818,8 -1761,6 +1761,6 @@@ static int create_and_start_worker(stru
  {
        struct worker *worker;
  
-       mutex_lock(&pool->manager_mutex);
        worker = create_worker(pool);
        if (worker) {
                spin_lock_irq(&pool->lock);
                spin_unlock_irq(&pool->lock);
        }
  
-       mutex_unlock(&pool->manager_mutex);
        return worker ? 0 : -ENOMEM;
  }
  
   * destroy_worker - destroy a workqueue worker
   * @worker: worker to be destroyed
   *
-  * Destroy @worker and adjust @pool stats accordingly.
+  * Destroy @worker and adjust @pool stats accordingly.  The worker should
+  * be idle.
   *
   * CONTEXT:
-  * spin_lock_irq(pool->lock) which is released and regrabbed.
+  * spin_lock_irq(pool->lock).
   */
  static void destroy_worker(struct worker *worker)
  {
        struct worker_pool *pool = worker->pool;
  
-       lockdep_assert_held(&pool->manager_mutex);
        lockdep_assert_held(&pool->lock);
  
        /* sanity check frenzy */
        if (WARN_ON(worker->current_work) ||
-           WARN_ON(!list_empty(&worker->scheduled)))
+           WARN_ON(!list_empty(&worker->scheduled)) ||
+           WARN_ON(!(worker->flags & WORKER_IDLE)))
                return;
  
-       if (worker->flags & WORKER_STARTED)
-               pool->nr_workers--;
-       if (worker->flags & WORKER_IDLE)
-               pool->nr_idle--;
-       /*
-        * Once WORKER_DIE is set, the kworker may destroy itself at any
-        * point.  Pin to ensure the task stays until we're done with it.
-        */
-       get_task_struct(worker->task);
+       pool->nr_workers--;
+       pool->nr_idle--;
  
        list_del_init(&worker->entry);
        worker->flags |= WORKER_DIE;
-       idr_remove(&pool->worker_idr, worker->id);
-       spin_unlock_irq(&pool->lock);
-       kthread_stop(worker->task);
-       put_task_struct(worker->task);
-       kfree(worker);
-       spin_lock_irq(&pool->lock);
+       wake_up_process(worker->task);
  }
  
  static void idle_worker_timeout(unsigned long __pool)
  
        spin_lock_irq(&pool->lock);
  
-       if (too_many_workers(pool)) {
+       while (too_many_workers(pool)) {
                struct worker *worker;
                unsigned long expires;
  
                worker = list_entry(pool->idle_list.prev, struct worker, entry);
                expires = worker->last_active + IDLE_WORKER_TIMEOUT;
  
-               if (time_before(jiffies, expires))
+               if (time_before(jiffies, expires)) {
                        mod_timer(&pool->idle_timer, expires);
-               else {
-                       /* it's been idle for too long, wake up manager */
-                       pool->flags |= POOL_MANAGE_WORKERS;
-                       wake_up_worker(pool);
+                       break;
                }
+               destroy_worker(worker);
        }
  
        spin_unlock_irq(&pool->lock);
@@@ -2016,44 -1938,6 +1938,6 @@@ restart
        return true;
  }
  
- /**
-  * maybe_destroy_worker - destroy workers which have been idle for a while
-  * @pool: pool to destroy workers for
-  *
-  * Destroy @pool workers which have been idle for longer than
-  * IDLE_WORKER_TIMEOUT.
-  *
-  * LOCKING:
-  * spin_lock_irq(pool->lock) which may be released and regrabbed
-  * multiple times.  Called only from manager.
-  *
-  * Return:
-  * %false if no action was taken and pool->lock stayed locked, %true
-  * otherwise.
-  */
- static bool maybe_destroy_workers(struct worker_pool *pool)
- {
-       bool ret = false;
-       while (too_many_workers(pool)) {
-               struct worker *worker;
-               unsigned long expires;
-               worker = list_entry(pool->idle_list.prev, struct worker, entry);
-               expires = worker->last_active + IDLE_WORKER_TIMEOUT;
-               if (time_before(jiffies, expires)) {
-                       mod_timer(&pool->idle_timer, expires);
-                       break;
-               }
-               destroy_worker(worker);
-               ret = true;
-       }
-       return ret;
- }
  /**
   * manage_workers - manage worker pool
   * @worker: self
@@@ -2083,8 -1967,6 +1967,6 @@@ static bool manage_workers(struct worke
        bool ret = false;
  
        /*
-        * Managership is governed by two mutexes - manager_arb and
-        * manager_mutex.  manager_arb handles arbitration of manager role.
         * Anyone who successfully grabs manager_arb wins the arbitration
         * and becomes the manager.  mutex_trylock() on pool->manager_arb
         * failure while holding pool->lock reliably indicates that someone
         * grabbing manager_arb is responsible for actually performing
         * manager duties.  If manager_arb is grabbed and released without
         * actual management, the pool may stall indefinitely.
-        *
-        * manager_mutex is used for exclusion of actual management
-        * operations.  The holder of manager_mutex can be sure that none
-        * of management operations, including creation and destruction of
-        * workers, won't take place until the mutex is released.  Because
-        * manager_mutex doesn't interfere with manager role arbitration,
-        * it is guaranteed that the pool's management, while may be
-        * delayed, won't be disturbed by someone else grabbing
-        * manager_mutex.
         */
        if (!mutex_trylock(&pool->manager_arb))
                return ret;
  
-       /*
-        * With manager arbitration won, manager_mutex would be free in
-        * most cases.  trylock first without dropping @pool->lock.
-        */
-       if (unlikely(!mutex_trylock(&pool->manager_mutex))) {
-               spin_unlock_irq(&pool->lock);
-               mutex_lock(&pool->manager_mutex);
-               spin_lock_irq(&pool->lock);
-               ret = true;
-       }
-       pool->flags &= ~POOL_MANAGE_WORKERS;
-       /*
-        * Destroy and then create so that may_start_working() is true
-        * on return.
-        */
-       ret |= maybe_destroy_workers(pool);
        ret |= maybe_create_worker(pool);
  
-       mutex_unlock(&pool->manager_mutex);
        mutex_unlock(&pool->manager_arb);
        return ret;
  }
@@@ -2314,6 -2168,11 +2168,11 @@@ woke_up
                spin_unlock_irq(&pool->lock);
                WARN_ON_ONCE(!list_empty(&worker->entry));
                worker->task->flags &= ~PF_WQ_WORKER;
+               set_task_comm(worker->task, "kworker/dying");
+               ida_simple_remove(&pool->worker_ida, worker->id);
+               worker_detach_from_pool(worker, pool);
+               kfree(worker);
                return 0;
        }
  
@@@ -2361,9 -2220,6 +2220,6 @@@ recheck
  
        worker_set_flags(worker, WORKER_PREP, false);
  sleep:
-       if (unlikely(need_to_manage_workers(pool)) && manage_workers(worker))
-               goto recheck;
        /*
         * pool->lock is held and there's no work to process and no need to
         * manage, sleep.  Workers are woken up only while holding
@@@ -2440,8 -2296,9 +2296,9 @@@ repeat
  
                spin_unlock_irq(&wq_mayday_lock);
  
-               /* migrate to the target cpu if possible */
-               worker_maybe_bind_and_lock(pool);
+               worker_attach_to_pool(rescuer, pool);
+               spin_lock_irq(&pool->lock);
                rescuer->pool = pool;
  
                /*
                                move_linked_works(work, scheduled, &n);
  
                process_scheduled_works(rescuer);
+               spin_unlock_irq(&pool->lock);
+               worker_detach_from_pool(rescuer, pool);
+               spin_lock_irq(&pool->lock);
  
                /*
                 * Put the reference grabbed by send_mayday().  @pool won't
@@@ -3550,9 -3412,10 +3412,10 @@@ static int init_worker_pool(struct work
                    (unsigned long)pool);
  
        mutex_init(&pool->manager_arb);
-       mutex_init(&pool->manager_mutex);
-       idr_init(&pool->worker_idr);
+       mutex_init(&pool->attach_mutex);
+       INIT_LIST_HEAD(&pool->workers);
  
+       ida_init(&pool->worker_ida);
        INIT_HLIST_NODE(&pool->hash_node);
        pool->refcnt = 1;
  
@@@ -3567,7 -3430,7 +3430,7 @@@ static void rcu_free_pool(struct rcu_he
  {
        struct worker_pool *pool = container_of(rcu, struct worker_pool, rcu);
  
-       idr_destroy(&pool->worker_idr);
+       ida_destroy(&pool->worker_ida);
        free_workqueue_attrs(pool->attrs);
        kfree(pool);
  }
   */
  static void put_unbound_pool(struct worker_pool *pool)
  {
+       DECLARE_COMPLETION_ONSTACK(detach_completion);
        struct worker *worker;
  
        lockdep_assert_held(&wq_pool_mutex);
        /*
         * Become the manager and destroy all workers.  Grabbing
         * manager_arb prevents @pool's workers from blocking on
-        * manager_mutex.
+        * attach_mutex.
         */
        mutex_lock(&pool->manager_arb);
-       mutex_lock(&pool->manager_mutex);
-       spin_lock_irq(&pool->lock);
  
-       while ((worker = first_worker(pool)))
+       spin_lock_irq(&pool->lock);
+       while ((worker = first_idle_worker(pool)))
                destroy_worker(worker);
        WARN_ON(pool->nr_workers || pool->nr_idle);
        spin_unlock_irq(&pool->lock);
-       mutex_unlock(&pool->manager_mutex);
+       mutex_lock(&pool->attach_mutex);
+       if (!list_empty(&pool->workers))
+               pool->detach_completion = &detach_completion;
+       mutex_unlock(&pool->attach_mutex);
+       if (pool->detach_completion)
+               wait_for_completion(pool->detach_completion);
        mutex_unlock(&pool->manager_arb);
  
        /* shut down the timers */
@@@ -3662,9 -3532,6 +3532,6 @@@ static struct worker_pool *get_unbound_
        if (!pool || init_worker_pool(pool) < 0)
                goto fail;
  
-       if (workqueue_freezing)
-               pool->flags |= POOL_FREEZING;
        lockdep_set_subclass(&pool->lock, 1);   /* see put_pwq() */
        copy_workqueue_attrs(pool->attrs, attrs);
  
@@@ -3771,7 -3638,12 +3638,12 @@@ static void pwq_adjust_max_active(struc
  
        spin_lock_irq(&pwq->pool->lock);
  
-       if (!freezable || !(pwq->pool->flags & POOL_FREEZING)) {
+       /*
+        * During [un]freezing, the caller is responsible for ensuring that
+        * this function is called at least once after @workqueue_freezing
+        * is updated and visible.
+        */
+       if (!freezable || !workqueue_freezing) {
                pwq->max_active = wq->saved_max_active;
  
                while (!list_empty(&pwq->delayed_works) &&
@@@ -4103,17 -3975,13 +3975,13 @@@ static void wq_update_unbound_numa(stru
         * Let's determine what needs to be done.  If the target cpumask is
         * different from wq's, we need to compare it to @pwq's and create
         * a new one if they don't match.  If the target cpumask equals
-        * wq's, the default pwq should be used.  If @pwq is already the
-        * default one, nothing to do; otherwise, install the default one.
+        * wq's, the default pwq should be used.
         */
        if (wq_calc_node_cpumask(wq->unbound_attrs, node, cpu_off, cpumask)) {
                if (cpumask_equal(cpumask, pwq->pool->attrs->cpumask))
                        goto out_unlock;
        } else {
-               if (pwq == wq->dfl_pwq)
-                       goto out_unlock;
-               else
-                       goto use_dfl_pwq;
+               goto use_dfl_pwq;
        }
  
        mutex_unlock(&wq->mutex);
        /* create a new pwq */
        pwq = alloc_unbound_pwq(wq, target_attrs);
        if (!pwq) {
-               pr_warning("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n",
-                          wq->name);
+               pr_warn("workqueue: allocation failed while updating NUMA affinity of \"%s\"\n",
+                       wq->name);
                mutex_lock(&wq->mutex);
                goto use_dfl_pwq;
        }
@@@ -4599,28 -4467,27 +4467,27 @@@ static void wq_unbind_fn(struct work_st
        int cpu = smp_processor_id();
        struct worker_pool *pool;
        struct worker *worker;
-       int wi;
  
        for_each_cpu_worker_pool(pool, cpu) {
                WARN_ON_ONCE(cpu != smp_processor_id());
  
-               mutex_lock(&pool->manager_mutex);
+               mutex_lock(&pool->attach_mutex);
                spin_lock_irq(&pool->lock);
  
                /*
-                * We've blocked all manager operations.  Make all workers
+                * We've blocked all attach/detach operations. Make all workers
                 * unbound and set DISASSOCIATED.  Before this, all workers
                 * except for the ones which are still executing works from
                 * before the last CPU down must be on the cpu.  After
                 * this, they may become diasporas.
                 */
-               for_each_pool_worker(worker, wi, pool)
+               for_each_pool_worker(worker, pool)
                        worker->flags |= WORKER_UNBOUND;
  
                pool->flags |= POOL_DISASSOCIATED;
  
                spin_unlock_irq(&pool->lock);
-               mutex_unlock(&pool->manager_mutex);
+               mutex_unlock(&pool->attach_mutex);
  
                /*
                 * Call schedule() so that we cross rq->lock and thus can
  static void rebind_workers(struct worker_pool *pool)
  {
        struct worker *worker;
-       int wi;
  
-       lockdep_assert_held(&pool->manager_mutex);
+       lockdep_assert_held(&pool->attach_mutex);
  
        /*
         * Restore CPU affinity of all workers.  As all idle workers should
         * of all workers first and then clear UNBOUND.  As we're called
         * from CPU_ONLINE, the following shouldn't fail.
         */
-       for_each_pool_worker(worker, wi, pool)
+       for_each_pool_worker(worker, pool)
                WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task,
                                                  pool->attrs->cpumask) < 0);
  
        spin_lock_irq(&pool->lock);
  
-       for_each_pool_worker(worker, wi, pool) {
+       for_each_pool_worker(worker, pool) {
                unsigned int worker_flags = worker->flags;
  
                /*
@@@ -4729,9 -4595,8 +4595,8 @@@ static void restore_unbound_workers_cpu
  {
        static cpumask_t cpumask;
        struct worker *worker;
-       int wi;
  
-       lockdep_assert_held(&pool->manager_mutex);
+       lockdep_assert_held(&pool->attach_mutex);
  
        /* is @cpu allowed for @pool? */
        if (!cpumask_test_cpu(cpu, pool->attrs->cpumask))
                return;
  
        /* as we're called from CPU_ONLINE, the following shouldn't fail */
-       for_each_pool_worker(worker, wi, pool)
+       for_each_pool_worker(worker, pool)
                WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task,
                                                  pool->attrs->cpumask) < 0);
  }
@@@ -4776,7 -4641,7 +4641,7 @@@ static int workqueue_cpu_up_callback(st
                mutex_lock(&wq_pool_mutex);
  
                for_each_pool(pool, pi) {
-                       mutex_lock(&pool->manager_mutex);
+                       mutex_lock(&pool->attach_mutex);
  
                        if (pool->cpu == cpu) {
                                spin_lock_irq(&pool->lock);
                                restore_unbound_workers_cpumask(pool, cpu);
                        }
  
-                       mutex_unlock(&pool->manager_mutex);
+                       mutex_unlock(&pool->attach_mutex);
                }
  
                /* update NUMA affinity of unbound workqueues */
@@@ -4887,24 -4752,14 +4752,14 @@@ EXPORT_SYMBOL_GPL(work_on_cpu)
   */
  void freeze_workqueues_begin(void)
  {
-       struct worker_pool *pool;
        struct workqueue_struct *wq;
        struct pool_workqueue *pwq;
-       int pi;
  
        mutex_lock(&wq_pool_mutex);
  
        WARN_ON_ONCE(workqueue_freezing);
        workqueue_freezing = true;
  
-       /* set FREEZING */
-       for_each_pool(pool, pi) {
-               spin_lock_irq(&pool->lock);
-               WARN_ON_ONCE(pool->flags & POOL_FREEZING);
-               pool->flags |= POOL_FREEZING;
-               spin_unlock_irq(&pool->lock);
-       }
        list_for_each_entry(wq, &workqueues, list) {
                mutex_lock(&wq->mutex);
                for_each_pwq(pwq, wq)
@@@ -4974,21 -4829,13 +4829,13 @@@ void thaw_workqueues(void
  {
        struct workqueue_struct *wq;
        struct pool_workqueue *pwq;
-       struct worker_pool *pool;
-       int pi;
  
        mutex_lock(&wq_pool_mutex);
  
        if (!workqueue_freezing)
                goto out_unlock;
  
-       /* clear FREEZING */
-       for_each_pool(pool, pi) {
-               spin_lock_irq(&pool->lock);
-               WARN_ON_ONCE(!(pool->flags & POOL_FREEZING));
-               pool->flags &= ~POOL_FREEZING;
-               spin_unlock_irq(&pool->lock);
-       }
+       workqueue_freezing = false;
  
        /* restore max_active and repopulate worklist */
        list_for_each_entry(wq, &workqueues, list) {
                mutex_unlock(&wq->mutex);
        }
  
-       workqueue_freezing = false;
  out_unlock:
        mutex_unlock(&wq_pool_mutex);
  }