summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Le Moal <dlemoal@kernel.org>2025-11-13 22:40:26 +0900
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-01-08 10:15:06 +0100
commitc8cdc025a6d24e83807a1acd84fa3860f3eaded3 (patch)
tree1ed376c676b97de33926249e3cc7555e549d1970
parent51297686e00f4d5d941b0f20f12b2f12879d753c (diff)
downloadlinux-c8cdc025a6d24e83807a1acd84fa3860f3eaded3.tar.gz
linux-c8cdc025a6d24e83807a1acd84fa3860f3eaded3.tar.bz2
linux-c8cdc025a6d24e83807a1acd84fa3860f3eaded3.zip
block: fix NULL pointer dereference in blk_zone_reset_all_bio_endio()
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>
-rw-r--r--block/blk-zoned.c21
1 files changed, 12 insertions, 9 deletions
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index e29e41f86c4a..7e04ed9b2c0b 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -746,17 +746,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)