dm integrity: add recovery mode
In recovery mode, we don't: - replay the journal - check checksums - allow writes to the device This mode can be used as a last resort for data recovery. The motivation for recovery mode is that when there is a single error in the journal, the user should not lose access to the whole device. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
This commit is contained in:
parent
1aa0efd421
commit
c2bcb2b702
|
@ -59,6 +59,11 @@ Target arguments:
|
|||
either both data and tag or none of them are written. The
|
||||
journaled mode degrades write throughput twice because the
|
||||
data have to be written twice.
|
||||
R - recovery mode - in this mode, journal is not replayed,
|
||||
checksums are not checked and writes to the device are not
|
||||
allowed. This mode is useful for data recovery if the
|
||||
device cannot be activated in any of the other standard
|
||||
modes.
|
||||
|
||||
5. the number of additional arguments
|
||||
|
||||
|
|
|
@ -1216,6 +1216,9 @@ static void integrity_metadata(struct work_struct *w)
|
|||
unsigned sectors_to_process = dio->range.n_sectors;
|
||||
sector_t sector = dio->range.logical_sector;
|
||||
|
||||
if (unlikely(ic->mode == 'R'))
|
||||
goto skip_io;
|
||||
|
||||
checksums = kmalloc((PAGE_SIZE >> SECTOR_SHIFT) * ic->tag_size + extra_space,
|
||||
GFP_NOIO | __GFP_NORETRY | __GFP_NOWARN);
|
||||
if (!checksums)
|
||||
|
@ -1288,6 +1291,7 @@ again:
|
|||
}
|
||||
}
|
||||
}
|
||||
skip_io:
|
||||
dec_in_flight(dio);
|
||||
return;
|
||||
error:
|
||||
|
@ -1327,6 +1331,9 @@ static int dm_integrity_map(struct dm_target *ti, struct bio *bio)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
if (unlikely(ic->mode == 'R') && unlikely(dio->write))
|
||||
return -EIO;
|
||||
|
||||
get_area_and_offset(ic, dio->range.logical_sector, &area, &offset);
|
||||
dio->metadata_block = get_metadata_sector_and_offset(ic, area, offset, &dio->metadata_offset);
|
||||
bio->bi_iter.bi_sector = get_data_sector(ic, area, offset);
|
||||
|
@ -1926,6 +1933,9 @@ static void replay_journal(struct dm_integrity_c *ic)
|
|||
bool journal_empty;
|
||||
unsigned char unused, last_used, want_commit_seq;
|
||||
|
||||
if (ic->mode == 'R')
|
||||
return;
|
||||
|
||||
if (ic->journal_uptodate)
|
||||
return;
|
||||
|
||||
|
@ -2705,7 +2715,7 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
if (!strcmp(argv[3], "J") || !strcmp(argv[3], "D"))
|
||||
if (!strcmp(argv[3], "J") || !strcmp(argv[3], "D") || !strcmp(argv[3], "R"))
|
||||
ic->mode = argv[3][0];
|
||||
else {
|
||||
ti->error = "Invalid mode (expecting J or D)";
|
||||
|
@ -2864,14 +2874,15 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||
ti->error = "Error reading superblock";
|
||||
goto bad;
|
||||
}
|
||||
if (!memcmp(ic->sb->magic, SB_MAGIC, 8)) {
|
||||
should_write_sb = false;
|
||||
} else {
|
||||
for (i = 0; i < 512; i += 8) {
|
||||
if (*(__u64 *)((__u8 *)ic->sb + i)) {
|
||||
r = -EINVAL;
|
||||
ti->error = "The device is not initialized";
|
||||
goto bad;
|
||||
should_write_sb = false;
|
||||
if (memcmp(ic->sb->magic, SB_MAGIC, 8)) {
|
||||
if (ic->mode != 'R') {
|
||||
for (i = 0; i < 512; i += 8) {
|
||||
if (*(__u64 *)((__u8 *)ic->sb + i)) {
|
||||
r = -EINVAL;
|
||||
ti->error = "The device is not initialized";
|
||||
goto bad;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2880,7 +2891,8 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||
ti->error = "Could not initialize superblock";
|
||||
goto bad;
|
||||
}
|
||||
should_write_sb = true;
|
||||
if (ic->mode != 'R')
|
||||
should_write_sb = true;
|
||||
}
|
||||
|
||||
if (ic->sb->version != SB_VERSION) {
|
||||
|
@ -2954,9 +2966,11 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
|
|||
}
|
||||
dm_bufio_set_sector_offset(ic->bufio, ic->start + ic->initial_sectors);
|
||||
|
||||
r = create_journal(ic, &ti->error);
|
||||
if (r)
|
||||
goto bad;
|
||||
if (ic->mode != 'R') {
|
||||
r = create_journal(ic, &ti->error);
|
||||
if (r)
|
||||
goto bad;
|
||||
}
|
||||
|
||||
if (should_write_sb) {
|
||||
int r;
|
||||
|
|
Loading…
Reference in New Issue