FROMGIT: 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>
Bug: 417517944
Change-Id: I9628b14d4fe0e1f964d4036178fbc6ee49b3be78
(cherry picked from commit bf7a8b5cbbb2d531f3336be2186af0c5590d157c git://git.kernel.dk/linux-block for-next)
Signed-off-by: Bart Van Assche <bvanassche@google.com>
This commit is contained in:
committed by
Bart Van Assche
parent
5aca882326
commit
5d1966b61d
+4
-2
@@ -3139,8 +3139,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) {
|
||||||
|
|||||||
+1
-19
@@ -1128,25 +1128,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;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
+3
-1
@@ -1796,7 +1796,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,
|
||||||
|
|||||||
@@ -840,6 +840,61 @@ static inline u64 sb_bdev_nr_blocks(struct super_block *sb)
|
|||||||
(sb->s_blocksize_bits - SECTOR_SHIFT);
|
(sb->s_blocksize_bits - SECTOR_SHIFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_BLK_DEV_ZONED
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else /* CONFIG_BLK_DEV_ZONED */
|
||||||
|
static inline bool bio_needs_zone_write_plugging(struct bio *bio)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int bdev_disk_changed(struct gendisk *disk, bool invalidate);
|
int bdev_disk_changed(struct gendisk *disk, bool invalidate);
|
||||||
|
|
||||||
void put_disk(struct gendisk *disk);
|
void put_disk(struct gendisk *disk);
|
||||||
|
|||||||
Reference in New Issue
Block a user