Messages in this thread Patch in this message |  | | Subject | FIXED: Fsync is no longer synchronous | Date | Thu, 17 Oct 1996 23:42:43 +0200 | From | Alain Knaff <> |
| |
> It seems that in recent kernels (at least 2.1.3 and 2.1.4, but >possibly earlyer) the fsync syscall is no longer synchronous. I.e. it >may schedule the flushing of the data to the disk, but return before >the flushing is actually complete. Synchronous syncing is needed for >reliable operations on removeable media (such as floppy disks). [...]
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
|  |