Index: linux-2.6.14-rc2/kernel/workqueue.c =================================================================== --- linux-2.6.14-rc2.orig/kernel/workqueue.c 2005-09-19 20:00:41.000000000 -0700 +++ linux-2.6.14-rc2/kernel/workqueue.c 2005-09-22 14:05:33.000000000 -0700 @@ -57,7 +57,7 @@ struct cpu_workqueue_struct { * per-CPU workqueues: */ struct workqueue_struct { - struct cpu_workqueue_struct cpu_wq[NR_CPUS]; + struct cpu_workqueue_struct *cpu_wq[NR_CPUS]; const char *name; struct list_head list; /* Empty if single thread */ }; @@ -102,7 +102,7 @@ int fastcall queue_work(struct workqueue if (unlikely(is_single_threaded(wq))) cpu = 0; BUG_ON(!list_empty(&work->entry)); - __queue_work(wq->cpu_wq + cpu, work); + __queue_work(wq->cpu_wq[cpu], work); ret = 1; } put_cpu(); @@ -118,7 +118,7 @@ static void delayed_work_timer_fn(unsign if (unlikely(is_single_threaded(wq))) cpu = 0; - __queue_work(wq->cpu_wq + cpu, work); + __queue_work(wq->cpu_wq[cpu], work); } int fastcall queue_delayed_work(struct workqueue_struct *wq, @@ -265,13 +265,13 @@ void fastcall flush_workqueue(struct wor if (is_single_threaded(wq)) { /* Always use cpu 0's area. */ - flush_cpu_workqueue(wq->cpu_wq + 0); + flush_cpu_workqueue(wq->cpu_wq[0]); } else { int cpu; lock_cpu_hotplug(); for_each_online_cpu(cpu) - flush_cpu_workqueue(wq->cpu_wq + cpu); + flush_cpu_workqueue(wq->cpu_wq[cpu]); unlock_cpu_hotplug(); } } @@ -279,9 +279,17 @@ void fastcall flush_workqueue(struct wor static struct task_struct *create_workqueue_thread(struct workqueue_struct *wq, int cpu) { - struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu; + struct cpu_workqueue_struct *cwq; struct task_struct *p; + if (!wq->cpu_wq[cpu]) + wq->cpu_wq[cpu] = kmalloc_node(sizeof(struct cpu_workqueue_struct), + GFP_KERNEL, cpu_to_node(cpu)); + cwq = wq->cpu_wq[cpu]; + if (!cwq) + return NULL; + + memset(cwq, 0, sizeof(struct cpu_workqueue_struct)); spin_lock_init(&cwq->lock); cwq->wq = wq; cwq->thread = NULL; @@ -353,13 +361,18 @@ static void cleanup_workqueue_thread(str unsigned long flags; struct task_struct *p; - cwq = wq->cpu_wq + cpu; + cwq = wq->cpu_wq[cpu]; + if (!cwq) + return; + spin_lock_irqsave(&cwq->lock, flags); p = cwq->thread; cwq->thread = NULL; spin_unlock_irqrestore(&cwq->lock, flags); if (p) kthread_stop(p); + kfree(cwq); + wq->cpu_wq[cpu] = NULL; } void destroy_workqueue(struct workqueue_struct *wq) @@ -458,7 +471,7 @@ int current_is_keventd(void) BUG_ON(!keventd_wq); - cwq = keventd_wq->cpu_wq + cpu; + cwq = keventd_wq->cpu_wq[cpu]; if (current == cwq->thread) ret = 1; @@ -470,7 +483,7 @@ int current_is_keventd(void) /* Take the work from this (downed) CPU. */ static void take_over_work(struct workqueue_struct *wq, unsigned int cpu) { - struct cpu_workqueue_struct *cwq = wq->cpu_wq + cpu; + struct cpu_workqueue_struct *cwq = wq->cpu_wq[cpu]; LIST_HEAD(list); struct work_struct *work; @@ -481,7 +494,7 @@ static void take_over_work(struct workqu printk("Taking work for %s\n", wq->name); work = list_entry(list.next,struct work_struct,entry); list_del(&work->entry); - __queue_work(wq->cpu_wq + smp_processor_id(), work); + __queue_work(wq->cpu_wq[smp_processor_id()], work); } spin_unlock_irq(&cwq->lock); } @@ -508,15 +521,15 @@ static int __devinit workqueue_cpu_callb case CPU_ONLINE: /* Kick off worker threads. */ list_for_each_entry(wq, &workqueues, list) { - kthread_bind(wq->cpu_wq[hotcpu].thread, hotcpu); - wake_up_process(wq->cpu_wq[hotcpu].thread); + kthread_bind(wq->cpu_wq[hotcpu]->thread, hotcpu); + wake_up_process(wq->cpu_wq[hotcpu]->thread); } break; case CPU_UP_CANCELED: list_for_each_entry(wq, &workqueues, list) { /* Unbind so it can run. */ - kthread_bind(wq->cpu_wq[hotcpu].thread, + kthread_bind(wq->cpu_wq[hotcpu]->thread, smp_processor_id()); cleanup_workqueue_thread(wq, hotcpu); }