ftrace: Update the kconfig for DYNAMIC_FTRACE
[linux-2.6.git] / kernel / workqueue.c
index 7da267c..a64b94e 100644 (file)
@@ -1141,8 +1141,8 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq,
        if (!test_and_set_bit(WORK_STRUCT_PENDING_BIT, work_data_bits(work))) {
                unsigned int lcpu;
 
-               BUG_ON(timer_pending(timer));
-               BUG_ON(!list_empty(&work->entry));
+               WARN_ON_ONCE(timer_pending(timer));
+               WARN_ON_ONCE(!list_empty(&work->entry));
 
                timer_stats_timer_set_start_info(&dwork->timer);
 
@@ -1864,7 +1864,9 @@ __acquires(&gcwq->lock)
 
        spin_unlock_irq(&gcwq->lock);
 
+       smp_wmb();      /* paired with test_and_set_bit(PENDING) */
        work_clear_pending(work);
+
        lock_map_acquire_read(&cwq->wq->lockdep_map);
        lock_map_acquire(&lockdep_map);
        trace_workqueue_execute_start(work);
@@ -2038,8 +2040,10 @@ static int rescuer_thread(void *__wq)
 repeat:
        set_current_state(TASK_INTERRUPTIBLE);
 
-       if (kthread_should_stop())
+       if (kthread_should_stop()) {
+               __set_current_state(TASK_RUNNING);
                return 0;
+       }
 
        /*
         * See whether any cpu is asking for help.  Unbounded
@@ -3433,14 +3437,17 @@ static int __cpuinit trustee_thread(void *__gcwq)
 
        for_each_busy_worker(worker, i, pos, gcwq) {
                struct work_struct *rebind_work = &worker->rebind_work;
+               unsigned long worker_flags = worker->flags;
 
                /*
                 * Rebind_work may race with future cpu hotplug
                 * operations.  Use a separate flag to mark that
-                * rebinding is scheduled.
+                * rebinding is scheduled.  The morphing should
+                * be atomic.
                 */
-               worker->flags |= WORKER_REBIND;
-               worker->flags &= ~WORKER_ROGUE;
+               worker_flags |= WORKER_REBIND;
+               worker_flags &= ~WORKER_ROGUE;
+               ACCESS_ONCE(worker->flags) = worker_flags;
 
                /* queue rebind_work, wq doesn't matter, use the default one */
                if (test_and_set_bit(WORK_STRUCT_PENDING_BIT,
@@ -3582,21 +3589,55 @@ static int __devinit workqueue_cpu_callback(struct notifier_block *nfb,
        return notifier_from_errno(0);
 }
 
+/*
+ * Workqueues should be brought up before normal priority CPU notifiers.
+ * This will be registered high priority CPU notifier.
+ */
+static int __devinit workqueue_cpu_up_callback(struct notifier_block *nfb,
+                                              unsigned long action,
+                                              void *hcpu)
+{
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_UP_PREPARE:
+       case CPU_UP_CANCELED:
+       case CPU_DOWN_FAILED:
+       case CPU_ONLINE:
+               return workqueue_cpu_callback(nfb, action, hcpu);
+       }
+       return NOTIFY_OK;
+}
+
+/*
+ * Workqueues should be brought down after normal priority CPU notifiers.
+ * This will be registered as low priority CPU notifier.
+ */
+static int __devinit workqueue_cpu_down_callback(struct notifier_block *nfb,
+                                                unsigned long action,
+                                                void *hcpu)
+{
+       switch (action & ~CPU_TASKS_FROZEN) {
+       case CPU_DOWN_PREPARE:
+       case CPU_DYING:
+       case CPU_POST_DEAD:
+               return workqueue_cpu_callback(nfb, action, hcpu);
+       }
+       return NOTIFY_OK;
+}
+
 #ifdef CONFIG_SMP
 
 struct work_for_cpu {
-       struct completion completion;
+       struct work_struct work;
        long (*fn)(void *);
        void *arg;
        long ret;
 };
 
-static int do_work_for_cpu(void *_wfc)
+static void work_for_cpu_fn(struct work_struct *work)
 {
-       struct work_for_cpu *wfc = _wfc;
+       struct work_for_cpu *wfc = container_of(work, struct work_for_cpu, work);
+
        wfc->ret = wfc->fn(wfc->arg);
-       complete(&wfc->completion);
-       return 0;
 }
 
 /**
@@ -3611,19 +3652,11 @@ static int do_work_for_cpu(void *_wfc)
  */
 long work_on_cpu(unsigned int cpu, long (*fn)(void *), void *arg)
 {
-       struct task_struct *sub_thread;
-       struct work_for_cpu wfc = {
-               .completion = COMPLETION_INITIALIZER_ONSTACK(wfc.completion),
-               .fn = fn,
-               .arg = arg,
-       };
+       struct work_for_cpu wfc = { .fn = fn, .arg = arg };
 
-       sub_thread = kthread_create(do_work_for_cpu, &wfc, "work_for_cpu");
-       if (IS_ERR(sub_thread))
-               return PTR_ERR(sub_thread);
-       kthread_bind(sub_thread, cpu);
-       wake_up_process(sub_thread);
-       wait_for_completion(&wfc.completion);
+       INIT_WORK_ONSTACK(&wfc.work, work_for_cpu_fn);
+       schedule_work_on(cpu, &wfc.work);
+       flush_work(&wfc.work);
        return wfc.ret;
 }
 EXPORT_SYMBOL_GPL(work_on_cpu);
@@ -3775,7 +3808,8 @@ static int __init init_workqueues(void)
        unsigned int cpu;
        int i;
 
-       cpu_notifier(workqueue_cpu_callback, CPU_PRI_WORKQUEUE);
+       cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP);
+       cpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN);
 
        /* initialize gcwqs */
        for_each_gcwq_cpu(cpu) {