Commit 359cdf5a authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'for-6.12/dm-fixes' of...

Merge tag 'for-6.12/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mikulas Patocka:
 "Revert the patch that made dm-verity restart or panic on I/O errors,
  and instead add new explicit options for people who want that
  behavior"

* tag 'for-6.12/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
  dm-verity: introduce the options restart_on_error and panic_on_error
  Revert: "dm-verity: restart or panic on an I/O error"
parents 27af290f f811b838
Loading
Loading
Loading
Loading
+78 −16
Original line number Diff line number Diff line
@@ -36,11 +36,13 @@
#define DM_VERITY_OPT_LOGGING		"ignore_corruption"
#define DM_VERITY_OPT_RESTART		"restart_on_corruption"
#define DM_VERITY_OPT_PANIC		"panic_on_corruption"
#define DM_VERITY_OPT_ERROR_RESTART	"restart_on_error"
#define DM_VERITY_OPT_ERROR_PANIC	"panic_on_error"
#define DM_VERITY_OPT_IGN_ZEROES	"ignore_zero_blocks"
#define DM_VERITY_OPT_AT_MOST_ONCE	"check_at_most_once"
#define DM_VERITY_OPT_TASKLET_VERIFY	"try_verify_in_tasklet"

#define DM_VERITY_OPTS_MAX		(4 + DM_VERITY_OPTS_FEC + \
#define DM_VERITY_OPTS_MAX		(5 + DM_VERITY_OPTS_FEC + \
					 DM_VERITY_ROOT_HASH_VERIFICATION_OPTS)

static unsigned int dm_verity_prefetch_cluster = DM_VERITY_DEFAULT_PREFETCH_SIZE;
@@ -273,10 +275,8 @@ static int verity_handle_err(struct dm_verity *v, enum verity_block_type type,
	if (v->mode == DM_VERITY_MODE_LOGGING)
		return 0;

	if (v->mode == DM_VERITY_MODE_RESTART) {
		pr_emerg("dm-verity device corrupted\n");
		emergency_restart();
	}
	if (v->mode == DM_VERITY_MODE_RESTART)
		kernel_restart("dm-verity device corrupted");

	if (v->mode == DM_VERITY_MODE_PANIC)
		panic("dm-verity device corrupted");
@@ -585,6 +585,11 @@ static inline bool verity_is_system_shutting_down(void)
		|| system_state == SYSTEM_RESTART;
}

static void restart_io_error(struct work_struct *w)
{
	kernel_restart("dm-verity device has I/O error");
}

/*
 * End one "io" structure with a given error.
 */
@@ -602,18 +607,18 @@ static void verity_finish_io(struct dm_verity_io *io, blk_status_t status)
	if (unlikely(status != BLK_STS_OK) &&
	    unlikely(!(bio->bi_opf & REQ_RAHEAD)) &&
	    !verity_is_system_shutting_down()) {
		if (v->mode == DM_VERITY_MODE_RESTART ||
		    v->mode == DM_VERITY_MODE_PANIC)
			DMERR_LIMIT("%s has error: %s", v->data_dev->name,
					blk_status_to_str(status));

		if (v->mode == DM_VERITY_MODE_RESTART) {
			pr_emerg("dm-verity device corrupted\n");
			emergency_restart();
		if (v->error_mode == DM_VERITY_MODE_PANIC) {
			panic("dm-verity device has I/O error");
		}
		if (v->error_mode == DM_VERITY_MODE_RESTART) {
			static DECLARE_WORK(restart_work, restart_io_error);
			queue_work(v->verify_wq, &restart_work);
			/*
			 * We deliberately don't call bio_endio here, because
			 * the machine will be restarted anyway.
			 */
			return;
		}

		if (v->mode == DM_VERITY_MODE_PANIC)
			panic("dm-verity device corrupted");
	}

	bio_endio(bio);
@@ -824,6 +829,8 @@ static void verity_status(struct dm_target *ti, status_type_t type,
				DMEMIT("%02x", v->salt[x]);
		if (v->mode != DM_VERITY_MODE_EIO)
			args++;
		if (v->error_mode != DM_VERITY_MODE_EIO)
			args++;
		if (verity_fec_is_enabled(v))
			args += DM_VERITY_OPTS_FEC;
		if (v->zero_digest)
@@ -853,6 +860,19 @@ static void verity_status(struct dm_target *ti, status_type_t type,
				BUG();
			}
		}
		if (v->error_mode != DM_VERITY_MODE_EIO) {
			DMEMIT(" ");
			switch (v->error_mode) {
			case DM_VERITY_MODE_RESTART:
				DMEMIT(DM_VERITY_OPT_ERROR_RESTART);
				break;
			case DM_VERITY_MODE_PANIC:
				DMEMIT(DM_VERITY_OPT_ERROR_PANIC);
				break;
			default:
				BUG();
			}
		}
		if (v->zero_digest)
			DMEMIT(" " DM_VERITY_OPT_IGN_ZEROES);
		if (v->validated_blocks)
@@ -905,6 +925,19 @@ static void verity_status(struct dm_target *ti, status_type_t type,
				DMEMIT("invalid");
			}
		}
		if (v->error_mode != DM_VERITY_MODE_EIO) {
			DMEMIT(",verity_error_mode=");
			switch (v->error_mode) {
			case DM_VERITY_MODE_RESTART:
				DMEMIT(DM_VERITY_OPT_ERROR_RESTART);
				break;
			case DM_VERITY_MODE_PANIC:
				DMEMIT(DM_VERITY_OPT_ERROR_PANIC);
				break;
			default:
				DMEMIT("invalid");
			}
		}
		DMEMIT(";");
		break;
	}
@@ -1107,6 +1140,25 @@ static int verity_parse_verity_mode(struct dm_verity *v, const char *arg_name)
	return 0;
}

static inline bool verity_is_verity_error_mode(const char *arg_name)
{
	return (!strcasecmp(arg_name, DM_VERITY_OPT_ERROR_RESTART) ||
		!strcasecmp(arg_name, DM_VERITY_OPT_ERROR_PANIC));
}

static int verity_parse_verity_error_mode(struct dm_verity *v, const char *arg_name)
{
	if (v->error_mode)
		return -EINVAL;

	if (!strcasecmp(arg_name, DM_VERITY_OPT_ERROR_RESTART))
		v->error_mode = DM_VERITY_MODE_RESTART;
	else if (!strcasecmp(arg_name, DM_VERITY_OPT_ERROR_PANIC))
		v->error_mode = DM_VERITY_MODE_PANIC;

	return 0;
}

static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
				 struct dm_verity_sig_opts *verify_args,
				 bool only_modifier_opts)
@@ -1141,6 +1193,16 @@ static int verity_parse_opt_args(struct dm_arg_set *as, struct dm_verity *v,
			}
			continue;

		} else if (verity_is_verity_error_mode(arg_name)) {
			if (only_modifier_opts)
				continue;
			r = verity_parse_verity_error_mode(v, arg_name);
			if (r) {
				ti->error = "Conflicting error handling parameters";
				return r;
			}
			continue;

		} else if (!strcasecmp(arg_name, DM_VERITY_OPT_IGN_ZEROES)) {
			if (only_modifier_opts)
				continue;
+1 −0
Original line number Diff line number Diff line
@@ -64,6 +64,7 @@ struct dm_verity {
	unsigned int digest_size;	/* digest size for the current hash algorithm */
	unsigned int hash_reqsize; /* the size of temporary space for crypto */
	enum verity_mode mode;	/* mode for handling verification errors */
	enum verity_mode error_mode;/* mode for handling I/O errors */
	unsigned int corrupted_errs;/* Number of errors for corrupted blocks */

	struct workqueue_struct *verify_wq;