drivers/nvme/host/core.c

Source file repositories/reference/linux-study-clean/drivers/nvme/host/core.c

File Facts

System
Linux kernel
Corpus path
drivers/nvme/host/core.c
Extension
.c
Size
149601 bytes
Lines
5521
Domain
Representative Device Path
Bucket
PCIe NVMe Storage Path
Inferred role
Representative Device Path: operation-table or driver-model contract
Status
pattern implementation candidate

Why This File Exists

Part of the selected hardware vertical slice: PCI discovery, driver binding, NVMe queues, block requests, DMA, interrupts, and completion.

Dependency Surface

Detected Declarations

Annotated Snippet

static const struct file_operations nvme_dev_fops = {
	.owner		= THIS_MODULE,
	.open		= nvme_dev_open,
	.release	= nvme_dev_release,
	.unlocked_ioctl	= nvme_dev_ioctl,
	.compat_ioctl	= compat_ptr_ioctl,
	.uring_cmd	= nvme_dev_uring_cmd,
};

static struct nvme_ns_head *nvme_find_ns_head(struct nvme_ctrl *ctrl,
		unsigned nsid)
{
	struct nvme_ns_head *h;

	lockdep_assert_held(&ctrl->subsys->lock);

	list_for_each_entry(h, &ctrl->subsys->nsheads, entry) {
		/*
		 * Private namespaces can share NSIDs under some conditions.
		 * In that case we can't use the same ns_head for namespaces
		 * with the same NSID.
		 */
		if (h->ns_id != nsid || !nvme_is_unique_nsid(ctrl, h))
			continue;
		if (nvme_tryget_ns_head(h))
			return h;
	}

	return NULL;
}

static int nvme_subsys_check_duplicate_ids(struct nvme_subsystem *subsys,
		struct nvme_ns_ids *ids)
{
	bool has_uuid = !uuid_is_null(&ids->uuid);
	bool has_nguid = memchr_inv(ids->nguid, 0, sizeof(ids->nguid));
	bool has_eui64 = memchr_inv(ids->eui64, 0, sizeof(ids->eui64));
	struct nvme_ns_head *h;

	lockdep_assert_held(&subsys->lock);

	list_for_each_entry(h, &subsys->nsheads, entry) {
		if (has_uuid && uuid_equal(&ids->uuid, &h->ids.uuid))
			return -EINVAL;
		if (has_nguid &&
		    memcmp(&ids->nguid, &h->ids.nguid, sizeof(ids->nguid)) == 0)
			return -EINVAL;
		if (has_eui64 &&
		    memcmp(&ids->eui64, &h->ids.eui64, sizeof(ids->eui64)) == 0)
			return -EINVAL;
	}

	return 0;
}

static void nvme_cdev_rel(struct device *dev)
{
	ida_free(&nvme_ns_chr_minor_ida, MINOR(dev->devt));
}

void nvme_cdev_del(struct cdev *cdev, struct device *cdev_device)
{
	cdev_device_del(cdev, cdev_device);
	put_device(cdev_device);
}

int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
		const struct file_operations *fops, struct module *owner)
{
	int minor, ret;

	minor = ida_alloc(&nvme_ns_chr_minor_ida, GFP_KERNEL);
	if (minor < 0)
		return minor;
	cdev_device->devt = MKDEV(MAJOR(nvme_ns_chr_devt), minor);
	cdev_device->class = &nvme_ns_chr_class;
	cdev_device->release = nvme_cdev_rel;
	device_initialize(cdev_device);
	cdev_init(cdev, fops);
	cdev->owner = owner;
	ret = cdev_device_add(cdev, cdev_device);
	if (ret)
		put_device(cdev_device);

	return ret;
}

static int nvme_ns_chr_open(struct inode *inode, struct file *file)
{
	return nvme_ns_open(container_of(inode->i_cdev, struct nvme_ns, cdev));

Annotation

Implementation Notes