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);
|
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)
|
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))
|
if (!test_opt2(sb, JOURNAL_FAST_COMMIT))
|
||||||
return;
|
return;
|
||||||
journal->j_fc_cleanup_callback = ext4_fc_cleanup;
|
journal->j_fc_cleanup_callback = ext4_fc_cleanup;
|
||||||
|
|
|
@ -35,7 +35,6 @@ struct recovery_info
|
||||||
int nr_revoke_hits;
|
int nr_revoke_hits;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum passtype {PASS_SCAN, PASS_REVOKE, PASS_REPLAY};
|
|
||||||
static int do_one_pass(journal_t *journal,
|
static int do_one_pass(journal_t *journal,
|
||||||
struct recovery_info *info, enum passtype pass);
|
struct recovery_info *info, enum passtype pass);
|
||||||
static int scan_revoke_records(journal_t *, struct buffer_head *,
|
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! */
|
/* Make sure we wrap around the log correctly! */
|
||||||
#define wrap(journal, var) \
|
#define wrap(journal, var) \
|
||||||
do { \
|
do { \
|
||||||
if (var >= (journal)->j_last) \
|
unsigned long _wrap_last = \
|
||||||
var -= ((journal)->j_last - (journal)->j_first); \
|
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)
|
} 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
|
* jbd2_journal_recover - recovers a on-disk journal
|
||||||
* @journal: the journal to recover
|
* @journal: the journal to recover
|
||||||
|
@ -472,7 +512,9 @@ static int do_one_pass(journal_t *journal,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
jbd_debug(2, "Scanning for sequence ID %u at %lu/%lu\n",
|
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
|
/* Skip over each chunk of the transaction looking
|
||||||
* either the next descriptor block or the final commit
|
* either the next descriptor block or the final commit
|
||||||
|
@ -834,6 +876,13 @@ static int do_one_pass(journal_t *journal,
|
||||||
success = -EIO;
|
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)
|
if (block_error && success == 0)
|
||||||
success = -EIO;
|
success = -EIO;
|
||||||
return success;
|
return success;
|
||||||
|
|
|
@ -751,6 +751,11 @@ jbd2_time_diff(unsigned long start, unsigned long end)
|
||||||
|
|
||||||
#define JBD2_NR_BATCH 64
|
#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
|
* struct journal_s - The journal_s type is the concrete type associated with
|
||||||
* journal_t.
|
* journal_t.
|
||||||
|
@ -1248,6 +1253,21 @@ struct journal_s
|
||||||
*/
|
*/
|
||||||
void (*j_fc_cleanup_callback)(struct journal_s *journal, int);
|
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) \
|
#define jbd2_might_wait_for_commit(j) \
|
||||||
|
|
Загрузка…
Ссылка в новой задаче