summaryrefslogtreecommitdiff
path: root/kernel/workqueue.c
diff options
context:
space:
mode:
authorAndrew Morton <akpm@osdl.org>2004-03-15 15:19:41 -0800
committerLinus Torvalds <torvalds@ppc970.osdl.org>2004-03-15 15:19:41 -0800
commit2139597d56ba1bcc7348a0f71716f9dcfbdcb848 (patch)
tree62670017cfa65d0f4cd8bef161cb077486272ebe /kernel/workqueue.c
parentb9b52730c0c103b677e29e723ce0db878003d496 (diff)
[PATCH] flush_workqueue(): detect excessive nesting
Add a debug check for workqueues nested more than three deep via the direct-run-workqueue() path.
Diffstat (limited to 'kernel/workqueue.c')
-rw-r--r--kernel/workqueue.c10
1 files changed, 10 insertions, 0 deletions
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 6ca72d53d9ca..9cbfa8e69ac6 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -47,6 +47,7 @@ struct cpu_workqueue_struct {
struct workqueue_struct *wq;
task_t *thread;
+ int run_depth; /* Detect run_workqueue() recursion depth */
} ____cacheline_aligned;
/*
@@ -129,6 +130,13 @@ static inline void run_workqueue(struct cpu_workqueue_struct *cwq)
* done.
*/
spin_lock_irqsave(&cwq->lock, flags);
+ cwq->run_depth++;
+ if (cwq->run_depth > 3) {
+ /* morton gets to eat his hat */
+ printk("%s: recursion depth exceeded: %d\n",
+ __FUNCTION__, cwq->run_depth);
+ dump_stack();
+ }
while (!list_empty(&cwq->worklist)) {
struct work_struct *work = list_entry(cwq->worklist.next,
struct work_struct, entry);
@@ -146,6 +154,7 @@ static inline void run_workqueue(struct cpu_workqueue_struct *cwq)
cwq->remove_sequence++;
wake_up(&cwq->work_done);
}
+ cwq->run_depth--;
spin_unlock_irqrestore(&cwq->lock, flags);
}
@@ -275,6 +284,7 @@ struct workqueue_struct *create_workqueue(const char *name)
wq = kmalloc(sizeof(*wq), GFP_KERNEL);
if (!wq)
return NULL;
+ memset(wq, 0, sizeof(*wq));
for (cpu = 0; cpu < NR_CPUS; cpu++) {
if (!cpu_online(cpu))