drivers/vfio/device_cdev.c

Source file repositories/reference/linux-study-clean/drivers/vfio/device_cdev.c

File Facts

System
Linux kernel
Corpus path
drivers/vfio/device_cdev.c
Extension
.c
Size
7358 bytes
Lines
306
Domain
Driver Families
Bucket
drivers/vfio
Inferred role
Driver Families: implementation source
Status
source 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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2023 Intel Corporation.
 */
#include <linux/vfio.h>
#include <linux/iommufd.h>

#include "vfio.h"

static dev_t device_devt;

void vfio_init_device_cdev(struct vfio_device *device)
{
	device->device.devt = MKDEV(MAJOR(device_devt), device->index);
	cdev_init(&device->cdev, &vfio_device_fops);
	device->cdev.owner = THIS_MODULE;
}

/*
 * device access via the fd opened by this function is blocked until
 * .open_device() is called successfully during BIND_IOMMUFD.
 */
int vfio_device_fops_cdev_open(struct inode *inode, struct file *filep)
{
	struct vfio_device *device = container_of(inode->i_cdev,
						  struct vfio_device, cdev);
	struct vfio_device_file *df;
	int ret;

	/* Paired with the put in vfio_device_fops_release() */
	if (!vfio_device_try_get_registration(device))
		return -ENODEV;

	df = vfio_allocate_device_file(device);
	if (IS_ERR(df)) {
		ret = PTR_ERR(df);
		goto err_put_registration;
	}

	filep->private_data = df;

	/*
	 * Use the pseudo fs inode on the device to link all mmaps
	 * to the same address space, allowing us to unmap all vmas
	 * associated to this device using unmap_mapping_range().
	 */
	filep->f_mapping = device->inode->i_mapping;

	return 0;

err_put_registration:
	vfio_device_put_registration(device);
	return ret;
}

static void vfio_df_get_kvm_safe(struct vfio_device_file *df)
{
	spin_lock(&df->kvm_ref_lock);
	vfio_device_get_kvm_safe(df->device, df->kvm);
	spin_unlock(&df->kvm_ref_lock);
}

static int vfio_df_check_token(struct vfio_device *device,
			       const struct vfio_device_bind_iommufd *bind)
{
	uuid_t uuid;

	if (!device->ops->match_token_uuid) {
		if (bind->flags & VFIO_DEVICE_BIND_FLAG_TOKEN)
			return -EINVAL;
		return 0;
	}

	if (!(bind->flags & VFIO_DEVICE_BIND_FLAG_TOKEN))
		return device->ops->match_token_uuid(device, NULL);

	if (copy_from_user(&uuid, u64_to_user_ptr(bind->token_uuid_ptr),
			   sizeof(uuid)))
		return -EFAULT;
	return device->ops->match_token_uuid(device, &uuid);
}

long vfio_df_ioctl_bind_iommufd(struct vfio_device_file *df,
				struct vfio_device_bind_iommufd __user *arg)
{
	const u32 VALID_FLAGS = VFIO_DEVICE_BIND_FLAG_TOKEN;
	struct vfio_device *device = df->device;
	struct vfio_device_bind_iommufd bind;
	unsigned long minsz;
	u32 user_size;

Annotation

Implementation Notes