]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
block: don't leak disk->zones_cond for !disk_need_zone_resources
authorChristoph Hellwig <hch@lst.de>
Wed, 5 Nov 2025 19:52:14 +0000 (14:52 -0500)
committerJens Axboe <axboe@kernel.dk>
Thu, 6 Nov 2025 23:15:27 +0000 (16:15 -0700)
disk->zones_cond is allocated for all zoned devices, but
disk_free_zone_resources skips it when the zone write plug hash is not
allocated, leaking the allocation for non-mq devices that don't emulate
zone append.  This is reported by kmemleak-enabled xfstests for various
tests that use simple device mapper targets.

Fix this by moving all code that requires writes plugs from
disk_free_zone_resources into disk_destroy_zone_wplugs_hash_table
and executing the rest of the code, including the disk->zones_cond
freeing unconditionally.

Fixes: 6e945ffb6555 ("block: use zone condition to determine conventional zones")
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
block/blk-zoned.c

index bba64b42708260c745fea10bdf00e7776ef3eaf1..a0ce17e2143f4a40c569b0ca3dc60f09d2d633a2 100644 (file)
@@ -1834,6 +1834,14 @@ static void disk_destroy_zone_wplugs_hash_table(struct gendisk *disk)
        kfree(disk->zone_wplugs_hash);
        disk->zone_wplugs_hash = NULL;
        disk->zone_wplugs_hash_bits = 0;
+
+       /*
+        * Wait for the zone write plugs to be RCU-freed before destroying the
+        * mempool.
+        */
+       rcu_barrier();
+       mempool_destroy(disk->zone_wplugs_pool);
+       disk->zone_wplugs_pool = NULL;
 }
 
 static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond)
@@ -1850,9 +1858,6 @@ static void disk_set_zones_cond_array(struct gendisk *disk, u8 *zones_cond)
 
 void disk_free_zone_resources(struct gendisk *disk)
 {
-       if (!disk->zone_wplugs_pool)
-               return;
-
        if (disk->zone_wplugs_wq) {
                destroy_workqueue(disk->zone_wplugs_wq);
                disk->zone_wplugs_wq = NULL;
@@ -1860,15 +1865,6 @@ void disk_free_zone_resources(struct gendisk *disk)
 
        disk_destroy_zone_wplugs_hash_table(disk);
 
-       /*
-        * Wait for the zone write plugs to be RCU-freed before
-        * destorying the mempool.
-        */
-       rcu_barrier();
-
-       mempool_destroy(disk->zone_wplugs_pool);
-       disk->zone_wplugs_pool = NULL;
-
        disk_set_zones_cond_array(disk, NULL);
        disk->zone_capacity = 0;
        disk->last_zone_capacity = 0;