Commit 8b837256 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Jens Axboe

virtio_blk: pass queue_limits to blk_mq_alloc_disk

Call virtblk_read_limits and most of virtblk_probe_zoned_device before
allocating the gendisk and thus request_queue and make them read into
a queue_limits structure instead.  Pass this initialized queue_limits
to blk_mq_alloc_disk to set the queue up with the right parameters
from the start and only leave a few final touches for zoned devices
to be done just before adding the disk.
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarKeith Busch <kbusch@kernel.org>
Reviewed-by: default avatarStefan Hajnoczi <stefanha@redhat.com>
Reviewed-by: default avatarChaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: default avatarMing Lei <ming.lei@redhat.com>
Reviewed-by: default avatarDamien Le Moal <dlemoal@kernel.org>
Reviewed-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Reviewed-by: default avatarHannes Reinecke <hare@suse.de>
Link: https://lore.kernel.org/r/20240213073425.1621680-13-hch@lst.deSigned-off-by: default avatarJens Axboe <axboe@kernel.dk>
parent 718628ad
...@@ -720,16 +720,15 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector, ...@@ -720,16 +720,15 @@ static int virtblk_report_zones(struct gendisk *disk, sector_t sector,
return ret; return ret;
} }
static int virtblk_probe_zoned_device(struct virtio_device *vdev, static int virtblk_read_zoned_limits(struct virtio_blk *vblk,
struct virtio_blk *vblk, struct queue_limits *lim)
struct request_queue *q)
{ {
struct virtio_device *vdev = vblk->vdev;
u32 v, wg; u32 v, wg;
dev_dbg(&vdev->dev, "probing host-managed zoned device\n"); dev_dbg(&vdev->dev, "probing host-managed zoned device\n");
disk_set_zoned(vblk->disk); lim->zoned = true;
blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, q);
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
zoned.max_open_zones, &v); zoned.max_open_zones, &v);
...@@ -747,8 +746,8 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, ...@@ -747,8 +746,8 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
dev_warn(&vdev->dev, "zero write granularity reported\n"); dev_warn(&vdev->dev, "zero write granularity reported\n");
return -ENODEV; return -ENODEV;
} }
blk_queue_physical_block_size(q, wg); lim->physical_block_size = wg;
blk_queue_io_min(q, wg); lim->io_min = wg;
dev_dbg(&vdev->dev, "write granularity = %u\n", wg); dev_dbg(&vdev->dev, "write granularity = %u\n", wg);
...@@ -764,13 +763,13 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, ...@@ -764,13 +763,13 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
vblk->zone_sectors); vblk->zone_sectors);
return -ENODEV; return -ENODEV;
} }
blk_queue_chunk_sectors(q, vblk->zone_sectors); lim->chunk_sectors = vblk->zone_sectors;
dev_dbg(&vdev->dev, "zone sectors = %u\n", vblk->zone_sectors); dev_dbg(&vdev->dev, "zone sectors = %u\n", vblk->zone_sectors);
if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) { if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
dev_warn(&vblk->vdev->dev, dev_warn(&vblk->vdev->dev,
"ignoring negotiated F_DISCARD for zoned device\n"); "ignoring negotiated F_DISCARD for zoned device\n");
blk_queue_max_discard_sectors(q, 0); lim->max_hw_discard_sectors = 0;
} }
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
...@@ -785,25 +784,21 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev, ...@@ -785,25 +784,21 @@ static int virtblk_probe_zoned_device(struct virtio_device *vdev,
wg, v); wg, v);
return -ENODEV; return -ENODEV;
} }
blk_queue_max_zone_append_sectors(q, v); lim->max_zone_append_sectors = v;
dev_dbg(&vdev->dev, "max append sectors = %u\n", v); dev_dbg(&vdev->dev, "max append sectors = %u\n", v);
return blk_revalidate_disk_zones(vblk->disk, NULL); return 0;
} }
#else #else
/* /*
* Zoned block device support is not configured in this kernel. * Zoned block device support is not configured in this kernel, host-managed
* Host-managed zoned devices can't be supported, but others are * zoned devices can't be supported.
* good to go as regular block devices.
*/ */
#define virtblk_report_zones NULL #define virtblk_report_zones NULL
static inline int virtblk_read_zoned_limits(struct virtio_blk *vblk,
static inline int virtblk_probe_zoned_device(struct virtio_device *vdev, struct queue_limits *lim)
struct virtio_blk *vblk, struct request_queue *q)
{ {
dev_err(&vdev->dev, dev_err(&vblk->vdev->dev,
"virtio_blk: zoned devices are not supported"); "virtio_blk: zoned devices are not supported");
return -EOPNOTSUPP; return -EOPNOTSUPP;
} }
...@@ -1248,9 +1243,9 @@ static const struct blk_mq_ops virtio_mq_ops = { ...@@ -1248,9 +1243,9 @@ static const struct blk_mq_ops virtio_mq_ops = {
static unsigned int virtblk_queue_depth; static unsigned int virtblk_queue_depth;
module_param_named(queue_depth, virtblk_queue_depth, uint, 0444); module_param_named(queue_depth, virtblk_queue_depth, uint, 0444);
static int virtblk_read_limits(struct virtio_blk *vblk) static int virtblk_read_limits(struct virtio_blk *vblk,
struct queue_limits *lim)
{ {
struct request_queue *q = vblk->disk->queue;
struct virtio_device *vdev = vblk->vdev; struct virtio_device *vdev = vblk->vdev;
u32 v, blk_size, max_size, sg_elems, opt_io_size; u32 v, blk_size, max_size, sg_elems, opt_io_size;
u32 max_discard_segs = 0; u32 max_discard_segs = 0;
...@@ -1273,10 +1268,10 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1273,10 +1268,10 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2); sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);
/* We can handle whatever the host told us to handle. */ /* We can handle whatever the host told us to handle. */
blk_queue_max_segments(q, sg_elems); lim->max_segments = sg_elems;
/* No real sector limit. */ /* No real sector limit. */
blk_queue_max_hw_sectors(q, UINT_MAX); lim->max_hw_sectors = UINT_MAX;
max_dma_size = virtio_max_dma_size(vdev); max_dma_size = virtio_max_dma_size(vdev);
max_size = max_dma_size > U32_MAX ? U32_MAX : max_dma_size; max_size = max_dma_size > U32_MAX ? U32_MAX : max_dma_size;
...@@ -1288,7 +1283,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1288,7 +1283,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
if (!err) if (!err)
max_size = min(max_size, v); max_size = min(max_size, v);
blk_queue_max_segment_size(q, max_size); lim->max_segment_size = max_size;
/* Host can optionally specify the block size of the device */ /* Host can optionally specify the block size of the device */
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
...@@ -1303,35 +1298,34 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1303,35 +1298,34 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
return err; return err;
} }
blk_queue_logical_block_size(q, blk_size); lim->logical_block_size = blk_size;
} else } else
blk_size = queue_logical_block_size(q); blk_size = lim->logical_block_size;
/* Use topology information if available */ /* Use topology information if available */
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
struct virtio_blk_config, physical_block_exp, struct virtio_blk_config, physical_block_exp,
&physical_block_exp); &physical_block_exp);
if (!err && physical_block_exp) if (!err && physical_block_exp)
blk_queue_physical_block_size(q, lim->physical_block_size = blk_size * (1 << physical_block_exp);
blk_size * (1 << physical_block_exp));
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
struct virtio_blk_config, alignment_offset, struct virtio_blk_config, alignment_offset,
&alignment_offset); &alignment_offset);
if (!err && alignment_offset) if (!err && alignment_offset)
blk_queue_alignment_offset(q, blk_size * alignment_offset); lim->alignment_offset = blk_size * alignment_offset;
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
struct virtio_blk_config, min_io_size, struct virtio_blk_config, min_io_size,
&min_io_size); &min_io_size);
if (!err && min_io_size) if (!err && min_io_size)
blk_queue_io_min(q, blk_size * min_io_size); lim->io_min = blk_size * min_io_size;
err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY, err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
struct virtio_blk_config, opt_io_size, struct virtio_blk_config, opt_io_size,
&opt_io_size); &opt_io_size);
if (!err && opt_io_size) if (!err && opt_io_size)
blk_queue_io_opt(q, blk_size * opt_io_size); lim->io_opt = blk_size * opt_io_size;
if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) { if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
...@@ -1339,7 +1333,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1339,7 +1333,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
max_discard_sectors, &v); max_discard_sectors, &v);
blk_queue_max_discard_sectors(q, v ? v : UINT_MAX); lim->max_hw_discard_sectors = v ? v : UINT_MAX;
virtio_cread(vdev, struct virtio_blk_config, max_discard_seg, virtio_cread(vdev, struct virtio_blk_config, max_discard_seg,
&max_discard_segs); &max_discard_segs);
...@@ -1348,7 +1342,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1348,7 +1342,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) { if (virtio_has_feature(vdev, VIRTIO_BLK_F_WRITE_ZEROES)) {
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
max_write_zeroes_sectors, &v); max_write_zeroes_sectors, &v);
blk_queue_max_write_zeroes_sectors(q, v ? v : UINT_MAX); lim->max_write_zeroes_sectors = v ? v : UINT_MAX;
} }
/* The discard and secure erase limits are combined since the Linux /* The discard and secure erase limits are combined since the Linux
...@@ -1391,7 +1385,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1391,7 +1385,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
return -EINVAL; return -EINVAL;
} }
blk_queue_max_secure_erase_sectors(q, v); lim->max_secure_erase_sectors = v;
virtio_cread(vdev, struct virtio_blk_config, virtio_cread(vdev, struct virtio_blk_config,
max_secure_erase_seg, &v); max_secure_erase_seg, &v);
...@@ -1418,13 +1412,34 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1418,13 +1412,34 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
if (!max_discard_segs) if (!max_discard_segs)
max_discard_segs = sg_elems; max_discard_segs = sg_elems;
blk_queue_max_discard_segments(q, lim->max_discard_segments =
min(max_discard_segs, MAX_DISCARD_SEGMENTS)); min(max_discard_segs, MAX_DISCARD_SEGMENTS);
if (discard_granularity) if (discard_granularity)
q->limits.discard_granularity = discard_granularity << SECTOR_SHIFT; lim->discard_granularity =
discard_granularity << SECTOR_SHIFT;
else else
q->limits.discard_granularity = blk_size; lim->discard_granularity = blk_size;
}
if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) {
u8 model;
virtio_cread(vdev, struct virtio_blk_config, zoned.model, &model);
switch (model) {
case VIRTIO_BLK_Z_NONE:
case VIRTIO_BLK_Z_HA:
/* treat host-aware devices as non-zoned */
return 0;
case VIRTIO_BLK_Z_HM:
err = virtblk_read_zoned_limits(vblk, lim);
if (err)
return err;
break;
default:
dev_err(&vdev->dev, "unsupported zone model %d\n", model);
return -EINVAL;
}
} }
return 0; return 0;
...@@ -1433,7 +1448,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk) ...@@ -1433,7 +1448,7 @@ static int virtblk_read_limits(struct virtio_blk *vblk)
static int virtblk_probe(struct virtio_device *vdev) static int virtblk_probe(struct virtio_device *vdev)
{ {
struct virtio_blk *vblk; struct virtio_blk *vblk;
struct request_queue *q; struct queue_limits lim = { };
int err, index; int err, index;
unsigned int queue_depth; unsigned int queue_depth;
...@@ -1493,12 +1508,15 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -1493,12 +1508,15 @@ static int virtblk_probe(struct virtio_device *vdev)
if (err) if (err)
goto out_free_vq; goto out_free_vq;
vblk->disk = blk_mq_alloc_disk(&vblk->tag_set, NULL, vblk); err = virtblk_read_limits(vblk, &lim);
if (err)
goto out_free_tags;
vblk->disk = blk_mq_alloc_disk(&vblk->tag_set, &lim, vblk);
if (IS_ERR(vblk->disk)) { if (IS_ERR(vblk->disk)) {
err = PTR_ERR(vblk->disk); err = PTR_ERR(vblk->disk);
goto out_free_tags; goto out_free_tags;
} }
q = vblk->disk->queue;
virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN); virtblk_name_format("vd", index, vblk->disk->disk_name, DISK_NAME_LEN);
...@@ -1516,10 +1534,6 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -1516,10 +1534,6 @@ static int virtblk_probe(struct virtio_device *vdev)
if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO)) if (virtio_has_feature(vdev, VIRTIO_BLK_F_RO))
set_disk_ro(vblk->disk, 1); set_disk_ro(vblk->disk, 1);
err = virtblk_read_limits(vblk);
if (err)
goto out_cleanup_disk;
virtblk_update_capacity(vblk, false); virtblk_update_capacity(vblk, false);
virtio_device_ready(vdev); virtio_device_ready(vdev);
...@@ -1527,27 +1541,11 @@ static int virtblk_probe(struct virtio_device *vdev) ...@@ -1527,27 +1541,11 @@ static int virtblk_probe(struct virtio_device *vdev)
* All steps that follow use the VQs therefore they need to be * All steps that follow use the VQs therefore they need to be
* placed after the virtio_device_ready() call above. * placed after the virtio_device_ready() call above.
*/ */
if (virtio_has_feature(vdev, VIRTIO_BLK_F_ZONED)) { if (IS_ENABLED(CONFIG_BLK_DEV_ZONED) && lim.zoned) {
u8 model; blk_queue_flag_set(QUEUE_FLAG_ZONE_RESETALL, vblk->disk->queue);
err = blk_revalidate_disk_zones(vblk->disk, NULL);
virtio_cread(vdev, struct virtio_blk_config, zoned.model,
&model);
switch (model) {
case VIRTIO_BLK_Z_NONE:
case VIRTIO_BLK_Z_HA:
/* Present the host-aware device as non-zoned */
break;
case VIRTIO_BLK_Z_HM:
err = virtblk_probe_zoned_device(vdev, vblk, q);
if (err) if (err)
goto out_cleanup_disk; goto out_cleanup_disk;
break;
default:
dev_err(&vdev->dev, "unsupported zone model %d\n",
model);
err = -EINVAL;
goto out_cleanup_disk;
}
} }
err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups); err = device_add_disk(&vdev->dev, vblk->disk, virtblk_attr_groups);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment