block: Introduce bio_needs_zone_write_plugging()

commit f70291411b upstream.

In preparation for fixing device mapper zone write handling, introduce
the inline helper function bio_needs_zone_write_plugging() to test if a
BIO requires handling through zone write plugging using the function
blk_zone_plug_bio(). This function returns true for any write
(op_is_write(bio) == true) operation directed at a zoned block device
using zone write plugging, that is, a block device with a disk that has
a zone write plug hash table.

This helper allows simplifying the check on entry to blk_zone_plug_bio()
and used in to protect calls to it for blk-mq devices and DM devices.

Fixes: f211268ed1 ("dm: Use the block layer zone append emulation")
Cc: stable@vger.kernel.org
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Link: https://lore.kernel.org/r/20250625093327.548866-3-dlemoal@kernel.org
Signed-off-by: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Damien Le Moal 2025-06-25 18:33:24 +09:00 committed by Greg Kroah-Hartman
parent 93795b80af
commit 4b3f4afaea
4 changed files with 63 additions and 22 deletions

View File

@ -3117,8 +3117,10 @@ void blk_mq_submit_bio(struct bio *bio)
if (blk_mq_attempt_bio_merge(q, bio, nr_segs))
goto queue_exit;
if (blk_queue_is_zoned(q) && blk_zone_plug_bio(bio, nr_segs))
goto queue_exit;
if (bio_needs_zone_write_plugging(bio)) {
if (blk_zone_plug_bio(bio, nr_segs))
goto queue_exit;
}
new_request:
if (rq) {

View File

@ -1116,25 +1116,7 @@ bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs)
{
struct block_device *bdev = bio->bi_bdev;
if (!bdev->bd_disk->zone_wplugs_hash)
return false;
/*
* If the BIO already has the plugging flag set, then it was already
* handled through this path and this is a submission from the zone
* plug bio submit work.
*/
if (bio_flagged(bio, BIO_ZONE_WRITE_PLUGGING))
return false;
/*
* We do not need to do anything special for empty flush BIOs, e.g
* BIOs such as issued by blkdev_issue_flush(). The is because it is
* the responsibility of the user to first wait for the completion of
* write operations for flush to have any effect on the persistence of
* the written data.
*/
if (op_is_flush(bio->bi_opf) && !bio_sectors(bio))
if (WARN_ON_ONCE(!bdev->bd_disk->zone_wplugs_hash))
return false;
/*

View File

@ -1802,7 +1802,9 @@ static inline bool dm_zone_bio_needs_split(struct mapped_device *md,
}
static inline bool dm_zone_plug_bio(struct mapped_device *md, struct bio *bio)
{
return dm_emulate_zone_append(md) && blk_zone_plug_bio(bio, 0);
if (!bio_needs_zone_write_plugging(bio))
return false;
return blk_zone_plug_bio(bio, 0);
}
static blk_status_t __send_zone_reset_all_emulated(struct clone_info *ci,

View File

@ -835,6 +835,55 @@ static inline unsigned int disk_nr_zones(struct gendisk *disk)
{
return disk->nr_zones;
}
/**
* bio_needs_zone_write_plugging - Check if a BIO needs to be handled with zone
* write plugging
* @bio: The BIO being submitted
*
* Return true whenever @bio execution needs to be handled through zone
* write plugging (using blk_zone_plug_bio()). Return false otherwise.
*/
static inline bool bio_needs_zone_write_plugging(struct bio *bio)
{
enum req_op op = bio_op(bio);
/*
* Only zoned block devices have a zone write plug hash table. But not
* all of them have one (e.g. DM devices may not need one).
*/
if (!bio->bi_bdev->bd_disk->zone_wplugs_hash)
return false;
/* Only write operations need zone write plugging. */
if (!op_is_write(op))
return false;
/* Ignore empty flush */
if (op_is_flush(bio->bi_opf) && !bio_sectors(bio))
return false;
/* Ignore BIOs that already have been handled by zone write plugging. */
if (bio_flagged(bio, BIO_ZONE_WRITE_PLUGGING))
return false;
/*
* All zone write operations must be handled through zone write plugging
* using blk_zone_plug_bio().
*/
switch (op) {
case REQ_OP_ZONE_APPEND:
case REQ_OP_WRITE:
case REQ_OP_WRITE_ZEROES:
case REQ_OP_ZONE_FINISH:
case REQ_OP_ZONE_RESET:
case REQ_OP_ZONE_RESET_ALL:
return true;
default:
return false;
}
}
bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs);
/**
@ -864,6 +913,12 @@ static inline unsigned int disk_nr_zones(struct gendisk *disk)
{
return 0;
}
static inline bool bio_needs_zone_write_plugging(struct bio *bio)
{
return false;
}
static inline bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs)
{
return false;