Introduce bdev_zone_is_seq()
Subsystems (2)
Damien Le Moal
maintainerv2 cover Introduce bdev_zone_is_seq()
Allow file systems to safely access a block device gendisk bitmap of conventional zones to determine a zone type by:
1) Patch 1 - changing the gendisk conv_zones_bitmap to be RCU protected
2) Patch 2 - Introducing the helper function bdev_zone_is_seq()
This is in preparation for use in btrfs to remove the btrfs-managed bitmap of conventional zones and in zoned support for xfs.
Changes from v1:
- Use rcu_dereference() in disk_zone_is_conv() (patch 1) and rebase patch 2, as suggested by Christoph.
Damien Le Moal (2):
block: RCU protect disk->conv_zones_bitmap
block: Add a public bdev_zone_is_seq() helper
block/blk-zoned.c | 42 ++++++++++++++++++++++++------------------ include/linux/blkdev.h | 29 ++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 19 deletions(-)
Signature · 1 line
2.47.0
Damien Le Moal
maintainerPATCH v2 1/2 block: RCU protect disk->conv_zones_bitmap
Ensure that a disk revalidation changing the conventional zones bitmap of a disk does not cause invalid memory references when using the disk_zone_is_conv() helper by RCU protecting the disk->conv_zones_bitmap pointer.
disk_zone_is_conv() is modified to operate under the RCU read lock and the function disk_set_conv_zones_bitmap() is added to update a disk conv_zones_bitmap pointer using rcu_replace_pointer() with the disk zone_wplugs_lock spinlock held.
disk_free_zone_resources() is modified to call disk_update_zone_resources() with a NULL bitmap pointer to free the disk conv_zones_bitmap. disk_set_conv_zones_bitmap() is also used in disk_update_zone_resources() to set the new (revalidated) bitmap and free the old one.
--- block/blk-zoned.c | 43 ++++++++++++++++++++++++++++++------------ include/linux/blkdev.h | 2 +- 2 files changed, 32 insertions(+), 13 deletions(-)
block/blk-zoned.c +31 -12
@@ -350,9 +350,15 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,static inline bool disk_zone_is_conv (struct gendisk *disk,sector_t sector) { -if (!disk->conv_zones_bitmap) -return false; -return test_bit (disk_zone_no (disk, sector), disk->conv_zones_bitmap); +unsigned long *bitmap; +bool is_conv; + +rcu_read_lock (); + bitmap =rcu_dereference (disk->conv_zones_bitmap); + is_conv = bitmap &&test_bit (disk_zone_no (disk, sector), bitmap); +rcu_read_unlock (); + +return is_conv; }static bool disk_zone_is_last (struct gendisk *disk,struct blk_zone *zone)
@@ -1455,6 +1461,24 @@ static void disk_destroy_zone_wplugs_hash_table(struct gendisk *disk) disk->zone_wplugs_hash_bits =0 ; } +static unsigned int disk_set_conv_zones_bitmap (struct gendisk *disk, +unsigned long *bitmap) +{ +unsigned int nr_conv_zones =0 ; +unsigned long flags; + +spin_lock_irqsave (&disk->zone_wplugs_lock, flags); +if (bitmap) + nr_conv_zones =bitmap_weight (bitmap, disk->nr_zones); + bitmap =rcu_replace_pointer (disk->conv_zones_bitmap, bitmap, +lockdep_is_held (&disk->zone_wplugs_lock)); +spin_unlock_irqrestore (&disk->zone_wplugs_lock, flags); + +kfree_rcu_mightsleep (bitmap); + +return nr_conv_zones; +} +void disk_free_zone_resources (struct gendisk *disk) {if (!disk->zone_wplugs_pool)
@@ -1478,8 +1502,7 @@ void disk_free_zone_resources(struct gendisk *disk)mempool_destroy (disk->zone_wplugs_pool); disk->zone_wplugs_pool =NULL ; -bitmap_free (disk->conv_zones_bitmap); - disk->conv_zones_bitmap =NULL ; +disk_set_conv_zones_bitmap (disk,NULL ); disk->zone_capacity =0 ; disk->last_zone_capacity =0 ; disk->nr_zones =0 ;
@@ -1538,17 +1561,15 @@ static int disk_update_zone_resources(struct gendisk *disk, struct blk_revalidate_zone_args *args) {struct request_queue *q = disk->queue; -unsigned int nr_seq_zones, nr_conv_zones =0 ; +unsigned int nr_seq_zones, nr_conv_zones;unsigned int pool_size;struct queue_limits lim; disk->nr_zones = args->nr_zones; disk->zone_capacity = args->zone_capacity; disk->last_zone_capacity = args->last_zone_capacity; -swap (disk->conv_zones_bitmap, args->conv_zones_bitmap); -if (disk->conv_zones_bitmap) - nr_conv_zones =bitmap_weight (disk->conv_zones_bitmap, - disk->nr_zones); + nr_conv_zones = +disk_set_conv_zones_bitmap (disk, args->conv_zones_bitmap);if (nr_conv_zones >= disk->nr_zones) {pr_warn ("%s: Invalid number of conventional zones %u / %u\n" , disk->disk_name, nr_conv_zones, disk->nr_zones);
@@ -1817,8 +1838,6 @@ int blk_revalidate_disk_zones(struct gendisk *disk)disk_free_zone_resources (disk);blk_mq_unfreeze_queue (q); -kfree (args.conv_zones_bitmap); -return ret; }EXPORT_SYMBOL_GPL (blk_revalidate_disk_zones);
include/linux/blkdev.h +1 -1
@@ -195,7 +195,7 @@ struct gendisk {unsigned int nr_zones;unsigned int zone_capacity;unsigned int last_zone_capacity; -unsigned long *conv_zones_bitmap; +unsigned long __rcu *conv_zones_bitmap;unsigned int zone_wplugs_hash_bits;spinlock_t zone_wplugs_lock;struct mempool_s *zone_wplugs_pool;
Signature · 1 line
2.47.0
Re: [PATCH v2 1/2] block: RCU protect disk->conv_zones_bitmap
Looks good:
Damien Le Moal
maintainerPATCH v2 2/2 block: Add a public bdev_zone_is_seq() helper
In reply to Damien Le MoalTurn the private disk_zone_is_conv() function in blk-zoned.c into a public and documented bdev_zone_is_seq() helper with the inverse polarity of the original function, also adding a check for non-zoned devices so that all file systems can use the helper, even with a regular block device.
--- block/blk-zoned.c | 17 ++--------------- include/linux/blkdev.h | 27 +++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 15 deletions(-)
block/blk-zoned.c +2 -15
@@ -348,19 +348,6 @@ int blkdev_zone_mgmt_ioctl(struct block_device *bdev, blk_mode_t mode,return ret; } -static inline bool disk_zone_is_conv (struct gendisk *disk,sector_t sector) -{ -unsigned long *bitmap; -bool is_conv; - -rcu_read_lock (); - bitmap =rcu_dereference (disk->conv_zones_bitmap); - is_conv = bitmap &&test_bit (disk_zone_no (disk, sector), bitmap); -rcu_read_unlock (); - -return is_conv; -} -static bool disk_zone_is_last (struct gendisk *disk,struct blk_zone *zone) {return zone->start + zone->len >=get_capacity (disk);
@@ -715,7 +702,7 @@ static bool blk_zone_wplug_handle_reset_or_finish(struct bio *bio,struct blk_zone_wplug *zwplug;/* Conventional zones cannot be reset nor finished. */ -if (disk_zone_is_conv (disk, sector)) { +if (!bdev_zone_is_seq (bio->bi_bdev, sector)) {bio_io_error (bio);return true; }
@@ -969,7 +956,7 @@ static bool blk_zone_wplug_handle_write(struct bio *bio, unsigned int nr_segs) }/* Conventional zones do not need write plugging. */ -if (disk_zone_is_conv (disk, sector)) { +if (!bdev_zone_is_seq (bio->bi_bdev, sector)) {/* Zone append to conventional zones is not allowed. */ if (bio_op (bio) ==REQ_OP_ZONE_APPEND ) {bio_io_error (bio);
include/linux/blkdev.h +27 -0
@@ -1380,6 +1380,33 @@ static inline bool bdev_is_zone_start(struct block_device *bdev,return bdev_offset_from_zone_start (bdev, sector) ==0 ; } +/** +* bdev_zone_is_seq - check if a sector belongs to a sequential write zone +* @bdev: block device to check +* @sector: sector number +* +* Check if @sector on @bdev is contained in a sequential write required zone. +*/ +static inline bool bdev_zone_is_seq (struct block_device *bdev,sector_t sector) +{ +bool is_seq = false; + +#if IS_ENABLED (CONFIG_BLK_DEV_ZONED ) +if (bdev_is_zoned (bdev)) { +struct gendisk *disk = bdev->bd_disk; +unsigned long *bitmap; + +rcu_read_lock (); + bitmap =rcu_dereference (disk->conv_zones_bitmap); + is_seq = !bitmap || + !test_bit (disk_zone_no (disk, sector), bitmap); +rcu_read_unlock (); + } +#endif + +return is_seq; +} +static inline int queue_dma_alignment (const struct request_queue *q) {return q->limits.dma_alignment;
Signature · 1 line
2.47.0
Re: [PATCH v2 2/2] block: Add a public bdev_zone_is_seq() helper
Looks good:
Quoted 9 lines · Damien Le Moal
Allow file systems to safely access a block device gendisk bitmap of conventional zones to determine a zone type by:
1) Patch 1 - changing the gendiskconv_zones_bitmapto be RCU protected
2) Patch 2 - Introducing the helper functionbdev_zone_is_seq()This is in preparation for use in btrfs to remove the btrfs-managed bitmap of conventional zones and in zoned support for xfs.
[...]
Applied, thanks!
[1/2] block: RCU protect disk->conv_zones_bitmap
commit: d7cb6d7414ea1b33536fa6d11805cb8dceec1f97
[2/2] block: Add a public bdev_zone_is_seq() helper
commit: f3d9bf05140dd242cdc33c431489a853f2bc1b67Best regards,
Signature · 1 line
Jens Axboe