From bd1abbf892a4a515f71a7d5df45fe0890d312308 Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Thu, 22 Aug 2019 23:02:19 -0400 Subject: [PATCH] add patch treat-buffers-with-write-errors-as-contining-valid-data --- series | 1 + timestamps | 3 +- ...ffers-with-write-errors-as-contining-valid-data | 82 ++++++++++++++++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 treat-buffers-with-write-errors-as-contining-valid-data diff --git a/series b/series index 732f1ee5..743502a0 100644 --- a/series +++ b/series @@ -9,6 +9,7 @@ return-extent-cache-info-via-fiemap drop-legacy-pre-1970-encoding-workaround set-error-return-correctly-when-ext4_htree_store_dirent-fails fix-warning-inside-ext4_convert_unwritten_extents_endio +treat-buffers-with-write-errors-as-contining-valid-data #################################################### # unstable patches diff --git a/timestamps b/timestamps index d0963408..359d0c1a 100755 --- a/timestamps +++ b/timestamps @@ -23,4 +23,5 @@ touch -d @1565634578 set-error-return-correctly-when-ext4_htree_store_dirent-fai touch -d @1566528768 series touch -d @1566528826 fix-warning-inside-ext4_convert_unwritten_extents_endio touch -d @1566528843 status -touch -d @1566528848 timestamps +touch -d @1566529232 treat-buffers-with-write-errors-as-contining-valid-data +touch -d @1566529253 timestamps diff --git a/treat-buffers-with-write-errors-as-contining-valid-data b/treat-buffers-with-write-errors-as-contining-valid-data new file mode 100644 index 00000000..e334a543 --- /dev/null +++ b/treat-buffers-with-write-errors-as-contining-valid-data @@ -0,0 +1,82 @@ +ext4: treat buffers with write errors as containing valid data + +From: ZhangXiaoxu + +I got some errors when I repair an ext4 volume which stacked by an +iscsi target: + Entry 'test60' in / (2) has deleted/unused inode 73750. Clear? +It can be reproduced when the network not good enough. + +When I debug this I found ext4 will read entry buffer from disk and +the buffer is marked with write_io_error. + +If the buffer is marked with write_io_error, it means it already +wroten to journal, and not checked out to disk. IOW, the journal +is newer than the data in disk. +If this journal record 'delete test60', it means the 'test60' still +on the disk metadata. + +In this case, if we read the buffer from disk successfully and create +file continue, the new journal record will overwrite the journal +which record 'delete test60', then the entry corruptioned. + +So, use the buffer rather than read from disk if the buffer is marked +with write_io_error. + +Signed-off-by: Zhang Xiaoxu +Signed-off-by: Theodore Ts'o +--- + fs/ext4/ext4.h | 13 +++++++++++++ + fs/ext4/inode.c | 4 ++-- + 2 files changed, 15 insertions(+), 2 deletions(-) + +diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h +index 1cb6785..5ebb36d 100644 +--- a/fs/ext4/ext4.h ++++ b/fs/ext4/ext4.h +@@ -3301,6 +3301,19 @@ static inline void ext4_clear_io_unwritten_flag(ext4_io_end_t *io_end) + + extern const struct iomap_ops ext4_iomap_ops; + ++static inline int ext4_buffer_uptodate(struct buffer_head *bh) ++{ ++ /* ++ * If the buffer has the write error flag, we have failed ++ * to write out data in the block. In this case, we don't ++ * have to read the block because we may read the old data ++ * successfully. ++ */ ++ if (!buffer_uptodate(bh) && buffer_write_io_error(bh)) ++ set_buffer_uptodate(bh); ++ return buffer_uptodate(bh); ++} ++ + #endif /* __KERNEL__ */ + + #define EFSBADCRC EBADMSG /* Bad CRC detected */ +diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c +index 82298c6..3546388 100644 +--- a/fs/ext4/inode.c ++++ b/fs/ext4/inode.c +@@ -1018,7 +1018,7 @@ struct buffer_head *ext4_bread(handle_t *handle, struct inode *inode, + bh = ext4_getblk(handle, inode, block, map_flags); + if (IS_ERR(bh)) + return bh; +- if (!bh || buffer_uptodate(bh)) ++ if (!bh || ext4_buffer_uptodate(bh)) + return bh; + ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, &bh); + wait_on_buffer(bh); +@@ -1045,7 +1045,7 @@ int ext4_bread_batch(struct inode *inode, ext4_lblk_t block, int bh_count, + + for (i = 0; i < bh_count; i++) + /* Note that NULL bhs[i] is valid because of holes. */ +- if (bhs[i] && !buffer_uptodate(bhs[i])) ++ if (bhs[i] && !ext4_buffer_uptodate(bhs[i])) + ll_rw_block(REQ_OP_READ, REQ_META | REQ_PRIO, 1, + &bhs[i]); + +-- +2.7.4 + + -- 2.11.4.GIT