Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c2bcb2b7 authored by Mikulas Patocka's avatar Mikulas Patocka Committed by Mike Snitzer
Browse files

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: default avatarMikulas Patocka <mpatocka@redhat.com>
Signed-off-by: default avatarMike Snitzer <snitzer@redhat.com>
parent 1aa0efd4
Loading
Loading
Loading
Loading
+5 −0
Original line number Diff line number Diff line
@@ -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

+27 −13
Original line number Diff line number Diff line
@@ -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 @@ static void integrity_metadata(struct work_struct *w)
			}
		}
	}
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,9 +2874,9 @@ 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 {
	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;
@@ -2874,12 +2884,14 @@ static int dm_integrity_ctr(struct dm_target *ti, unsigned argc, char **argv)
					goto bad;
				}
			}
		}

		r = initialize_superblock(ic, journal_sectors, interleave_sectors);
		if (r) {
			ti->error = "Could not initialize superblock";
			goto bad;
		}
		if (ic->mode != 'R')
			should_write_sb = true;
	}

@@ -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);

	if (ic->mode != 'R') {
		r = create_journal(ic, &ti->error);
		if (r)
			goto bad;
	}

	if (should_write_sb) {
		int r;