Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

block: introduce disk_report_zone()

Commit b76b840fd933 ("dm: Fix dm-zoned-reclaim zone write pointer
alignment") introduced an indirect call for the callback function of a
report zones executed with blkdev_report_zones(). This is necessary so
that the function disk_zone_wplug_sync_wp_offset() can be called to
refresh a zone write plug zone write pointer offset after a write error.
However, this solution makes following the path of a zone information
harder to understand.

Clean this up by introducing the new blk_report_zones_args structure to
define a zone report callback and its private data and introduce the
helper function disk_report_zone() which calls both
disk_zone_wplug_sync_wp_offset() and the zone report user callback
function for all zones of a zone report. This helper function must be
called by all block device drivers that implement the report zones
block operation in order to correctly report a zone information.

All block device drivers supporting the report_zones block operation are
updated to use this new scheme.

Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Johannes Thumshirn <johannes.thumshirn@wdc.com>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: Jens Axboe <axboe@kernel.dk>

authored by

Damien Le Moal and committed by
Jens Axboe
fdb9aed8 e8ecb21f

+120 -102
+42 -37
block/blk-zoned.c
··· 114 114 } 115 115 EXPORT_SYMBOL_GPL(blk_zone_cond_str); 116 116 117 - struct disk_report_zones_cb_args { 118 - struct gendisk *disk; 119 - report_zones_cb user_cb; 120 - void *user_data; 117 + /* 118 + * Zone report arguments for block device drivers report_zones operation. 119 + * @cb: report_zones_cb callback for each reported zone. 120 + * @data: Private data passed to report_zones_cb. 121 + */ 122 + struct blk_report_zones_args { 123 + report_zones_cb cb; 124 + void *data; 121 125 }; 122 - 123 - static void disk_zone_wplug_sync_wp_offset(struct gendisk *disk, 124 - struct blk_zone *zone); 125 - 126 - static int disk_report_zones_cb(struct blk_zone *zone, unsigned int idx, 127 - void *data) 128 - { 129 - struct disk_report_zones_cb_args *args = data; 130 - struct gendisk *disk = args->disk; 131 - 132 - if (disk->zone_wplugs_hash) 133 - disk_zone_wplug_sync_wp_offset(disk, zone); 134 - 135 - if (!args->user_cb) 136 - return 0; 137 - 138 - return args->user_cb(zone, idx, args->user_data); 139 - } 140 126 141 127 /** 142 128 * blkdev_report_zones - Get zones information ··· 147 161 unsigned int nr_zones, report_zones_cb cb, void *data) 148 162 { 149 163 struct gendisk *disk = bdev->bd_disk; 150 - struct disk_report_zones_cb_args args = { 151 - .disk = disk, 152 - .user_cb = cb, 153 - .user_data = data, 164 + struct blk_report_zones_args args = { 165 + .cb = cb, 166 + .data = data, 154 167 }; 155 168 156 169 if (!bdev_is_zoned(bdev) || WARN_ON_ONCE(!disk->fops->report_zones)) ··· 158 173 if (!nr_zones || sector >= get_capacity(disk)) 159 174 return 0; 160 175 161 - return disk->fops->report_zones(disk, sector, nr_zones, 162 - disk_report_zones_cb, &args); 176 + return disk->fops->report_zones(disk, sector, nr_zones, &args); 163 177 } 164 178 EXPORT_SYMBOL_GPL(blkdev_report_zones); 165 179 ··· 676 692 disk_put_zone_wplug(zwplug); 677 693 } 678 694 679 - static int disk_zone_sync_wp_offset(struct gendisk *disk, sector_t sector) 695 + /** 696 + * disk_report_zone - Report one zone 697 + * @disk: Target disk 698 + * @zone: The zone to report 699 + * @idx: The index of the zone in the overall zone report 700 + * @args: report zones callback and data 701 + * 702 + * Description: 703 + * Helper function for block device drivers to report one zone of a zone 704 + * report initiated with blkdev_report_zones(). The zone being reported is 705 + * specified by @zone and used to update, if necessary, the zone write plug 706 + * information for the zone. If @args specifies a user callback function, 707 + * this callback is executed. 708 + */ 709 + int disk_report_zone(struct gendisk *disk, struct blk_zone *zone, 710 + unsigned int idx, struct blk_report_zones_args *args) 680 711 { 681 - struct disk_report_zones_cb_args args = { 682 - .disk = disk, 683 - }; 712 + if (disk->zone_wplugs_hash) 713 + disk_zone_wplug_sync_wp_offset(disk, zone); 684 714 685 - return disk->fops->report_zones(disk, sector, 1, 686 - disk_report_zones_cb, &args); 715 + if (args && args->cb) 716 + return args->cb(zone, idx, args->data); 717 + 718 + return 0; 687 719 } 720 + EXPORT_SYMBOL_GPL(disk_report_zone); 688 721 689 722 static void blk_zone_reset_bio_endio(struct bio *bio) 690 723 { ··· 1787 1786 sector_t capacity = get_capacity(disk); 1788 1787 struct blk_revalidate_zone_args args = { }; 1789 1788 unsigned int memflags, noio_flag; 1789 + struct blk_report_zones_args rep_args = { 1790 + .cb = blk_revalidate_zone_cb, 1791 + .data = &args, 1792 + }; 1790 1793 int ret = -ENOMEM; 1791 1794 1792 1795 if (WARN_ON_ONCE(!blk_queue_is_zoned(q))) ··· 1822 1817 return ret; 1823 1818 } 1824 1819 1825 - ret = disk->fops->report_zones(disk, 0, UINT_MAX, 1826 - blk_revalidate_zone_cb, &args); 1820 + ret = disk->fops->report_zones(disk, 0, UINT_MAX, &rep_args); 1827 1821 if (!ret) { 1828 1822 pr_warn("%s: No zones reported\n", disk->disk_name); 1829 1823 ret = -ENODEV; ··· 1867 1863 int blk_zone_issue_zeroout(struct block_device *bdev, sector_t sector, 1868 1864 sector_t nr_sects, gfp_t gfp_mask) 1869 1865 { 1866 + struct gendisk *disk = bdev->bd_disk; 1870 1867 int ret; 1871 1868 1872 1869 if (WARN_ON_ONCE(!bdev_is_zoned(bdev))) ··· 1883 1878 * pointer. Undo this using a report zone to update the zone write 1884 1879 * pointer to the correct current value. 1885 1880 */ 1886 - ret = disk_zone_sync_wp_offset(bdev->bd_disk, sector); 1881 + ret = disk->fops->report_zones(disk, sector, 1, NULL); 1887 1882 if (ret != 1) 1888 1883 return ret < 0 ? ret : -EIO; 1889 1884
+2 -1
drivers/block/null_blk/null_blk.h
··· 143 143 int null_register_zoned_dev(struct nullb *nullb); 144 144 void null_free_zoned_dev(struct nullb_device *dev); 145 145 int null_report_zones(struct gendisk *disk, sector_t sector, 146 - unsigned int nr_zones, report_zones_cb cb, void *data); 146 + unsigned int nr_zones, 147 + struct blk_report_zones_args *args); 147 148 blk_status_t null_process_zoned_cmd(struct nullb_cmd *cmd, enum req_op op, 148 149 sector_t sector, sector_t nr_sectors); 149 150 size_t null_zone_valid_read_len(struct nullb *nullb,
+2 -2
drivers/block/null_blk/zoned.c
··· 191 191 } 192 192 193 193 int null_report_zones(struct gendisk *disk, sector_t sector, 194 - unsigned int nr_zones, report_zones_cb cb, void *data) 194 + unsigned int nr_zones, struct blk_report_zones_args *args) 195 195 { 196 196 struct nullb *nullb = disk->private_data; 197 197 struct nullb_device *dev = nullb->dev; ··· 225 225 blkz.capacity = zone->capacity; 226 226 null_unlock_zone(dev, zone); 227 227 228 - error = cb(&blkz, i, data); 228 + error = disk_report_zone(disk, &blkz, i, args); 229 229 if (error) 230 230 return error; 231 231 }
+2 -2
drivers/block/ublk_drv.c
··· 367 367 } 368 368 369 369 static int ublk_report_zones(struct gendisk *disk, sector_t sector, 370 - unsigned int nr_zones, report_zones_cb cb, void *data) 370 + unsigned int nr_zones, struct blk_report_zones_args *args) 371 371 { 372 372 struct ublk_device *ub = disk->private_data; 373 373 unsigned int zone_size_sectors = disk->queue->limits.chunk_sectors; ··· 430 430 if (!zone->len) 431 431 break; 432 432 433 - ret = cb(zone, i, data); 433 + ret = disk_report_zone(disk, zone, i, args); 434 434 if (ret) 435 435 goto out; 436 436
+6 -5
drivers/block/virtio_blk.c
··· 584 584 585 585 static int virtblk_parse_zone(struct virtio_blk *vblk, 586 586 struct virtio_blk_zone_descriptor *entry, 587 - unsigned int idx, report_zones_cb cb, void *data) 587 + unsigned int idx, 588 + struct blk_report_zones_args *args) 588 589 { 589 590 struct blk_zone zone = { }; 590 591 ··· 651 650 * The callback below checks the validity of the reported 652 651 * entry data, no need to further validate it here. 653 652 */ 654 - return cb(&zone, idx, data); 653 + return disk_report_zone(vblk->disk, &zone, idx, args); 655 654 } 656 655 657 656 static int virtblk_report_zones(struct gendisk *disk, sector_t sector, 658 - unsigned int nr_zones, report_zones_cb cb, 659 - void *data) 657 + unsigned int nr_zones, 658 + struct blk_report_zones_args *args) 660 659 { 661 660 struct virtio_blk *vblk = disk->private_data; 662 661 struct virtio_blk_zone_report *report; ··· 694 693 695 694 for (i = 0; i < nz && zone_idx < nr_zones; i++) { 696 695 ret = virtblk_parse_zone(vblk, &report->zones[i], 697 - zone_idx, cb, data); 696 + zone_idx, args); 698 697 if (ret) 699 698 goto fail_report; 700 699
+2 -2
drivers/block/zloop.c
··· 647 647 } 648 648 649 649 static int zloop_report_zones(struct gendisk *disk, sector_t sector, 650 - unsigned int nr_zones, report_zones_cb cb, void *data) 650 + unsigned int nr_zones, struct blk_report_zones_args *args) 651 651 { 652 652 struct zloop_device *zlo = disk->private_data; 653 653 struct blk_zone blkz = {}; ··· 687 687 688 688 mutex_unlock(&zone->lock); 689 689 690 - ret = cb(&blkz, i, data); 690 + ret = disk_report_zone(disk, &blkz, i, args); 691 691 if (ret) 692 692 return ret; 693 693 }
+30 -24
drivers/md/dm-zone.c
··· 17 17 * For internal zone reports bypassing the top BIO submission path. 18 18 */ 19 19 static int dm_blk_do_report_zones(struct mapped_device *md, struct dm_table *t, 20 - sector_t sector, unsigned int nr_zones, 21 - report_zones_cb cb, void *data) 20 + unsigned int nr_zones, 21 + struct dm_report_zones_args *args) 22 22 { 23 - struct gendisk *disk = md->disk; 24 - int ret; 25 - struct dm_report_zones_args args = { 26 - .next_sector = sector, 27 - .orig_data = data, 28 - .orig_cb = cb, 29 - }; 30 - 31 23 do { 32 24 struct dm_target *tgt; 25 + int ret; 33 26 34 - tgt = dm_table_find_target(t, args.next_sector); 27 + tgt = dm_table_find_target(t, args->next_sector); 35 28 if (WARN_ON_ONCE(!tgt->type->report_zones)) 36 29 return -EIO; 37 30 38 - args.tgt = tgt; 39 - ret = tgt->type->report_zones(tgt, &args, 40 - nr_zones - args.zone_idx); 31 + args->tgt = tgt; 32 + ret = tgt->type->report_zones(tgt, args, 33 + nr_zones - args->zone_idx); 41 34 if (ret < 0) 42 35 return ret; 43 - } while (args.zone_idx < nr_zones && 44 - args.next_sector < get_capacity(disk)); 36 + } while (args->zone_idx < nr_zones && 37 + args->next_sector < get_capacity(md->disk)); 45 38 46 - return args.zone_idx; 39 + return args->zone_idx; 47 40 } 48 41 49 42 /* ··· 45 52 * generally implemented by targets using dm_report_zones(). 46 53 */ 47 54 int dm_blk_report_zones(struct gendisk *disk, sector_t sector, 48 - unsigned int nr_zones, report_zones_cb cb, void *data) 55 + unsigned int nr_zones, 56 + struct blk_report_zones_args *args) 49 57 { 50 58 struct mapped_device *md = disk->private_data; 51 59 struct dm_table *map; ··· 70 76 map = zone_revalidate_map; 71 77 } 72 78 73 - if (map) 74 - ret = dm_blk_do_report_zones(md, map, sector, nr_zones, cb, 75 - data); 79 + if (map) { 80 + struct dm_report_zones_args dm_args = { 81 + .disk = md->disk, 82 + .next_sector = sector, 83 + .rep_args = args, 84 + }; 85 + ret = dm_blk_do_report_zones(md, map, nr_zones, &dm_args); 86 + } 76 87 77 88 if (put_table) 78 89 dm_put_live_table(md, srcu_idx); ··· 112 113 } 113 114 114 115 args->next_sector = zone->start + zone->len; 115 - return args->orig_cb(zone, args->zone_idx++, args->orig_data); 116 + 117 + return disk_report_zone(args->disk, zone, args->zone_idx++, 118 + args->rep_args); 116 119 } 117 120 118 121 /* ··· 493 492 sector_t sector, unsigned int nr_zones, 494 493 unsigned long *need_reset) 495 494 { 495 + struct dm_report_zones_args args = { 496 + .disk = md->disk, 497 + .next_sector = sector, 498 + .cb = dm_zone_need_reset_cb, 499 + .data = need_reset, 500 + }; 496 501 int ret; 497 502 498 - ret = dm_blk_do_report_zones(md, t, sector, nr_zones, 499 - dm_zone_need_reset_cb, need_reset); 503 + ret = dm_blk_do_report_zones(md, t, nr_zones, &args); 500 504 if (ret != nr_zones) { 501 505 DMERR("Get %s zone reset bitmap failed\n", 502 506 md->disk->disk_name);
+2 -1
drivers/md/dm.h
··· 109 109 void dm_zone_endio(struct dm_io *io, struct bio *clone); 110 110 #ifdef CONFIG_BLK_DEV_ZONED 111 111 int dm_blk_report_zones(struct gendisk *disk, sector_t sector, 112 - unsigned int nr_zones, report_zones_cb cb, void *data); 112 + unsigned int nr_zones, 113 + struct blk_report_zones_args *args); 113 114 bool dm_is_zone_write(struct mapped_device *md, struct bio *bio); 114 115 int dm_zone_get_reset_bitmap(struct mapped_device *md, struct dm_table *t, 115 116 sector_t sector, unsigned int nr_zones,
+2 -3
drivers/nvme/host/core.c
··· 2599 2599 2600 2600 #ifdef CONFIG_BLK_DEV_ZONED 2601 2601 static int nvme_report_zones(struct gendisk *disk, sector_t sector, 2602 - unsigned int nr_zones, report_zones_cb cb, void *data) 2602 + unsigned int nr_zones, struct blk_report_zones_args *args) 2603 2603 { 2604 - return nvme_ns_report_zones(disk->private_data, sector, nr_zones, cb, 2605 - data); 2604 + return nvme_ns_report_zones(disk->private_data, sector, nr_zones, args); 2606 2605 } 2607 2606 #else 2608 2607 #define nvme_report_zones NULL
+2 -2
drivers/nvme/host/multipath.c
··· 576 576 577 577 #ifdef CONFIG_BLK_DEV_ZONED 578 578 static int nvme_ns_head_report_zones(struct gendisk *disk, sector_t sector, 579 - unsigned int nr_zones, report_zones_cb cb, void *data) 579 + unsigned int nr_zones, struct blk_report_zones_args *args) 580 580 { 581 581 struct nvme_ns_head *head = disk->private_data; 582 582 struct nvme_ns *ns; ··· 585 585 srcu_idx = srcu_read_lock(&head->srcu); 586 586 ns = nvme_find_path(head); 587 587 if (ns) 588 - ret = nvme_ns_report_zones(ns, sector, nr_zones, cb, data); 588 + ret = nvme_ns_report_zones(ns, sector, nr_zones, args); 589 589 srcu_read_unlock(&head->srcu, srcu_idx); 590 590 return ret; 591 591 }
+1 -1
drivers/nvme/host/nvme.h
··· 1108 1108 }; 1109 1109 1110 1110 int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector, 1111 - unsigned int nr_zones, report_zones_cb cb, void *data); 1111 + unsigned int nr_zones, struct blk_report_zones_args *args); 1112 1112 int nvme_query_zone_info(struct nvme_ns *ns, unsigned lbaf, 1113 1113 struct nvme_zone_info *zi); 1114 1114 void nvme_update_zone_info(struct nvme_ns *ns, struct queue_limits *lim,
+5 -5
drivers/nvme/host/zns.c
··· 148 148 149 149 static int nvme_zone_parse_entry(struct nvme_ns *ns, 150 150 struct nvme_zone_descriptor *entry, 151 - unsigned int idx, report_zones_cb cb, 152 - void *data) 151 + unsigned int idx, 152 + struct blk_report_zones_args *args) 153 153 { 154 154 struct nvme_ns_head *head = ns->head; 155 155 struct blk_zone zone = { }; ··· 169 169 else 170 170 zone.wp = nvme_lba_to_sect(head, le64_to_cpu(entry->wp)); 171 171 172 - return cb(&zone, idx, data); 172 + return disk_report_zone(ns->disk, &zone, idx, args); 173 173 } 174 174 175 175 int nvme_ns_report_zones(struct nvme_ns *ns, sector_t sector, 176 - unsigned int nr_zones, report_zones_cb cb, void *data) 176 + unsigned int nr_zones, struct blk_report_zones_args *args) 177 177 { 178 178 struct nvme_zone_report *report; 179 179 struct nvme_command c = { }; ··· 213 213 214 214 for (i = 0; i < nz && zone_idx < nr_zones; i++) { 215 215 ret = nvme_zone_parse_entry(ns, &report->entries[i], 216 - zone_idx, cb, data); 216 + zone_idx, args); 217 217 if (ret) 218 218 goto out_free; 219 219 zone_idx++;
+1 -1
drivers/scsi/sd.h
··· 240 240 unsigned int sd_zbc_complete(struct scsi_cmnd *cmd, unsigned int good_bytes, 241 241 struct scsi_sense_hdr *sshdr); 242 242 int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, 243 - unsigned int nr_zones, report_zones_cb cb, void *data); 243 + unsigned int nr_zones, struct blk_report_zones_args *args); 244 244 245 245 #else /* CONFIG_BLK_DEV_ZONED */ 246 246
+7 -13
drivers/scsi/sd_zbc.c
··· 35 35 * @buf: SCSI zone descriptor. 36 36 * @idx: Index of the zone relative to the first zone reported by the current 37 37 * sd_zbc_report_zones() call. 38 - * @cb: Callback function pointer. 39 - * @data: Second argument passed to @cb. 38 + * @args: report zones arguments (callback, etc) 40 39 * 41 40 * Return: Value returned by @cb. 42 41 * ··· 43 44 * call @cb(blk_zone, @data). 44 45 */ 45 46 static int sd_zbc_parse_report(struct scsi_disk *sdkp, const u8 buf[64], 46 - unsigned int idx, report_zones_cb cb, void *data) 47 + unsigned int idx, struct blk_report_zones_args *args) 47 48 { 48 49 struct scsi_device *sdp = sdkp->device; 49 50 struct blk_zone zone = { 0 }; 50 51 sector_t start_lba, gran; 51 - int ret; 52 52 53 53 if (WARN_ON_ONCE(sd_zbc_is_gap_zone(buf))) 54 54 return -EINVAL; ··· 85 87 else 86 88 zone.wp = logical_to_sectors(sdp, get_unaligned_be64(&buf[24])); 87 89 88 - ret = cb(&zone, idx, data); 89 - if (ret) 90 - return ret; 91 - 92 - return 0; 90 + return disk_report_zone(sdkp->disk, &zone, idx, args); 93 91 } 94 92 95 93 /** ··· 211 217 * @disk: Disk to report zones for. 212 218 * @sector: Start sector. 213 219 * @nr_zones: Maximum number of zones to report. 214 - * @cb: Callback function called to report zone information. 215 - * @data: Second argument passed to @cb. 220 + * @args: Callback arguments. 216 221 * 217 222 * Called by the block layer to iterate over zone information. See also the 218 223 * disk->fops->report_zones() calls in block/blk-zoned.c. 219 224 */ 220 225 int sd_zbc_report_zones(struct gendisk *disk, sector_t sector, 221 - unsigned int nr_zones, report_zones_cb cb, void *data) 226 + unsigned int nr_zones, 227 + struct blk_report_zones_args *args) 222 228 { 223 229 struct scsi_disk *sdkp = scsi_disk(disk); 224 230 sector_t lba = sectors_to_logical(sdkp->device, sector); ··· 277 283 } 278 284 279 285 ret = sd_zbc_parse_report(sdkp, buf + offset, zone_idx, 280 - cb, data); 286 + args); 281 287 if (ret) 282 288 goto out; 283 289
+6 -1
include/linux/blkdev.h
··· 38 38 struct kiocb; 39 39 struct pr_ops; 40 40 struct rq_qos; 41 + struct blk_report_zones_args; 41 42 struct blk_queue_stats; 42 43 struct blk_stat_callback; 43 44 struct blk_crypto_profile; ··· 432 431 433 432 typedef int (*report_zones_cb)(struct blk_zone *zone, unsigned int idx, 434 433 void *data); 434 + 435 + int disk_report_zone(struct gendisk *disk, struct blk_zone *zone, 436 + unsigned int idx, struct blk_report_zones_args *args); 435 437 436 438 #define BLK_ALL_ZONES ((unsigned int)-1) 437 439 int blkdev_report_zones(struct block_device *bdev, sector_t sector, ··· 1666 1662 /* this callback is with swap_lock and sometimes page table lock held */ 1667 1663 void (*swap_slot_free_notify) (struct block_device *, unsigned long); 1668 1664 int (*report_zones)(struct gendisk *, sector_t sector, 1669 - unsigned int nr_zones, report_zones_cb cb, void *data); 1665 + unsigned int nr_zones, 1666 + struct blk_report_zones_args *args); 1670 1667 char *(*devnode)(struct gendisk *disk, umode_t *mode); 1671 1668 /* returns the length of the identifier or a negative errno: */ 1672 1669 int (*get_unique_id)(struct gendisk *disk, u8 id[16],
+8 -2
include/linux/device-mapper.h
··· 538 538 #ifdef CONFIG_BLK_DEV_ZONED 539 539 struct dm_report_zones_args { 540 540 struct dm_target *tgt; 541 + struct gendisk *disk; 541 542 sector_t next_sector; 542 543 543 - void *orig_data; 544 - report_zones_cb orig_cb; 545 544 unsigned int zone_idx; 545 + 546 + /* for block layer ->report_zones */ 547 + struct blk_report_zones_args *rep_args; 548 + 549 + /* for internal users */ 550 + report_zones_cb cb; 551 + void *data; 546 552 547 553 /* must be filled by ->report_zones before calling dm_report_zones_cb */ 548 554 sector_t start;