Commit 4ab1a3e6 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] tighter locking in pdflush

Had a weird oops from Bill Irwin - the pdflush_list was corrupt.

The only thing I can think of is that something sprayed out a wakeup
when it shouldn't.  So tighten things up against that, and add some
printks to catch it if it happens again.
parent 57eb0613
...@@ -79,9 +79,9 @@ static unsigned long last_empty_jifs; ...@@ -79,9 +79,9 @@ static unsigned long last_empty_jifs;
*/ */
struct pdflush_work { struct pdflush_work {
struct task_struct *who; /* The thread */ struct task_struct *who; /* The thread */
void (*fn)(unsigned long); /* A callback function for pdflush to work on */ void (*fn)(unsigned long); /* A callback function */
unsigned long arg0; /* An argument to the callback function */ unsigned long arg0; /* An argument to the callback */
struct list_head list; /* On pdflush_list, when the thread is idle */ struct list_head list; /* On pdflush_list, when idle */
unsigned long when_i_went_to_sleep; unsigned long when_i_went_to_sleep;
}; };
...@@ -99,24 +99,35 @@ static int __pdflush(struct pdflush_work *my_work) ...@@ -99,24 +99,35 @@ static int __pdflush(struct pdflush_work *my_work)
current->flags |= PF_FLUSHER; current->flags |= PF_FLUSHER;
my_work->fn = NULL; my_work->fn = NULL;
my_work->who = current; my_work->who = current;
INIT_LIST_HEAD(&my_work->list);
spin_lock_irq(&pdflush_lock); spin_lock_irq(&pdflush_lock);
nr_pdflush_threads++; nr_pdflush_threads++;
// printk("pdflush %d [%d] starts\n", nr_pdflush_threads, current->pid);
for ( ; ; ) { for ( ; ; ) {
struct pdflush_work *pdf; struct pdflush_work *pdf;
list_add(&my_work->list, &pdflush_list);
my_work->when_i_went_to_sleep = jiffies;
set_current_state(TASK_INTERRUPTIBLE); set_current_state(TASK_INTERRUPTIBLE);
list_move(&my_work->list, &pdflush_list);
my_work->when_i_went_to_sleep = jiffies;
spin_unlock_irq(&pdflush_lock); spin_unlock_irq(&pdflush_lock);
if (current->flags & PF_FREEZE) if (current->flags & PF_FREEZE)
refrigerator(PF_IOTHREAD); refrigerator(PF_IOTHREAD);
schedule(); schedule();
if (my_work->fn) spin_lock_irq(&pdflush_lock);
(*my_work->fn)(my_work->arg0); if (!list_empty(&my_work->list)) {
printk("pdflush: bogus wakeup!\n");
my_work->fn = NULL;
continue;
}
if (my_work->fn == NULL) {
printk("pdflush: NULL work function\n");
continue;
}
spin_unlock_irq(&pdflush_lock);
(*my_work->fn)(my_work->arg0);
/* /*
* Thread creation: For how long have there been zero * Thread creation: For how long have there been zero
...@@ -132,6 +143,7 @@ static int __pdflush(struct pdflush_work *my_work) ...@@ -132,6 +143,7 @@ static int __pdflush(struct pdflush_work *my_work)
} }
spin_lock_irq(&pdflush_lock); spin_lock_irq(&pdflush_lock);
my_work->fn = NULL;
/* /*
* Thread destruction: For how long has the sleepiest * Thread destruction: For how long has the sleepiest
...@@ -143,13 +155,12 @@ static int __pdflush(struct pdflush_work *my_work) ...@@ -143,13 +155,12 @@ static int __pdflush(struct pdflush_work *my_work)
continue; continue;
pdf = list_entry(pdflush_list.prev, struct pdflush_work, list); pdf = list_entry(pdflush_list.prev, struct pdflush_work, list);
if (jiffies - pdf->when_i_went_to_sleep > 1 * HZ) { if (jiffies - pdf->when_i_went_to_sleep > 1 * HZ) {
pdf->when_i_went_to_sleep = jiffies; /* Limit exit rate */ /* Limit exit rate */
pdf->when_i_went_to_sleep = jiffies;
break; /* exeunt */ break; /* exeunt */
} }
my_work->fn = NULL;
} }
nr_pdflush_threads--; nr_pdflush_threads--;
// printk("pdflush %d [%d] ends\n", nr_pdflush_threads, current->pid);
spin_unlock_irq(&pdflush_lock); spin_unlock_irq(&pdflush_lock);
return 0; return 0;
} }
...@@ -191,11 +202,10 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0) ...@@ -191,11 +202,10 @@ int pdflush_operation(void (*fn)(unsigned long), unsigned long arg0)
list_del_init(&pdf->list); list_del_init(&pdf->list);
if (list_empty(&pdflush_list)) if (list_empty(&pdflush_list))
last_empty_jifs = jiffies; last_empty_jifs = jiffies;
spin_unlock_irqrestore(&pdflush_lock, flags);
pdf->fn = fn; pdf->fn = fn;
pdf->arg0 = arg0; pdf->arg0 = arg0;
wmb(); /* ? */
wake_up_process(pdf->who); wake_up_process(pdf->who);
spin_unlock_irqrestore(&pdflush_lock, flags);
} }
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment