jbd2: add errseq to detect client fs's bdev writeback error
authorZhihao Cheng <chengzhihao1@huawei.com>
Wed, 13 Dec 2023 01:32:20 +0000 (09:32 +0800)
committerTheodore Ts'o <tytso@mit.edu>
Fri, 5 Jan 2024 04:42:21 +0000 (23:42 -0500)
Add errseq in journal, so that JBD2 can detect whether metadata is
successfully written to fs bdev. This patch adds detection in recovery
process to replace original solution(using local variable wb_err).

Signed-off-by: Zhihao Cheng <chengzhihao1@huawei.com>
Suggested-by: Jan Kara <jack@suse.cz>
Reviewed-by: Jan Kara <jack@suse.cz>
Link: https://lore.kernel.org/r/20231213013224.2100050-2-chengzhihao1@huawei.com
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/jbd2/journal.c
fs/jbd2/recovery.c
include/linux/jbd2.h

index 206cb53ef2b06813a7344da309e0d811dd3e808c..559938a82379a09a57ba19e38e09e588a227ffc1 100644 (file)
@@ -1534,6 +1534,7 @@ static journal_t *journal_init_common(struct block_device *bdev,
        journal->j_fs_dev = fs_dev;
        journal->j_blk_offset = start;
        journal->j_total_len = len;
+       jbd2_init_fs_dev_write_error(journal);
 
        err = journal_load_superblock(journal);
        if (err)
index 01f744cb97a401d0d13305983f5ea5617921c599..1f7664984d6e47b2ede19c00bdcf09672ccad7f5 100644 (file)
@@ -289,8 +289,6 @@ int jbd2_journal_recover(journal_t *journal)
        journal_superblock_t *  sb;
 
        struct recovery_info    info;
-       errseq_t                wb_err;
-       struct address_space    *mapping;
 
        memset(&info, 0, sizeof(info));
        sb = journal->j_superblock;
@@ -308,9 +306,6 @@ int jbd2_journal_recover(journal_t *journal)
                return 0;
        }
 
-       wb_err = 0;
-       mapping = journal->j_fs_dev->bd_inode->i_mapping;
-       errseq_check_and_advance(&mapping->wb_err, &wb_err);
        err = do_one_pass(journal, &info, PASS_SCAN);
        if (!err)
                err = do_one_pass(journal, &info, PASS_REVOKE);
@@ -334,7 +329,7 @@ int jbd2_journal_recover(journal_t *journal)
        err2 = sync_blockdev(journal->j_fs_dev);
        if (!err)
                err = err2;
-       err2 = errseq_check_and_advance(&mapping->wb_err, &wb_err);
+       err2 = jbd2_check_fs_dev_write_error(journal);
        if (!err)
                err = err2;
        /* Make sure all replayed data is on permanent storage */
index beb30719ee161bad0e01db32edfd14e610a6634c..cea1aa70ae36f13d014bd0591fd7d92b86802847 100644 (file)
@@ -998,6 +998,13 @@ struct journal_s
         */
        struct block_device     *j_fs_dev;
 
+       /**
+        * @j_fs_dev_wb_err:
+        *
+        * Records the errseq of the client fs's backing block device.
+        */
+       errseq_t                j_fs_dev_wb_err;
+
        /**
         * @j_total_len: Total maximum capacity of the journal region on disk.
         */
@@ -1698,6 +1705,25 @@ static inline void jbd2_journal_abort_handle(handle_t *handle)
        handle->h_aborted = 1;
 }
 
+static inline void jbd2_init_fs_dev_write_error(journal_t *journal)
+{
+       struct address_space *mapping = journal->j_fs_dev->bd_inode->i_mapping;
+
+       /*
+        * Save the original wb_err value of client fs's bdev mapping which
+        * could be used to detect the client fs's metadata async write error.
+        */
+       errseq_check_and_advance(&mapping->wb_err, &journal->j_fs_dev_wb_err);
+}
+
+static inline int jbd2_check_fs_dev_write_error(journal_t *journal)
+{
+       struct address_space *mapping = journal->j_fs_dev->bd_inode->i_mapping;
+
+       return errseq_check(&mapping->wb_err,
+                           READ_ONCE(journal->j_fs_dev_wb_err));
+}
+
 #endif /* __KERNEL__   */
 
 /* Comparison functions for transaction IDs: perform comparisons using