drivers/nvme/host/multipath.c

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

File Facts

System
Linux kernel
Corpus path
drivers/nvme/host/multipath.c
Extension
.c
Size
40480 bytes
Lines
1495
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_ns_head_chr_fops = {
	.owner		= THIS_MODULE,
	.open		= nvme_ns_head_chr_open,
	.release	= nvme_ns_head_chr_release,
	.unlocked_ioctl	= nvme_ns_head_chr_ioctl,
	.compat_ioctl	= compat_ptr_ioctl,
	.uring_cmd	= nvme_ns_head_chr_uring_cmd,
	.uring_cmd_iopoll = nvme_ns_chr_uring_cmd_iopoll,
};

static int nvme_add_ns_head_cdev(struct nvme_ns_head *head)
{
	int ret;

	head->cdev_device.parent = &head->subsys->dev;
	ret = dev_set_name(&head->cdev_device, "ng%dn%d",
			   head->subsys->instance, head->instance);
	if (ret)
		return ret;
	ret = nvme_cdev_add(&head->cdev, &head->cdev_device,
			    &nvme_ns_head_chr_fops, THIS_MODULE);
	return ret;
}

static void nvme_partition_scan_work(struct work_struct *work)
{
	struct nvme_ns_head *head =
		container_of(work, struct nvme_ns_head, partition_scan_work);

	if (WARN_ON_ONCE(!test_and_clear_bit(GD_SUPPRESS_PART_SCAN,
					     &head->disk->state)))
		return;

	mutex_lock(&head->disk->open_mutex);
	bdev_disk_changed(head->disk, false);
	mutex_unlock(&head->disk->open_mutex);
}

static void nvme_requeue_work(struct work_struct *work)
{
	struct nvme_ns_head *head =
		container_of(work, struct nvme_ns_head, requeue_work);
	struct bio *bio, *next;

	spin_lock_irq(&head->requeue_lock);
	next = bio_list_get(&head->requeue_list);
	spin_unlock_irq(&head->requeue_lock);

	while ((bio = next) != NULL) {
		next = bio->bi_next;
		bio->bi_next = NULL;

		submit_bio_noacct(bio);
	}
}

static void nvme_remove_head(struct nvme_ns_head *head)
{
	if (test_and_clear_bit(NVME_NSHEAD_DISK_LIVE, &head->flags)) {
		/*
		 * requeue I/O after NVME_NSHEAD_DISK_LIVE has been cleared
		 * to allow multipath to fail all I/O.
		 */
		kblockd_schedule_work(&head->requeue_work);

		nvme_cdev_del(&head->cdev, &head->cdev_device);
		synchronize_srcu(&head->srcu);
		del_gendisk(head->disk);
	}
	nvme_put_ns_head(head);
}

static void nvme_remove_head_work(struct work_struct *work)
{
	struct nvme_ns_head *head = container_of(to_delayed_work(work),
			struct nvme_ns_head, remove_work);
	bool remove = false;

	mutex_lock(&head->subsys->lock);
	if (list_empty(&head->list)) {
		list_del_init(&head->entry);
		remove = true;
	}
	mutex_unlock(&head->subsys->lock);
	if (remove)
		nvme_remove_head(head);

	module_put(THIS_MODULE);
}

Annotation

Implementation Notes