From e76239a3748c90a8b0e197f8f4544a8ce52f126e Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Fri, 12 Oct 2018 19:08:49 +0900 Subject: block: add a report_zones method Dispatching a report zones command through the request queue is a major pain due to the command reply payload rewriting necessary. Given that blkdev_report_zones() is executing everything synchronously, implement report zones as a block device file operation instead, allowing major simplification of the code in many places. sd, null-blk, dm-linear and dm-flakey being the only block device drivers supporting exposing zoned block devices, these drivers are modified to provide the device side implementation of the report_zones() block device file operation. For device mappers, a new report_zones() target type operation is defined so that the upper block layer calls blkdev_report_zones() can be propagated down to the underlying devices of the dm targets. Implementation for this new operation is added to the dm-linear and dm-flakey targets. Reviewed-by: Hannes Reinecke Signed-off-by: Christoph Hellwig [Damien] * Changed method block_device argument to gendisk * Various bug fixes and improvements * Added support for null_blk, dm-linear and dm-flakey. Reviewed-by: Martin K. Petersen Reviewed-by: Mike Snitzer Signed-off-by: Damien Le Moal Signed-off-by: Jens Axboe --- drivers/block/null_blk_zoned.c | 57 +++++++++++------------------------------- 1 file changed, 15 insertions(+), 42 deletions(-) (limited to 'drivers/block/null_blk_zoned.c') diff --git a/drivers/block/null_blk_zoned.c b/drivers/block/null_blk_zoned.c index 7c6b86d98700..c0b0e4a3fa8f 100644 --- a/drivers/block/null_blk_zoned.c +++ b/drivers/block/null_blk_zoned.c @@ -48,54 +48,27 @@ void null_zone_exit(struct nullb_device *dev) kvfree(dev->zones); } -static void null_zone_fill_bio(struct nullb_device *dev, struct bio *bio, - unsigned int zno, unsigned int nr_zones) +int null_zone_report(struct gendisk *disk, sector_t sector, + struct blk_zone *zones, unsigned int *nr_zones, + gfp_t gfp_mask) { - struct blk_zone_report_hdr *hdr = NULL; - struct bio_vec bvec; - struct bvec_iter iter; - void *addr; - unsigned int zones_to_cpy; - - bio_for_each_segment(bvec, bio, iter) { - addr = kmap_atomic(bvec.bv_page); - - zones_to_cpy = bvec.bv_len / sizeof(struct blk_zone); - - if (!hdr) { - hdr = (struct blk_zone_report_hdr *)addr; - hdr->nr_zones = nr_zones; - zones_to_cpy--; - addr += sizeof(struct blk_zone_report_hdr); - } - - zones_to_cpy = min_t(unsigned int, zones_to_cpy, nr_zones); - - memcpy(addr, &dev->zones[zno], - zones_to_cpy * sizeof(struct blk_zone)); - - kunmap_atomic(addr); + struct nullb *nullb = disk->private_data; + struct nullb_device *dev = nullb->dev; + unsigned int zno, nrz = 0; - nr_zones -= zones_to_cpy; - zno += zones_to_cpy; + if (!dev->zoned) + /* Not a zoned null device */ + return -EOPNOTSUPP; - if (!nr_zones) - break; + zno = null_zone_no(dev, sector); + if (zno < dev->nr_zones) { + nrz = min_t(unsigned int, *nr_zones, dev->nr_zones - zno); + memcpy(zones, &dev->zones[zno], nrz * sizeof(struct blk_zone)); } -} -blk_status_t null_zone_report(struct nullb *nullb, struct bio *bio) -{ - struct nullb_device *dev = nullb->dev; - unsigned int zno = null_zone_no(dev, bio->bi_iter.bi_sector); - unsigned int nr_zones = dev->nr_zones - zno; - unsigned int max_zones; + *nr_zones = nrz; - max_zones = (bio->bi_iter.bi_size / sizeof(struct blk_zone)) - 1; - nr_zones = min_t(unsigned int, nr_zones, max_zones); - null_zone_fill_bio(nullb->dev, bio, zno, nr_zones); - - return BLK_STS_OK; + return 0; } void null_zone_write(struct nullb_cmd *cmd, sector_t sector, -- cgit