Another fs/buffer.c patch ...

Bill Hawes (whawes@star.net)
Wed, 02 Jul 1997 19:26:33 -0400


This is a multi-part message in MIME format.
--------------1CF2D140EE4E0810D2081A4A
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Sorry to be late with this, but I just spotted it a little while ago.
After grow_more_buffer_heads() wakes up from &buffer_wait, it fails to
do a recover_reusable_buffer_heads(). So even if some async buffers
have been freed, it may continue to sleep until some other kind task
recovers the buffer heads.

The attached patch corrects this. There are really only a few lines
changed, but I moved recover_reusable_buffer_heads() to keep the
compiler happy.

Regards,
Bill
--------------1CF2D140EE4E0810D2081A4A
Content-Type: text/plain; charset=us-ascii; name="buffer_rr-patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="buffer_rr-patch"

--- fs/buffer.c.old Sun Apr 27 15:54:43 1997
+++ fs/buffer.c Wed Jul 2 18:43:11 1997
@@ -919,6 +919,34 @@
wake_up(&buffer_wait);
}

+/*
+ * We can't put completed temporary IO buffer_heads directly onto the
+ * unused_list when they become unlocked, since the device driver
+ * end_request routines still expect access to the buffer_head's
+ * fields after the final unlock. So, the device driver puts them on
+ * the reuse_list instead once IO completes, and we recover these to
+ * the unused_list here.
+ *
+ * The reuse_list receives buffers from interrupt routines, so we need
+ * to be IRQ-safe here (but note that interrupts only _add_ to the
+ * reuse_list, never take away. So we don't need to worry about the
+ * reuse_list magically emptying).
+ */
+static inline void recover_reusable_buffer_heads(void)
+{
+ if (reuse_list) {
+ struct buffer_head *head;
+
+ head = xchg(&reuse_list, NULL);
+
+ do {
+ struct buffer_head *bh = head;
+ head = head->b_next_free;
+ put_unused_buffer_head(bh);
+ } while (head);
+ }
+}
+
static void get_more_buffer_heads(void)
{
struct buffer_head * bh;
@@ -946,35 +974,10 @@
*/
run_task_queue(&tq_disk);
sleep_on(&buffer_wait);
- }
-
-}
-
-/*
- * We can't put completed temporary IO buffer_heads directly onto the
- * unused_list when they become unlocked, since the device driver
- * end_request routines still expect access to the buffer_head's
- * fields after the final unlock. So, the device driver puts them on
- * the reuse_list instead once IO completes, and we recover these to
- * the unused_list here.
- *
- * The reuse_list receives buffers from interrupt routines, so we need
- * to be IRQ-safe here (but note that interrupts only _add_ to the
- * reuse_list, never take away. So we don't need to worry about the
- * reuse_list magically emptying).
- */
-static inline void recover_reusable_buffer_heads(void)
-{
- if (reuse_list) {
- struct buffer_head *head;
-
- head = xchg(&reuse_list, NULL);
-
- do {
- struct buffer_head *bh = head;
- head = head->b_next_free;
- put_unused_buffer_head(bh);
- } while (head);
+ /*
+ * After we wake up, check for released async buffer heads.
+ */
+ recover_reusable_buffer_heads();
}
}

@@ -1158,6 +1161,7 @@
free_async_buffers(bh);
restore_flags(flags);
after_unlock_page(page);
+ wake_up(&buffer_wait);
}
++current->maj_flt;
return 0;

--------------1CF2D140EE4E0810D2081A4A--