patch-2.0.33 linux/fs/buffer.c

Next file: linux/fs/exec.c
Previous file: linux/drivers/scsi/aic7xxx_seq.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.32/linux/fs/buffer.c linux/fs/buffer.c
@@ -601,6 +601,8 @@
 	nr_unused_buffer_heads++;
 	bh->b_next_free = unused_list;
 	unused_list = bh;
+	if (!waitqueue_active(&buffer_wait))
+		return;
 	wake_up(&buffer_wait);
 }
 
@@ -983,6 +985,7 @@
 
 static void get_more_buffer_heads(void)
 {
+	struct wait_queue wait = { current, NULL };
 	struct buffer_head * bh;
 
 	while (!unused_list) {
@@ -1011,11 +1014,18 @@
 		 * finishing IO..
 		 */
 		run_task_queue(&tq_disk);
-		sleep_on(&buffer_wait);
+
 		/*
-		 * After we wake up, check for released async buffer heads.
+		 * Set our state for sleeping, then check again for buffer heads.
+		 * This ensures we won't miss a wake_up from an interrupt.
 		 */
+		add_wait_queue(&buffer_wait, &wait);
+		current->state = TASK_UNINTERRUPTIBLE;
+		if (!unused_list && !reuse_list)
+			schedule();
 		recover_reusable_buffer_heads();
+		remove_wait_queue(&buffer_wait, &wait);
+		current->state = TASK_RUNNING;
 	}
 
 }
@@ -1192,13 +1202,13 @@
 		 * and unlock_buffer(). */
 	} else {
 		unsigned long flags;
-		clear_bit(PG_locked, &page->flags);
-		set_bit(PG_uptodate, &page->flags);
-		wake_up(&page->wait);
 		save_flags(flags);
 		cli();
 		free_async_buffers(bh);
 		restore_flags(flags);
+		clear_bit(PG_locked, &page->flags);
+		set_bit(PG_uptodate, &page->flags);
+		wake_up(&page->wait);
 		after_unlock_page(page);
 		if (waitqueue_active(&buffer_wait))
 			wake_up(&buffer_wait);

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov