dm-verity: introduce the options restart_on_error and panic_on_error
This patch introduces the options restart_on_error and panic_on_error on
dm-verity.
Previously, restarting on error was handled by the patch
e6a3531dd5
, but Google engineers wanted to
have a special option for it.
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Suggested-by: Sami Tolvanen <samitolvanen@google.com>
Suggested-by: Will Drewry <wad@chromium.org>
This commit is contained in:
parent
462763212d
commit
f811b83879
@ -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;
|
||||
@ -583,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.
|
||||
*/
|
||||
@ -597,6 +604,23 @@ static void verity_finish_io(struct dm_verity_io *io, blk_status_t status)
|
||||
if (!static_branch_unlikely(&use_bh_wq_enabled) || !io->in_bh)
|
||||
verity_fec_finish_io(io);
|
||||
|
||||
if (unlikely(status != BLK_STS_OK) &&
|
||||
unlikely(!(bio->bi_opf & REQ_RAHEAD)) &&
|
||||
!verity_is_system_shutting_down()) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
bio_endio(bio);
|
||||
}
|
||||
|
||||
@ -805,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)
|
||||
@ -834,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)
|
||||
@ -886,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;
|
||||
}
|
||||
@ -1088,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)
|
||||
@ -1122,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;
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user