]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
dm: don't change md if dm_table_set_restrictions() fails
authorBenjamin Marzinski <bmarzins@redhat.com>
Thu, 10 Apr 2025 19:49:38 +0000 (15:49 -0400)
committerMikulas Patocka <mpatocka@redhat.com>
Fri, 11 Apr 2025 11:38:39 +0000 (13:38 +0200)
__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: bb37d77239af2 ("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>
drivers/md/dm.c

index 5ab7574c0c76ab939af1ed919c38da396b599c49..f5c5ccb6f8d25a37497981f3c9dea918094d2c9c 100644 (file)
@@ -2421,21 +2421,29 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
                               struct queue_limits *limits)
 {
        struct dm_table *old_map;
-       sector_t size;
+       sector_t size, old_size;
        int ret;
 
        lockdep_assert_held(&md->suspend_lock);
 
        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.
         */
-       if (size != dm_get_size(md))
+       if (size != old_size)
                memset(&md->geometry, 0, sizeof(md->geometry));
 
-       set_capacity(md->disk, size);
-
        dm_table_event_callback(t, event_callback, md);
 
        if (dm_table_request_based(t)) {
@@ -2468,12 +2476,6 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
                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));
        rcu_assign_pointer(md->map, (void *)t);
        md->immutable_target_type = dm_table_get_immutable_target_type(t);