dm: don't change md if dm_table_set_restrictions() fails
[ Upstream commit 9eb7109a5bfc5b8226e9517e9f3cc6d414391884 ]
__bind was changing the disk capacity, geometry and mempools of the
mapped device before calling dm_table_set_restrictions() which could
fail, forcing dm to drop the new table. Failing here would leave the
device using the old table but with the wrong capacity and mempools.
Move dm_table_set_restrictions() earlier in __bind(). Since it needs the
capacity to be set, save the old version and restore it on failure.
Fixes: bb37d77239
("dm: introduce zone append emulation")
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Tested-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Benjamin Marzinski <bmarzins@redhat.com>
Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
e431cc956d
commit
679d40ca03
@@ -2195,21 +2195,29 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
|
|||||||
struct queue_limits *limits)
|
struct queue_limits *limits)
|
||||||
{
|
{
|
||||||
struct dm_table *old_map;
|
struct dm_table *old_map;
|
||||||
sector_t size;
|
sector_t size, old_size;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
lockdep_assert_held(&md->suspend_lock);
|
lockdep_assert_held(&md->suspend_lock);
|
||||||
|
|
||||||
size = dm_table_get_size(t);
|
size = dm_table_get_size(t);
|
||||||
|
|
||||||
|
old_size = dm_get_size(md);
|
||||||
|
set_capacity(md->disk, size);
|
||||||
|
|
||||||
|
ret = dm_table_set_restrictions(t, md->queue, limits);
|
||||||
|
if (ret) {
|
||||||
|
set_capacity(md->disk, old_size);
|
||||||
|
old_map = ERR_PTR(ret);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Wipe any geometry if the size of the table changed.
|
* Wipe any geometry if the size of the table changed.
|
||||||
*/
|
*/
|
||||||
if (size != dm_get_size(md))
|
if (size != old_size)
|
||||||
memset(&md->geometry, 0, sizeof(md->geometry));
|
memset(&md->geometry, 0, sizeof(md->geometry));
|
||||||
|
|
||||||
set_capacity(md->disk, size);
|
|
||||||
|
|
||||||
dm_table_event_callback(t, event_callback, md);
|
dm_table_event_callback(t, event_callback, md);
|
||||||
|
|
||||||
if (dm_table_request_based(t)) {
|
if (dm_table_request_based(t)) {
|
||||||
@@ -2242,12 +2250,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
|
|||||||
t->mempools = NULL;
|
t->mempools = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = dm_table_set_restrictions(t, md->queue, limits);
|
|
||||||
if (ret) {
|
|
||||||
old_map = ERR_PTR(ret);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
old_map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
|
old_map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
|
||||||
rcu_assign_pointer(md->map, (void *)t);
|
rcu_assign_pointer(md->map, (void *)t);
|
||||||
md->immutable_target_type = dm_table_get_immutable_target_type(t);
|
md->immutable_target_type = dm_table_get_immutable_target_type(t);
|
||||||
|
Reference in New Issue
Block a user