drivers/nvme/target/loop.c

Source file repositories/reference/linux-study-clean/drivers/nvme/target/loop.c

File Facts

System
Linux kernel
Corpus path
drivers/nvme/target/loop.c
Extension
.c
Size
18619 bytes
Lines
724
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 blk_mq_ops nvme_loop_mq_ops = {
	.queue_rq	= nvme_loop_queue_rq,
	.complete	= nvme_loop_complete_rq,
	.init_request	= nvme_loop_init_request,
	.init_hctx	= nvme_loop_init_hctx,
};

static const struct blk_mq_ops nvme_loop_admin_mq_ops = {
	.queue_rq	= nvme_loop_queue_rq,
	.complete	= nvme_loop_complete_rq,
	.init_request	= nvme_loop_init_request,
	.init_hctx	= nvme_loop_init_admin_hctx,
};

static void nvme_loop_destroy_admin_queue(struct nvme_loop_ctrl *ctrl)
{
	if (!test_and_clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[0].flags))
		return;
	/*
	 * It's possible that some requests might have been added
	 * after admin queue is stopped/quiesced. So now start the
	 * queue to flush these requests to the completion.
	 */
	nvme_unquiesce_admin_queue(&ctrl->ctrl);

	nvmet_sq_destroy(&ctrl->queues[0].nvme_sq);
	nvmet_cq_put(&ctrl->queues[0].nvme_cq);
}

static void nvme_loop_free_ctrl(struct nvme_ctrl *nctrl)
{
	struct nvme_loop_ctrl *ctrl = to_loop_ctrl(nctrl);

	if (list_empty(&ctrl->list))
		goto free_ctrl;

	mutex_lock(&nvme_loop_ctrl_mutex);
	list_del(&ctrl->list);
	mutex_unlock(&nvme_loop_ctrl_mutex);

	if (nctrl->tagset)
		nvme_remove_io_tag_set(nctrl);
	kfree(ctrl->queues);
	nvmf_free_options(nctrl->opts);
free_ctrl:
	kfree(ctrl);
}

static void nvme_loop_destroy_io_queues(struct nvme_loop_ctrl *ctrl)
{
	int i;

	for (i = 1; i < ctrl->ctrl.queue_count; i++) {
		clear_bit(NVME_LOOP_Q_LIVE, &ctrl->queues[i].flags);
		nvmet_sq_destroy(&ctrl->queues[i].nvme_sq);
		nvmet_cq_put(&ctrl->queues[i].nvme_cq);
	}
	ctrl->ctrl.queue_count = 1;
	/*
	 * It's possible that some requests might have been added
	 * after io queue is stopped/quiesced. So now start the
	 * queue to flush these requests to the completion.
	 */
	nvme_unquiesce_io_queues(&ctrl->ctrl);
}

static int nvme_loop_init_io_queues(struct nvme_loop_ctrl *ctrl)
{
	struct nvmf_ctrl_options *opts = ctrl->ctrl.opts;
	unsigned int nr_io_queues;
	int ret, i;

	nr_io_queues = min(opts->nr_io_queues, num_online_cpus());
	ret = nvme_set_queue_count(&ctrl->ctrl, &nr_io_queues);
	if (ret || !nr_io_queues)
		return ret;

	dev_info(ctrl->ctrl.device, "creating %d I/O queues.\n", nr_io_queues);

	for (i = 1; i <= nr_io_queues; i++) {
		ctrl->queues[i].ctrl = ctrl;
		nvmet_cq_init(&ctrl->queues[i].nvme_cq);
		ret = nvmet_sq_init(&ctrl->queues[i].nvme_sq,
				&ctrl->queues[i].nvme_cq);
		if (ret) {
			nvmet_cq_put(&ctrl->queues[i].nvme_cq);
			goto out_destroy_queues;
		}

		ctrl->ctrl.queue_count++;

Annotation

Implementation Notes