Skip to content

Commit 0a8b8af

Browse files
damien-lemoalaxboe
authored andcommitted
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: 9e78c38 ("block: Hold a reference on zone write plugs to schedule submission") Cc: [email protected] Signed-off-by: Damien Le Moal <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Bart Van Assche <[email protected]> Reviewed-by: Johannes Thumshirn <[email protected]> Signed-off-by: Jens Axboe <[email protected]>
1 parent b7d4ffb commit 0a8b8af

1 file changed

Lines changed: 8 additions & 4 deletions

File tree

block/blk-zoned.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1154,13 +1154,17 @@ static void disk_zone_wplug_schedule_bio_work(struct gendisk *disk,
11541154
lockdep_assert_held(&zwplug->lock);
11551155

11561156
/*
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.
11601163
*/
11611164
WARN_ON_ONCE(!(zwplug->flags & BLK_ZONE_WPLUG_PLUGGED));
11621165
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);
11641168
}
11651169

11661170
static inline void disk_zone_wplug_add_bio(struct gendisk *disk,

0 commit comments

Comments
 (0)