mirror of https://github.com/torvalds/linux.git
block: Introduce bio_needs_zone_write_plugging()
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>
This commit is contained in:
parent
3f66ccbaae
commit
f70291411b
|
|
@ -3169,8 +3169,10 @@ void blk_mq_submit_bio(struct bio *bio)
|
||||||
if (blk_mq_attempt_bio_merge(q, bio, nr_segs))
|
if (blk_mq_attempt_bio_merge(q, bio, nr_segs))
|
||||||
goto queue_exit;
|
goto queue_exit;
|
||||||
|
|
||||||
if (blk_queue_is_zoned(q) && blk_zone_plug_bio(bio, nr_segs))
|
if (bio_needs_zone_write_plugging(bio)) {
|
||||||
goto queue_exit;
|
if (blk_zone_plug_bio(bio, nr_segs))
|
||||||
|
goto queue_exit;
|
||||||
|
}
|
||||||
|
|
||||||
new_request:
|
new_request:
|
||||||
if (rq) {
|
if (rq) {
|
||||||
|
|
|
||||||
|
|
@ -1116,25 +1116,7 @@ bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs)
|
||||||
{
|
{
|
||||||
struct block_device *bdev = bio->bi_bdev;
|
struct block_device *bdev = bio->bi_bdev;
|
||||||
|
|
||||||
if (!bdev->bd_disk->zone_wplugs_hash)
|
if (WARN_ON_ONCE(!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))
|
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -1788,7 +1788,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)
|
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,
|
static blk_status_t __send_zone_reset_all_emulated(struct clone_info *ci,
|
||||||
|
|
|
||||||
|
|
@ -837,6 +837,55 @@ static inline unsigned int disk_nr_zones(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
return disk->nr_zones;
|
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);
|
bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -866,6 +915,12 @@ static inline unsigned int disk_nr_zones(struct gendisk *disk)
|
||||||
{
|
{
|
||||||
return 0;
|
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)
|
static inline bool blk_zone_plug_bio(struct bio *bio, unsigned int nr_segs)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue