drivers/vfio/pci/virtio/migrate.c

Source file repositories/reference/linux-study-clean/drivers/vfio/pci/virtio/migrate.c

File Facts

System
Linux kernel
Corpus path
drivers/vfio/pci/virtio/migrate.c
Extension
.c
Size
34243 bytes
Lines
1316
Domain
Driver Families
Bucket
drivers/vfio
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 file_operations virtiovf_save_fops = {
	.owner = THIS_MODULE,
	.read = virtiovf_save_read,
	.unlocked_ioctl = virtiovf_precopy_ioctl,
	.compat_ioctl = compat_ptr_ioctl,
	.release = virtiovf_release_file,
};

static int
virtiovf_add_buf_header(struct virtiovf_data_buffer *header_buf,
			u32 data_size)
{
	struct virtiovf_migration_file *migf = header_buf->migf;
	struct virtiovf_migration_header header = {};
	struct page *page;
	u8 *to_buff;

	header.record_size = cpu_to_le64(data_size);
	header.flags = cpu_to_le32(VIRTIOVF_MIGF_HEADER_FLAGS_TAG_MANDATORY);
	header.tag = cpu_to_le32(VIRTIOVF_MIGF_HEADER_TAG_DEVICE_DATA);
	page = virtiovf_get_migration_page(header_buf, 0);
	if (!page)
		return -EINVAL;
	to_buff = kmap_local_page(page);
	memcpy(to_buff, &header, sizeof(header));
	kunmap_local(to_buff);
	header_buf->length = sizeof(header);
	header_buf->start_pos = header_buf->migf->max_pos;
	migf->max_pos += header_buf->length;

	scoped_guard(mutex, &migf->list_lock)
		list_add_tail(&header_buf->buf_elm, &migf->buf_list);

	return 0;
}

static int
virtiovf_read_device_context_chunk(struct virtiovf_migration_file *migf,
				   u32 ctx_size)
{
	struct virtiovf_data_buffer *header_buf;
	struct virtiovf_data_buffer *buf;
	bool unmark_end = false;
	struct scatterlist *sg;
	unsigned int i;
	u32 res_size;
	int nent;
	int ret;

	buf = virtiovf_get_data_buffer(migf, ctx_size);
	if (IS_ERR(buf))
		return PTR_ERR(buf);

	/* Find the total count of SG entries which satisfies the size */
	nent = sg_nents_for_len(buf->table.sgt.sgl, ctx_size);
	if (nent <= 0) {
		ret = -EINVAL;
		goto out;
	}

	/*
	 * Iterate to that SG entry and mark it as last (if it's not already)
	 * to let underlay layers iterate only till that entry.
	 */
	for_each_sg(buf->table.sgt.sgl, sg, nent - 1, i)
		;

	if (!sg_is_last(sg)) {
		unmark_end = true;
		sg_mark_end(sg);
	}

	ret = virtio_pci_admin_dev_parts_get(migf->virtvdev->core_device.pdev,
					     VIRTIO_RESOURCE_OBJ_DEV_PARTS,
					     migf->obj_id,
					     VIRTIO_ADMIN_CMD_DEV_PARTS_GET_TYPE_ALL,
					     buf->table.sgt.sgl, &res_size);
	/* Restore the original SG mark end */
	if (unmark_end)
		sg_unmark_end(sg);
	if (ret)
		goto out;

	buf->length = res_size;
	header_buf = virtiovf_get_data_buffer(migf,
				sizeof(struct virtiovf_migration_header));
	if (IS_ERR(header_buf)) {
		ret = PTR_ERR(header_buf);
		goto out;
	}

Annotation

Implementation Notes