jbd2: fast commit recovery path
This patch adds fast commit recovery support in JBD2. Signed-off-by: Harshad Shirwadkar <harshadshirwadkar@gmail.com> Link: https://lore.kernel.org/r/20201015203802.3597742-7-harshadshirwadkar@gmail.com Signed-off-by: Theodore Ts'o <tytso@mit.edu>
This commit is contained in:
Родитель
aa75f4d3da
Коммит
5b849b5f96
|
@ -1188,8 +1188,23 @@ static void ext4_fc_cleanup(journal_t *journal, int full)
|
|||
trace_ext4_fc_stats(sb);
|
||||
}
|
||||
|
||||
/*
|
||||
* Main recovery path entry point.
|
||||
*/
|
||||
static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
|
||||
enum passtype pass, int off, tid_t expected_tid)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ext4_fc_init(struct super_block *sb, journal_t *journal)
|
||||
{
|
||||
/*
|
||||
* We set replay callback even if fast commit disabled because we may
|
||||
* could still have fast commit blocks that need to be replayed even if
|
||||
* fast commit has now been turned off.
|
||||
*/
|
||||
journal->j_fc_replay_callback = ext4_fc_replay;
|
||||
if (!test_opt2(sb, JOURNAL_FAST_COMMIT))
|
||||
return;
|
||||
journal->j_fc_cleanup_callback = ext4_fc_cleanup;
|
||||
|
|
|
@ -35,7 +35,6 @@ struct recovery_info
|
|||
int nr_revoke_hits;
|
||||
};
|
||||
|
||||
enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
|
||||
static int do_one_pass(journal_t *journal,
|
||||
struct recovery_info *info, enum passtype pass);
|
||||
static int scan_revoke_records(journal_t *, struct buffer_head *,
|
||||
|
@ -225,10 +224,51 @@ static int count_tags(journal_t *journal, struct buffer_head *bh)
|
|||
/* Make sure we wrap around the log correctly! */
|
||||
#define wrap(journal, var) \
|
||||
do { \
|
||||
if (var >= (journal)->j_last) \
|
||||
var -= ((journal)->j_last - (journal)->j_first); \
|
||||
unsigned long _wrap_last = \
|
||||
jbd2_has_feature_fast_commit(journal) ? \
|
||||
(journal)->j_fc_last : (journal)->j_last; \
|
||||
\
|
||||
if (var >= _wrap_last) \
|
||||
var -= (_wrap_last - (journal)->j_first); \
|
||||
} while (0)
|
||||
|
||||
static int fc_do_one_pass(journal_t *journal,
|
||||
struct recovery_info *info, enum passtype pass)
|
||||
{
|
||||
unsigned int expected_commit_id = info->end_transaction;
|
||||
unsigned long next_fc_block;
|
||||
struct buffer_head *bh;
|
||||
int err = 0;
|
||||
|
||||
next_fc_block = journal->j_fc_first;
|
||||
if (!journal->j_fc_replay_callback)
|
||||
return 0;
|
||||
|
||||
while (next_fc_block <= journal->j_fc_last) {
|
||||
jbd_debug(3, "Fast commit replay: next block %ld",
|
||||
next_fc_block);
|
||||
err = jread(&bh, journal, next_fc_block);
|
||||
if (err) {
|
||||
jbd_debug(3, "Fast commit replay: read error");
|
||||
break;
|
||||
}
|
||||
|
||||
jbd_debug(3, "Processing fast commit blk with seq %d");
|
||||
err = journal->j_fc_replay_callback(journal, bh, pass,
|
||||
next_fc_block - journal->j_fc_first,
|
||||
expected_commit_id);
|
||||
next_fc_block++;
|
||||
if (err < 0 || err == JBD2_FC_REPLAY_STOP)
|
||||
break;
|
||||
err = 0;
|
||||
}
|
||||
|
||||
if (err)
|
||||
jbd_debug(3, "Fast commit replay failed, err = %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* jbd2_journal_recover - recovers a on-disk journal
|
||||
* @journal: the journal to recover
|
||||
|
@ -472,7 +512,9 @@ static int do_one_pass(journal_t *journal,
|
|||
break;
|
||||
|
||||
jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
|
||||
next_commit_ID, next_log_block, journal->j_last);
|
||||
next_commit_ID, next_log_block,
|
||||
jbd2_has_feature_fast_commit(journal) ?
|
||||
journal->j_fc_last : journal->j_last);
|
||||
|
||||
/* Skip over each chunk of the transaction looking
|
||||
* either the next descriptor block or the final commit
|
||||
|
@ -834,6 +876,13 @@ static int do_one_pass(journal_t *journal,
|
|||
success = -EIO;
|
||||
}
|
||||
}
|
||||
|
||||
if (jbd2_has_feature_fast_commit(journal) && pass != PASS_REVOKE) {
|
||||
err = fc_do_one_pass(journal, info, pass);
|
||||
if (err)
|
||||
success = err;
|
||||
}
|
||||
|
||||
if (block_error && success == 0)
|
||||
success = -EIO;
|
||||
return success;
|
||||
|
|
|
@ -751,6 +751,11 @@ jbd2_time_diff(unsigned long start, unsigned long end)
|
|||
|
||||
#define JBD2_NR_BATCH 64
|
||||
|
||||
enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
|
||||
|
||||
#define JBD2_FC_REPLAY_STOP 0
|
||||
#define JBD2_FC_REPLAY_CONTINUE 1
|
||||
|
||||
/**
|
||||
* struct journal_s - The journal_s type is the concrete type associated with
|
||||
* journal_t.
|
||||
|
@ -1248,6 +1253,21 @@ struct journal_s
|
|||
*/
|
||||
void (*j_fc_cleanup_callback)(struct journal_s *journal, int);
|
||||
|
||||
/*
|
||||
* @j_fc_replay_callback:
|
||||
*
|
||||
* File-system specific function that performs replay of a fast
|
||||
* commit. JBD2 calls this function for each fast commit block found in
|
||||
* the journal. This function should return JBD2_FC_REPLAY_CONTINUE
|
||||
* to indicate that the block was processed correctly and more fast
|
||||
* commit replay should continue. Return value of JBD2_FC_REPLAY_STOP
|
||||
* indicates the end of replay (no more blocks remaining). A negative
|
||||
* return value indicates error.
|
||||
*/
|
||||
int (*j_fc_replay_callback)(struct journal_s *journal,
|
||||
struct buffer_head *bh,
|
||||
enum passtype pass, int off,
|
||||
tid_t expected_commit_id);
|
||||
};
|
||||
|
||||
#define jbd2_might_wait_for_commit(j) \
|
||||
|
|
Загрузка…
Ссылка в новой задаче