From: Oleg Nesterov <oleg@redhat.com> Date: Sun, 30 May 2010 16:19:54 -0400 Subject: [misc] workqueue: cwq instead of wq where appropriate Message-id: <20100530161954.GC9577@redhat.com> Patchwork-id: 25905 O-Subject: [RHEL5 PATCH 2/7] bz#596626: workqueues: change queue_delayed_work/delayed_work_timer_fn to use cwq instead of wq Bugzilla: 596626 RH-Acked-by: Stanislaw Gruszka <sgruszka@redhat.com> RH-Acked-by: Prarit Bhargava <prarit@redhat.com> (changes the existing code) Currently we can't know what work->wq_data actually means, it could be either cpu_workqueue_struct* if this work is already queued, or it is workqueue_struct* if work->timer is pending. Change queue_delayed_work/delayed_work_timer_fn to use cwq, not wq. Thereafter work->wq_data always points to cpu_workqueue_struct if queue_work/queue_delayed_work was ever called, otherwise this pointer is not initialized: see the next patch. Signed-off-by: Oleg Nesterov <oleg@redhat.com> diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 25758a3..3a61c86 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -128,7 +128,9 @@ EXPORT_SYMBOL_GPL(queue_work); static void delayed_work_timer_fn(unsigned long __data) { struct work_struct *work = (struct work_struct *)__data; - struct workqueue_struct *wq = work->wq_data; + struct cpu_workqueue_struct *cwq = work->wq_data; + struct workqueue_struct *wq = cwq->wq; + int cpu = smp_processor_id(); if (unlikely(is_single_threaded(wq))) @@ -137,6 +139,15 @@ static void delayed_work_timer_fn(unsigned long __data) __queue_work(per_cpu_ptr(wq->cpu_wq, cpu), work); } +/* This stores cwq for the moment, for the timer_fn */ +static void set_delayed_wq_data(struct work_struct *work, + struct workqueue_struct *wq) +{ + int cpu = is_single_threaded(wq) ? + singlethread_cpu : raw_smp_processor_id(); + work->wq_data = per_cpu_ptr(wq->cpu_wq, cpu); +} + /** * queue_delayed_work - queue work on a workqueue after delay * @wq: workqueue to use @@ -155,8 +166,7 @@ int fastcall queue_delayed_work(struct workqueue_struct *wq, BUG_ON(timer_pending(timer)); BUG_ON(!list_empty(&work->entry)); - /* This stores wq for the moment, for the timer_fn */ - work->wq_data = wq; + set_delayed_wq_data(work, wq); timer->expires = jiffies + delay; timer->data = (unsigned long)work; timer->function = delayed_work_timer_fn; @@ -186,8 +196,7 @@ int queue_delayed_work_on(int cpu, struct workqueue_struct *wq, BUG_ON(timer_pending(timer)); BUG_ON(!list_empty(&work->entry)); - /* This stores wq for the moment, for the timer_fn */ - work->wq_data = wq; + set_delayed_wq_data(work, wq); timer->expires = jiffies + delay; timer->data = (unsigned long)work; timer->function = delayed_work_timer_fn;