summaryrefslogtreecommitdiff
path: root/include/linux
diff options
context:
space:
mode:
authorAndrew Morton <akpm@digeo.com>2003-02-10 00:29:41 -0800
committerKai Germaschewski <kai@tp1.ruhr-uni-bochum.de>2003-02-10 00:29:41 -0800
commit8d49bf3f9d4f6d61f0f759f75e79caaee6dcc6e4 (patch)
treea664f0a82eae712c1051157d38c3ed15714a8a19 /include/linux
parent3d9d68595649eacc0fee8d6cae3081ee78cd9c4a (diff)
[PATCH] Fix synchronous writers to wait properly for the result
Mikulas Patocka <mikulas@artax.karlin.mff.cuni.cz> points out a bug in ll_rw_block() usage. Typical usage is: mark_buffer_dirty(bh); ll_rw_block(WRITE, 1, &bh); wait_on_buffer(bh); the problem is that if the buffer was locked on entry to this code sequence (due to in-progress I/O), ll_rw_block() will not wait, and start new I/O. So this code will wait on the _old_ I/O, and will then continue execution, leaving the buffer dirty. It turns out that all callers were only writing one buffer, and they were all waiting on that writeout. So I added a new sync_dirty_buffer() function: void sync_dirty_buffer(struct buffer_head *bh) { lock_buffer(bh); if (test_clear_buffer_dirty(bh)) { get_bh(bh); bh->b_end_io = end_buffer_io_sync; submit_bh(WRITE, bh); } else { unlock_buffer(bh); } } which allowed a fair amount of code to be removed, while adding the desired data-integrity guarantees. UFS has its own wrappers around ll_rw_block() which got in the way, so this operation was open-coded in that case.
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/buffer_head.h1
-rw-r--r--include/linux/hfs_sysdep.h9
2 files changed, 3 insertions, 7 deletions
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h
index aaefe4e964b7..8def67e47d28 100644
--- a/include/linux/buffer_head.h
+++ b/include/linux/buffer_head.h
@@ -169,6 +169,7 @@ struct buffer_head *alloc_buffer_head(void);
void free_buffer_head(struct buffer_head * bh);
void FASTCALL(unlock_buffer(struct buffer_head *bh));
void ll_rw_block(int, int, struct buffer_head * bh[]);
+void sync_dirty_buffer(struct buffer_head *bh);
int submit_bh(int, struct buffer_head *);
void write_boundary_block(struct block_device *bdev,
sector_t bblock, unsigned blocksize);
diff --git a/include/linux/hfs_sysdep.h b/include/linux/hfs_sysdep.h
index d1e67f3ada14..1468ef02e8b6 100644
--- a/include/linux/hfs_sysdep.h
+++ b/include/linux/hfs_sysdep.h
@@ -155,13 +155,8 @@ static inline void hfs_buffer_dirty(hfs_buffer buffer) {
}
static inline void hfs_buffer_sync(hfs_buffer buffer) {
- while (buffer_locked(buffer)) {
- wait_on_buffer(buffer);
- }
- if (buffer_dirty(buffer)) {
- ll_rw_block(WRITE, 1, &buffer);
- wait_on_buffer(buffer);
- }
+ if (buffer_dirty(buffer))
+ sync_dirty_buffer(buffer);
}
static inline void *hfs_buffer_data(const hfs_buffer buffer) {