Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

block: fix zone write plugs refcount handling in disk_zone_wplug_schedule_bio_work()

The function disk_zone_wplug_schedule_bio_work() always takes a
reference on the zone write plug of the BIO work being scheduled. This
ensures that the zone write plug cannot be freed while the BIO work is
being scheduled but has not run yet. However, this unconditional
reference taking is fragile since the reference taken is released by the
BIO work blk_zone_wplug_bio_work() function, which implies that there
always must be a 1:1 relation between the work being scheduled and the
work running.

Make sure to drop the reference taken when scheduling the BIO work if
the work is already scheduled, that is, when queue_work() returns false.

Fixes: 9e78c38ab30b ("block: Hold a reference on zone write plugs to schedule submission")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Damien Le Moal and committed by
Jens Axboe
0a8b8af8 b7d4ffb5

+8 -4
+8 -4
block/blk-zoned.c
··· 1154 1154 lockdep_assert_held(&zwplug->lock); 1155 1155 1156 1156 /* 1157 - * Take a reference on the zone write plug and schedule the submission 1158 - * of the next plugged BIO. blk_zone_wplug_bio_work() will release the 1159 - * reference we take here. 1157 + * Schedule the submission of the next plugged BIO. Taking a reference 1158 + * to the zone write plug is required as the bio_work belongs to the 1159 + * plug, and thus we must ensure that the write plug does not go away 1160 + * while the work is being scheduled but has not run yet. 1161 + * blk_zone_wplug_bio_work() will release the reference we take here, 1162 + * and we also drop this reference if the work is already scheduled. 1160 1163 */ 1161 1164 WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED)); 1162 1165 refcount_inc(&zwplug->ref); 1163 - queue_work(disk->zone_wplugs_wq, &zwplug->bio_work); 1166 + if (!queue_work(disk->zone_wplugs_wq, &zwplug->bio_work)) 1167 + disk_put_zone_wplug(zwplug); 1164 1168 } 1165 1169 1166 1170 static inline void disk_zone_wplug_add_bio(struct gendisk *disk,