From: Josef Bacik <josef@toxicpanda.com>
The issuer of a plugged zone write hears about the completion in
bio_endio(), before blk_zone_write_plug_finish_request() unplugs the
zone, and may reset the zone and write it again in between. Since commit
836efd35c472 that revives the plug the reset marked dead, with the new
BIO on the list and wp_offset still 0. The unplug of the first write
then sees an empty zone and marks the plug dead again, BIO and all. Once
that BIO is done the plug is freed and the write pointer offset is lost.
Only remove the plug of an empty zone when no BIO is left on it.
Fixes: 836efd35c472 ("block: fix handling of dead zone write plugs")
Cc: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>
---
block/blk-zoned.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/block/blk-zoned.c b/block/blk-zoned.c
index 4c5889296191..18c05e2a1746 100644
--- a/block/blk-zoned.c
+++ b/block/blk-zoned.c
@@ -1812,7 +1812,14 @@ static void disk_zone_wplug_unplug_bio(struct gendisk *disk,
else if (!bio_list_empty(&zwplug->bio_list))
disk_zone_wplug_schedule_work(disk, zwplug);
- if (!zwplug->wp_offset || disk_zone_wplug_is_full(disk, zwplug))
+ /*
+ * The issuer of the write was told about its completion before we got
+ * here. It may already have reset the zone and started to write it
+ * again, in which case the zone is empty but has BIOs plugged. The plug
+ * must stay alive to track them.
+ */
+ if ((!zwplug->wp_offset && bio_list_empty(&zwplug->bio_list)) ||
+ disk_zone_wplug_is_full(disk, zwplug))
disk_mark_zone_wplug_dead(zwplug);
spin_unlock_irqrestore(&zwplug->lock, flags);
--
2.56.0