diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c index 80a43954325966a872cf8ebc95fb23c92c0b8819..4763c4ae30e434e181b7f91838309c75c2126952 100644 --- a/drivers/md/dm-ioctl.c +++ b/drivers/md/dm-ioctl.c @@ -1291,7 +1291,8 @@ static int table_load(struct dm_ioctl *param, size_t param_size) immutable_target_type = dm_get_immutable_target_type(md); if (immutable_target_type && - (immutable_target_type != dm_table_get_immutable_target_type(t))) { + (immutable_target_type != dm_table_get_immutable_target_type(t)) && + !dm_table_get_wildcard_target(t)) { DMWARN("can't replace immutable target type %s", immutable_target_type->name); r = -EINVAL; diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c index 061152a437300bbfacfbbc6e475c3935df7cecb6..a49e62b8611f2ed11bde45153b158d766534531f 100644 --- a/drivers/md/dm-table.c +++ b/drivers/md/dm-table.c @@ -920,6 +920,20 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t) return t->immutable_target_type; } +struct dm_target *dm_table_get_wildcard_target(struct dm_table *t) +{ + struct dm_target *uninitialized_var(ti); + unsigned i = 0; + + while (i < dm_table_get_num_targets(t)) { + ti = dm_table_get_target(t, i++); + if (dm_target_is_wildcard(ti->type)) + return ti; + } + + return NULL; +} + bool dm_table_request_based(struct dm_table *t) { return __table_type_request_based(dm_table_get_type(t)); diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c index 925ec1b15e75ede24ea91c74667d426950af251e..a317dd884ba6b5aca1b1355e7537b28bfa5c1bd4 100644 --- a/drivers/md/dm-target.c +++ b/drivers/md/dm-target.c @@ -150,7 +150,8 @@ static void io_err_release_clone_rq(struct request *clone) static struct target_type error_target = { .name = "error", - .version = {1, 3, 0}, + .version = {1, 4, 0}, + .features = DM_TARGET_WILDCARD, .ctr = io_err_ctr, .dtr = io_err_dtr, .map = io_err_map, diff --git a/drivers/md/dm.h b/drivers/md/dm.h index 7edcf97dfa5a66fc93b964c4f16671d72a17e5a8..53df2585571bac681caaa0c0d7e052db92cb32c3 100644 --- a/drivers/md/dm.h +++ b/drivers/md/dm.h @@ -73,6 +73,7 @@ int dm_table_resume_targets(struct dm_table *t); int dm_table_any_congested(struct dm_table *t, int bdi_bits); unsigned dm_table_get_type(struct dm_table *t); struct target_type *dm_table_get_immutable_target_type(struct dm_table *t); +struct dm_target *dm_table_get_wildcard_target(struct dm_table *t); bool dm_table_request_based(struct dm_table *t); bool dm_table_mq_request_based(struct dm_table *t); void dm_table_free_md_mempools(struct dm_table *t); diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h index ec1c61c87d8974897af2be54af23588f14746777..87d50ecbc9df1aa317c95cdd12339152d49fc4fe 100644 --- a/include/linux/device-mapper.h +++ b/include/linux/device-mapper.h @@ -189,6 +189,13 @@ struct target_type { #define DM_TARGET_IMMUTABLE 0x00000004 #define dm_target_is_immutable(type) ((type)->features & DM_TARGET_IMMUTABLE) +/* + * Indicates that a target may replace any target; even immutable targets. + * .map, .map_rq, .clone_and_map_rq and .release_clone_rq are all defined. + */ +#define DM_TARGET_WILDCARD 0x00000008 +#define dm_target_is_wildcard(type) ((type)->features & DM_TARGET_WILDCARD) + /* * Some targets need to be sent the same WRITE bio severals times so * that they can send copies of it to different devices. This function