From: Hifumi Hisashi I found bugs on error handlings in the functions arround the ext3 file system, which cause inadequate completions of synchronous write I/O operations when disk I/O failures occur. Both 2.4 and 2.6 have this problem. I carried out following experiment: 1. Mount a ext3 file system on a SCSI disk with ordered mode. 2. Open a file on the file system with O_SYNC|O_RDWR|O_TRUNC|O_CREAT flag. 3. Write 512 bytes data to the file by calling write() every 5 seconds, and examine return values from the syscall. from write(). 4. Disconnect the SCSI cable, and examine messages from the kernel. After the SCSI cable is disconnected, write() must fail. But the result was different: write() succeeded for a while even though messages of the kernel notified SCSI I/O error. By applying following modifications, the above problem was solved. Signed-off-by: Hisashi Hifumi Signed-off-by: Andrew Morton --- 25-akpm/fs/buffer.c | 8 +++++--- 25-akpm/fs/fs-writeback.c | 13 +++++++++---- 25-akpm/fs/inode.c | 2 +- 25-akpm/fs/jbd/commit.c | 3 +++ 25-akpm/include/linux/fs.h | 2 +- 5 files changed, 19 insertions(+), 9 deletions(-) diff -puN fs/buffer.c~bug-on-error-handlings-in-ext3-under-i-o-failure fs/buffer.c --- 25/fs/buffer.c~bug-on-error-handlings-in-ext3-under-i-o-failure 2005-01-10 21:15:29.494969664 -0800 +++ 25-akpm/fs/buffer.c 2005-01-10 21:15:29.511967080 -0800 @@ -311,10 +311,10 @@ int file_fsync(struct file *filp, struct { struct inode * inode = dentry->d_inode; struct super_block * sb; - int ret; + int ret, err; /* sync the inode to buffers */ - write_inode_now(inode, 0); + ret = write_inode_now(inode, 0); /* sync the superblock to buffers */ sb = inode->i_sb; @@ -324,7 +324,9 @@ int file_fsync(struct file *filp, struct unlock_super(sb); /* .. finally sync the buffers to disk */ - ret = sync_blockdev(sb->s_bdev); + err = sync_blockdev(sb->s_bdev); + if (!ret) + ret = err; return ret; } diff -puN fs/fs-writeback.c~bug-on-error-handlings-in-ext3-under-i-o-failure fs/fs-writeback.c --- 25/fs/fs-writeback.c~bug-on-error-handlings-in-ext3-under-i-o-failure 2005-01-10 21:15:29.496969360 -0800 +++ 25-akpm/fs/fs-writeback.c 2005-01-10 21:15:29.512966928 -0800 @@ -567,8 +567,9 @@ void sync_inodes(int wait) * dirty. This is primarily needed by knfsd. */ -void write_inode_now(struct inode *inode, int sync) +int write_inode_now(struct inode *inode, int sync) { + int err = 0; struct writeback_control wbc = { .nr_to_write = LONG_MAX, .sync_mode = WB_SYNC_ALL, @@ -579,10 +580,11 @@ void write_inode_now(struct inode *inode might_sleep(); spin_lock(&inode_lock); - __writeback_single_inode(inode, &wbc); + err = __writeback_single_inode(inode, &wbc); spin_unlock(&inode_lock); if (sync) wait_on_inode(inode); + return err; } EXPORT_SYMBOL(write_inode_now); @@ -651,8 +653,11 @@ int generic_osync_inode(struct inode *in need_write_inode_now = 1; spin_unlock(&inode_lock); - if (need_write_inode_now) - write_inode_now(inode, 1); + if (need_write_inode_now) { + err2 = write_inode_now(inode, 1); + if (!err) + err = err2; + } else wait_on_inode(inode); diff -puN fs/inode.c~bug-on-error-handlings-in-ext3-under-i-o-failure fs/inode.c --- 25/fs/inode.c~bug-on-error-handlings-in-ext3-under-i-o-failure 2005-01-10 21:15:29.497969208 -0800 +++ 25-akpm/fs/inode.c 2005-01-10 21:15:29.513966776 -0800 @@ -1049,7 +1049,7 @@ void generic_forget_inode(struct inode * spin_unlock(&inode_lock); if (!sb || (sb->s_flags & MS_ACTIVE)) return; - write_inode_now(inode, 1); + (void) write_inode_now(inode, 1); spin_lock(&inode_lock); inodes_stat.nr_unused--; hlist_del_init(&inode->i_hash); diff -puN fs/jbd/commit.c~bug-on-error-handlings-in-ext3-under-i-o-failure fs/jbd/commit.c --- 25/fs/jbd/commit.c~bug-on-error-handlings-in-ext3-under-i-o-failure 2005-01-10 21:15:29.499968904 -0800 +++ 25-akpm/fs/jbd/commit.c 2005-01-10 21:15:29.514966624 -0800 @@ -337,6 +337,9 @@ write_out_data: } spin_unlock(&journal->j_list_lock); + if (err) + __journal_abort_hard(journal); + journal_write_revoke_records(journal, commit_transaction); jbd_debug(3, "JBD: commit phase 2\n"); diff -puN include/linux/fs.h~bug-on-error-handlings-in-ext3-under-i-o-failure include/linux/fs.h --- 25/include/linux/fs.h~bug-on-error-handlings-in-ext3-under-i-o-failure 2005-01-10 21:15:29.505967992 -0800 +++ 25-akpm/include/linux/fs.h 2005-01-10 21:15:29.516966320 -0800 @@ -1363,7 +1363,7 @@ static inline void invalidate_remote_ino invalidate_inode_pages(inode->i_mapping); } extern int invalidate_inode_pages2(struct address_space *mapping); -extern void write_inode_now(struct inode *, int); +extern int write_inode_now(struct inode *, int); extern int filemap_fdatawrite(struct address_space *); extern int filemap_flush(struct address_space *); extern int filemap_fdatawait(struct address_space *); _