in dm-integrity.c [2899:3057]
static void replay_journal(struct dm_integrity_c *ic)
{
unsigned i, j;
bool used_commit_ids[N_COMMIT_IDS];
unsigned max_commit_id_sections[N_COMMIT_IDS];
unsigned write_start, write_sections;
unsigned continue_section;
bool journal_empty;
unsigned char unused, last_used, want_commit_seq;
if (ic->mode == 'R')
return;
if (ic->journal_uptodate)
return;
last_used = 0;
write_start = 0;
if (!ic->just_formatted) {
DEBUG_print("reading journal\n");
rw_journal(ic, REQ_OP_READ, 0, 0, ic->journal_sections, NULL);
if (ic->journal_io)
DEBUG_bytes(lowmem_page_address(ic->journal_io[0].page), 64, "read journal");
if (ic->journal_io) {
struct journal_completion crypt_comp;
crypt_comp.ic = ic;
init_completion(&crypt_comp.comp);
crypt_comp.in_flight = (atomic_t)ATOMIC_INIT(0);
encrypt_journal(ic, false, 0, ic->journal_sections, &crypt_comp);
wait_for_completion(&crypt_comp.comp);
}
DEBUG_bytes(lowmem_page_address(ic->journal[0].page), 64, "decrypted journal");
}
if (dm_integrity_failed(ic))
goto clear_journal;
journal_empty = true;
memset(used_commit_ids, 0, sizeof used_commit_ids);
memset(max_commit_id_sections, 0, sizeof max_commit_id_sections);
for (i = 0; i < ic->journal_sections; i++) {
for (j = 0; j < ic->journal_section_sectors; j++) {
int k;
struct journal_sector *js = access_journal(ic, i, j);
k = find_commit_seq(ic, i, j, js->commit_id);
if (k < 0)
goto clear_journal;
used_commit_ids[k] = true;
max_commit_id_sections[k] = i;
}
if (journal_empty) {
for (j = 0; j < ic->journal_section_entries; j++) {
struct journal_entry *je = access_journal_entry(ic, i, j);
if (!journal_entry_is_unused(je)) {
journal_empty = false;
break;
}
}
}
}
if (!used_commit_ids[N_COMMIT_IDS - 1]) {
unused = N_COMMIT_IDS - 1;
while (unused && !used_commit_ids[unused - 1])
unused--;
} else {
for (unused = 0; unused < N_COMMIT_IDS; unused++)
if (!used_commit_ids[unused])
break;
if (unused == N_COMMIT_IDS) {
dm_integrity_io_error(ic, "journal commit ids", -EIO);
goto clear_journal;
}
}
DEBUG_print("first unused commit seq %d [%d,%d,%d,%d]\n",
unused, used_commit_ids[0], used_commit_ids[1],
used_commit_ids[2], used_commit_ids[3]);
last_used = prev_commit_seq(unused);
want_commit_seq = prev_commit_seq(last_used);
if (!used_commit_ids[want_commit_seq] && used_commit_ids[prev_commit_seq(want_commit_seq)])
journal_empty = true;
write_start = max_commit_id_sections[last_used] + 1;
if (unlikely(write_start >= ic->journal_sections))
want_commit_seq = next_commit_seq(want_commit_seq);
wraparound_section(ic, &write_start);
i = write_start;
for (write_sections = 0; write_sections < ic->journal_sections; write_sections++) {
for (j = 0; j < ic->journal_section_sectors; j++) {
struct journal_sector *js = access_journal(ic, i, j);
if (js->commit_id != dm_integrity_commit_id(ic, i, j, want_commit_seq)) {
/*
* This could be caused by crash during writing.
* We won't replay the inconsistent part of the
* journal.
*/
DEBUG_print("commit id mismatch at position (%u, %u): %d != %d\n",
i, j, find_commit_seq(ic, i, j, js->commit_id), want_commit_seq);
goto brk;
}
}
i++;
if (unlikely(i >= ic->journal_sections))
want_commit_seq = next_commit_seq(want_commit_seq);
wraparound_section(ic, &i);
}
brk:
if (!journal_empty) {
DEBUG_print("replaying %u sections, starting at %u, commit seq %d\n",
write_sections, write_start, want_commit_seq);
do_journal_write(ic, write_start, write_sections, true);
}
if (write_sections == ic->journal_sections && (ic->mode == 'J' || journal_empty)) {
continue_section = write_start;
ic->commit_seq = want_commit_seq;
DEBUG_print("continuing from section %u, commit seq %d\n", write_start, ic->commit_seq);
} else {
unsigned s;
unsigned char erase_seq;
clear_journal:
DEBUG_print("clearing journal\n");
erase_seq = prev_commit_seq(prev_commit_seq(last_used));
s = write_start;
init_journal(ic, s, 1, erase_seq);
s++;
wraparound_section(ic, &s);
if (ic->journal_sections >= 2) {
init_journal(ic, s, ic->journal_sections - 2, erase_seq);
s += ic->journal_sections - 2;
wraparound_section(ic, &s);
init_journal(ic, s, 1, erase_seq);
}
continue_section = 0;
ic->commit_seq = next_commit_seq(erase_seq);
}
ic->committed_section = continue_section;
ic->n_committed_sections = 0;
ic->uncommitted_section = continue_section;
ic->n_uncommitted_sections = 0;
ic->free_section = continue_section;
ic->free_section_entry = 0;
ic->free_sectors = ic->journal_entries;
ic->journal_tree_root = RB_ROOT;
for (i = 0; i < ic->journal_entries; i++)
init_journal_node(&ic->journal_tree[i]);
}