Sorry to follow up to my own message, but I think I've found the
problem:
In 2.1.3, the implementation of sync_buffers was changed to only scan
the dirty buffers list. Indeed, if the implementation of the separate
buffer lists works (and it works), there should be no dirty buffers on
other lists. However, there is one small problem: as soon as the
write gets scheduled, the buffer is transferred to the "locked" list!
Thus it can no longer be found in the second and third passes, which
wait for the I/O to complete: sync_buffers returns right away!
The following patch fixes this problem by also scanning the "locked"
list for buffers to wait for.
diff -ur 2.1.4/linux/fs/buffer.c linux/fs/buffer.c
--- 2.1.4/linux/fs/buffer.c Thu Oct 17 21:47:38 1996
+++ linux/fs/buffer.c Thu Oct 17 21:22:55 1996
@@ -210,7 +210,31 @@
next->b_count--;
retry = 1;
}
-
+
+ repeat2:
+ bh = lru_list[BUF_LOCKED];
+ if (!bh)
+ break;
+ for (i = nr_buffers_type[BUF_LOCKED]*2 ; i-- > 0 ; bh = next) {
+ if (bh->b_list != BUF_LOCKED)
+ goto repeat2;
+ next = bh->b_next_free;
+ if (!lru_list[BUF_LOCKED])
+ break;
+ if (dev && bh->b_dev != dev)
+ continue;
+ if (buffer_locked(bh)) {
+ /* Buffer is locked; skip it unless wait is
+ requested AND pass > 0. */
+ if (!wait || !pass) {
+ retry = 1;
+ continue;
+ }
+ wait_on_buffer (bh);
+ goto repeat2;
+ }
+ }
+
/* If we are waiting for the sync to succeed, and if any dirty
blocks were written, then repeat; on the second pass, only
wait for buffers being written (do not pass to write any