[PATCH] Race condition in fs/buffer.c

From: Mike Klar (mfklar@ponymail.com)
Date: Sun Apr 02 2000 - 23:23:56 EST


Several weeks ago, Nicolas Pitre posted a patch that fixes a race condition
between bdflush and anything that calls wakeup_bdflush. It doesn't seem to
have made it into the kernel. Can we get this fixed, either with Nicolas'
patch, the patch below, or some other solution? This is a blatant race
condition, and could be a problem for anything that calls wakeup_bdflush
early, although I've only ever seen that happen with initrd and a relatively
small amount of memory. For example, a 4MB initrd on a system with 12MB of
RAM can trip this, provided there's not much else configured in the kernel.

Nicolas' patch is much simpler, but is somewhat dependant on the behavior of
schedule(). The patch below is more complex but addresses the problem
specifically.

Details: wakeup_bdflush references the task_struct pointer set in bdflush
(bdflush_tsk) to do its work, but if bdflush hasn't been allowed to run yet
by the scheduler, it winds up with a NULL pointer dereference. This patch
(against 2.3.99-pre4-2) addresses that by not allowing init to continue
until after bdflush_tsk has been initialized.

Mike Klar

diff -ruN linux-2.3.99-pre4-2.orig/fs/buffer.c
linux-2.3.99-pre4-2/fs/buffer.c
--- linux-2.3.99-pre4-2.orig/fs/buffer.c Sun Apr 2 16:10:02 2000
+++ linux-2.3.99-pre4-2/fs/buffer.c Sun Apr 2 17:44:38 2000
@@ -2474,6 +2474,8 @@
  * the syscall above, but now we launch it ourselves internally with
  * kernel_thread(...) directly after the first thread in init/main.c
  */
+static DECLARE_WAIT_QUEUE_HEAD(bdflush_tsk_valid);
+
 int bdflush(void * unused)
 {
         struct task_struct *tsk = current;
@@ -2488,6 +2490,7 @@
         tsk->pgrp = 1;
         strcpy(tsk->comm, "kflushd");
         bdflush_tsk = tsk;
+ wake_up(&bdflush_tsk_valid);

         /* avoid getting signals */
         spin_lock_irq(&tsk->sigmask_lock);
@@ -2579,7 +2582,14 @@

 static int __init bdflush_init(void)
 {
+ DECLARE_WAITQUEUE(wait, current);
+
+ __add_wait_queue(&bdflush_tsk_valid, &wait);
+ set_current_state(TASK_UNINTERRUPTIBLE);
         kernel_thread(bdflush, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+ schedule();
+ __remove_wait_queue(&bdflush_tsk_valid, &wait);
+
         kernel_thread(kupdate, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
         return 0;
 }

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Fri Apr 07 2000 - 21:00:09 EST