]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
block: fix NULL pointer dereference in blk_zone_reset_all_bio_endio()
authorDamien Le Moal <dlemoal@kernel.org>
Thu, 13 Nov 2025 13:40:26 +0000 (22:40 +0900)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 8 Jan 2026 09:17:21 +0000 (10:17 +0100)
commit c2b8d20628ca789640f64074a642f9440eefc623 upstream.

For zoned block devices that do not need zone write plugs (e.g. most
device mapper devices that support zones), the disk hash table of zone
write plugs is NULL. For such devices, blk_zone_reset_all_bio_endio()
should not attempt to scan this has table as that causes a NULL pointer
dereference.

Fix this by checking that the disk does have zone write plugs using the
atomic counter. This is equivalent to checking for a non-NULL hash table
but has the advantage to also speed up the execution of
blk_zone_reset_all_bio_endio() for devices that do use zone write plugs
but do not have any plug in the hash table (e.g. a disk with only full
zones).

Fixes: efae226c2ef1 ("block: handle zone management operations completions")
Reported-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
block/blk-zoned.c

index 3a3cbee60591b5852e9b6d9f6d02bdbe3891035a..0c812f3bd7df38c296d93ccd561dc8d3939936d6 100644 (file)
@@ -736,17 +736,20 @@ static void blk_zone_reset_all_bio_endio(struct bio *bio)
        unsigned long flags;
        unsigned int i;
 
-       /* Update the condition of all zone write plugs. */
-       rcu_read_lock();
-       for (i = 0; i < disk_zone_wplugs_hash_size(disk); i++) {
-               hlist_for_each_entry_rcu(zwplug, &disk->zone_wplugs_hash[i],
-                                        node) {
-                       spin_lock_irqsave(&zwplug->lock, flags);
-                       disk_zone_wplug_set_wp_offset(disk, zwplug, 0);
-                       spin_unlock_irqrestore(&zwplug->lock, flags);
+       if (atomic_read(&disk->nr_zone_wplugs)) {
+               /* Update the condition of all zone write plugs. */
+               rcu_read_lock();
+               for (i = 0; i < disk_zone_wplugs_hash_size(disk); i++) {
+                       hlist_for_each_entry_rcu(zwplug,
+                                                &disk->zone_wplugs_hash[i],
+                                                node) {
+                               spin_lock_irqsave(&zwplug->lock, flags);
+                               disk_zone_wplug_set_wp_offset(disk, zwplug, 0);
+                               spin_unlock_irqrestore(&zwplug->lock, flags);
+                       }
                }
+               rcu_read_unlock();
        }
-       rcu_read_unlock();
 }
 
 static void blk_zone_finish_bio_endio(struct bio *bio)