summaryrefslogtreecommitdiffstats
path: root/fs/ocfs2
diff options
context:
space:
mode:
authorpiaojun <piaojun@huawei.com>2018-01-31 19:15:32 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2018-01-31 20:18:35 -0500
commitd984187e3a1ad7d12447a7ab2c43ce3717a2b5b3 (patch)
tree89700a88b07f2389e9072b83875220442c1afa98 /fs/ocfs2
parente75ed71be4f2f7508bd7d1d993d34095a10ca447 (diff)
ocfs2: return error when we attempt to access a dirty bh in jbd2
We should not reuse the dirty bh in jbd2 directly due to the following situation: 1. When removing extent rec, we will dirty the bhs of extent rec and truncate log at the same time, and hand them over to jbd2. 2. The bhs are submitted to jbd2 area successfully. 3. The write-back thread of device help flush the bhs to disk but encounter write error due to abnormal storage link. 4. After a while the storage link become normal. Truncate log flush worker triggered by the next space reclaiming found the dirty bh of truncate log and clear its 'BH_Write_EIO' and then set it uptodate in __ocfs2_journal_access(): ocfs2_truncate_log_worker ocfs2_flush_truncate_log __ocfs2_flush_truncate_log ocfs2_replay_truncate_records ocfs2_journal_access_di __ocfs2_journal_access // here we clear io_error and set 'tl_bh' uptodata. 5. Then jbd2 will flush the bh of truncate log to disk, but the bh of extent rec is still in error state, and unfortunately nobody will take care of it. 6. At last the space of extent rec was not reduced, but truncate log flush worker have given it back to globalalloc. That will cause duplicate cluster problem which could be identified by fsck.ocfs2. Sadly we can hardly revert this but set fs read-only in case of ruining atomicity and consistency of space reclaim. Link: http://lkml.kernel.org/r/5A6E8092.8090701@huawei.com Fixes: acf8fdbe6afb ("ocfs2: do not BUG if buffer not uptodate in __ocfs2_journal_access") Signed-off-by: Jun Piao <piaojun@huawei.com> Reviewed-by: Yiwen Jiang <jiangyiwen@huawei.com> Reviewed-by: Changwei Ge <ge.changwei@h3c.com> Cc: Mark Fasheh <mfasheh@versity.com> Cc: Joel Becker <jlbec@evilplan.org> Cc: Junxiao Bi <junxiao.bi@oracle.com> Cc: Joseph Qi <jiangqi903@gmail.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/ocfs2')
-rw-r--r--fs/ocfs2/journal.c23
1 files changed, 12 insertions, 11 deletions
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 36304434eacf..e5dcea6cee5f 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -666,23 +666,24 @@ static int __ocfs2_journal_access(handle_t *handle,
666 /* we can safely remove this assertion after testing. */ 666 /* we can safely remove this assertion after testing. */
667 if (!buffer_uptodate(bh)) { 667 if (!buffer_uptodate(bh)) {
668 mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n"); 668 mlog(ML_ERROR, "giving me a buffer that's not uptodate!\n");
669 mlog(ML_ERROR, "b_blocknr=%llu\n", 669 mlog(ML_ERROR, "b_blocknr=%llu, b_state=0x%lx\n",
670 (unsigned long long)bh->b_blocknr); 670 (unsigned long long)bh->b_blocknr, bh->b_state);
671 671
672 lock_buffer(bh); 672 lock_buffer(bh);
673 /* 673 /*
674 * A previous attempt to write this buffer head failed. 674 * A previous transaction with a couple of buffer heads fail
675 * Nothing we can do but to retry the write and hope for 675 * to checkpoint, so all the bhs are marked as BH_Write_EIO.
676 * the best. 676 * For current transaction, the bh is just among those error
677 * bhs which previous transaction handle. We can't just clear
678 * its BH_Write_EIO and reuse directly, since other bhs are
679 * not written to disk yet and that will cause metadata
680 * inconsistency. So we should set fs read-only to avoid
681 * further damage.
677 */ 682 */
678 if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) { 683 if (buffer_write_io_error(bh) && !buffer_uptodate(bh)) {
679 clear_buffer_write_io_error(bh);
680 set_buffer_uptodate(bh);
681 }
682
683 if (!buffer_uptodate(bh)) {
684 unlock_buffer(bh); 684 unlock_buffer(bh);
685 return -EIO; 685 return ocfs2_error(osb->sb, "A previous attempt to "
686 "write this buffer head failed\n");
686 } 687 }
687 unlock_buffer(bh); 688 unlock_buffer(bh);
688 } 689 }