drivers/block/virtio_blk.c

Source file repositories/reference/linux-study-clean/drivers/block/virtio_blk.c

File Facts

System
Linux kernel
Corpus path
drivers/block/virtio_blk.c
Extension
.c
Size
44459 bytes
Lines
1733
Domain
Driver Families
Bucket
drivers/block
Inferred role
Driver Families: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct blk_mq_ops virtio_mq_ops = {
	.queue_rq	= virtio_queue_rq,
	.queue_rqs	= virtio_queue_rqs,
	.commit_rqs	= virtio_commit_rqs,
	.complete	= virtblk_request_done,
	.map_queues	= virtblk_map_queues,
	.poll		= virtblk_poll,
};

static unsigned int virtblk_queue_depth;
module_param_named(queue_depth, virtblk_queue_depth, uint, 0444);

static int virtblk_read_limits(struct virtio_blk *vblk,
		struct queue_limits *lim)
{
	struct virtio_device *vdev = vblk->vdev;
	u32 v, max_size, sg_elems, opt_io_size;
	u32 max_discard_segs = 0;
	u32 discard_granularity = 0;
	u16 min_io_size;
	u8 physical_block_exp, alignment_offset;
	size_t max_dma_size;
	int err;

	/* We need to know how many segments before we allocate. */
	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SEG_MAX,
				   struct virtio_blk_config, seg_max,
				   &sg_elems);

	/* We need at least one SG element, whatever they say. */
	if (err || !sg_elems)
		sg_elems = 1;

	/* Prevent integer overflows and honor max vq size */
	sg_elems = min_t(u32, sg_elems, VIRTIO_BLK_MAX_SG_ELEMS - 2);

	/* We can handle whatever the host told us to handle. */
	lim->max_segments = sg_elems;

	/* No real sector limit. */
	lim->max_hw_sectors = UINT_MAX;

	max_dma_size = virtio_max_dma_size(vdev);
	max_size = max_dma_size > U32_MAX ? U32_MAX : max_dma_size;

	/* Host can optionally specify maximum segment size and number of
	 * segments. */
	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_SIZE_MAX,
				   struct virtio_blk_config, size_max, &v);
	if (!err)
		max_size = min(max_size, v);

	lim->max_segment_size = max_size;

	/* Host can optionally specify the block size of the device */
	virtio_cread_feature(vdev, VIRTIO_BLK_F_BLK_SIZE,
				   struct virtio_blk_config, blk_size,
				   &lim->logical_block_size);

	/* Use topology information if available */
	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
				   struct virtio_blk_config, physical_block_exp,
				   &physical_block_exp);
	if (!err && physical_block_exp)
		lim->physical_block_size =
			lim->logical_block_size * (1 << physical_block_exp);

	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
				   struct virtio_blk_config, alignment_offset,
				   &alignment_offset);
	if (!err && alignment_offset)
		lim->alignment_offset =
			lim->logical_block_size * alignment_offset;

	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
				   struct virtio_blk_config, min_io_size,
				   &min_io_size);
	if (!err && min_io_size)
		lim->io_min = lim->logical_block_size * min_io_size;

	err = virtio_cread_feature(vdev, VIRTIO_BLK_F_TOPOLOGY,
				   struct virtio_blk_config, opt_io_size,
				   &opt_io_size);
	if (!err && opt_io_size)
		lim->io_opt = lim->logical_block_size * opt_io_size;

	if (virtio_has_feature(vdev, VIRTIO_BLK_F_DISCARD)) {
		virtio_cread(vdev, struct virtio_blk_config,
			     discard_sector_alignment, &discard_granularity);

Annotation

Implementation Notes