]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blobdiff - kernel/workqueue.c
netfilter: nf_osf: avoid passing pointer to local var
[mirror_ubuntu-focal-kernel.git] / kernel / workqueue.c
index bc2e09a8ea61db57cec3ca455850df4fd1139849..1a0c224af6fb30e27ebc3fd3a1e260f45b578948 100644 (file)
@@ -425,7 +425,8 @@ static void workqueue_sysfs_unregister(struct workqueue_struct *wq);
  * ignored.
  */
 #define for_each_pwq(pwq, wq)                                          \
-       list_for_each_entry_rcu((pwq), &(wq)->pwqs, pwqs_node)          \
+       list_for_each_entry_rcu((pwq), &(wq)->pwqs, pwqs_node,          \
+                               lockdep_is_held(&wq->mutex))            \
                if (({ assert_rcu_or_wq_mutex(wq); false; })) { }       \
                else
 
@@ -1416,14 +1417,16 @@ static void __queue_work(int cpu, struct workqueue_struct *wq,
                return;
        rcu_read_lock();
 retry:
-       if (req_cpu == WORK_CPU_UNBOUND)
-               cpu = wq_select_unbound_cpu(raw_smp_processor_id());
-
        /* pwq which will be used unless @work is executing elsewhere */
-       if (!(wq->flags & WQ_UNBOUND))
-               pwq = per_cpu_ptr(wq->cpu_pwqs, cpu);
-       else
+       if (wq->flags & WQ_UNBOUND) {
+               if (req_cpu == WORK_CPU_UNBOUND)
+                       cpu = wq_select_unbound_cpu(raw_smp_processor_id());
                pwq = unbound_pwq_by_node(wq, cpu_to_node(cpu));
+       } else {
+               if (req_cpu == WORK_CPU_UNBOUND)
+                       cpu = raw_smp_processor_id();
+               pwq = per_cpu_ptr(wq->cpu_pwqs, cpu);
+       }
 
        /*
         * If @work was previously on a different pool, it might still be
@@ -2532,8 +2535,14 @@ repeat:
                         */
                        if (need_to_create_worker(pool)) {
                                spin_lock(&wq_mayday_lock);
-                               get_pwq(pwq);
-                               list_move_tail(&pwq->mayday_node, &wq->maydays);
+                               /*
+                                * Queue iff we aren't racing destruction
+                                * and somebody else hasn't queued it already.
+                                */
+                               if (wq->rescuer && list_empty(&pwq->mayday_node)) {
+                                       get_pwq(pwq);
+                                       list_add_tail(&pwq->mayday_node, &wq->maydays);
+                               }
                                spin_unlock(&wq_mayday_lock);
                        }
                }
@@ -4325,9 +4334,29 @@ void destroy_workqueue(struct workqueue_struct *wq)
        struct pool_workqueue *pwq;
        int node;
 
+       /*
+        * Remove it from sysfs first so that sanity check failure doesn't
+        * lead to sysfs name conflicts.
+        */
+       workqueue_sysfs_unregister(wq);
+
        /* drain it before proceeding with destruction */
        drain_workqueue(wq);
 
+       /* kill rescuer, if sanity checks fail, leave it w/o rescuer */
+       if (wq->rescuer) {
+               struct worker *rescuer = wq->rescuer;
+
+               /* this prevents new queueing */
+               spin_lock_irq(&wq_mayday_lock);
+               wq->rescuer = NULL;
+               spin_unlock_irq(&wq_mayday_lock);
+
+               /* rescuer will empty maydays list before exiting */
+               kthread_stop(rescuer->task);
+               kfree(rescuer);
+       }
+
        /* sanity checks */
        mutex_lock(&wq->mutex);
        for_each_pwq(pwq, wq) {
@@ -4359,11 +4388,6 @@ void destroy_workqueue(struct workqueue_struct *wq)
        list_del_rcu(&wq->list);
        mutex_unlock(&wq_pool_mutex);
 
-       workqueue_sysfs_unregister(wq);
-
-       if (wq->rescuer)
-               kthread_stop(wq->rescuer->task);
-
        if (!(wq->flags & WQ_UNBOUND)) {
                wq_unregister_lockdep(wq);
                /*
@@ -4638,7 +4662,8 @@ static void show_pwq(struct pool_workqueue *pwq)
        pr_info("  pwq %d:", pool->id);
        pr_cont_pool_info(pool);
 
-       pr_cont(" active=%d/%d%s\n", pwq->nr_active, pwq->max_active,
+       pr_cont(" active=%d/%d refcnt=%d%s\n",
+               pwq->nr_active, pwq->max_active, pwq->refcnt,
                !list_empty(&pwq->mayday_node) ? " MAYDAY" : "");
 
        hash_for_each(pool->busy_hash, bkt, worker, hentry) {