drivers/block/nbd.c

Source file repositories/reference/linux-study-clean/drivers/block/nbd.c

File Facts

System
Linux kernel
Corpus path
drivers/block/nbd.c
Extension
.c
Size
71029 bytes
Lines
2790
Domain
Driver Families
Bucket
drivers/block
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 blk_mq_ops nbd_mq_ops = {
	.queue_rq	= nbd_queue_rq,
	.complete	= nbd_complete_rq,
	.init_request	= nbd_init_request,
	.timeout	= nbd_xmit_timeout,
};

static struct nbd_device *nbd_dev_add(int index, unsigned int refs)
{
	struct queue_limits lim = {
		.max_hw_sectors		= 65536,
		.io_opt			= 256 << SECTOR_SHIFT,
		.max_segments		= USHRT_MAX,
		.max_segment_size	= UINT_MAX,
	};
	struct nbd_device *nbd;
	struct gendisk *disk;
	int err = -ENOMEM;

	nbd = kzalloc_obj(struct nbd_device);
	if (!nbd)
		goto out;

	nbd->tag_set.ops = &nbd_mq_ops;
	nbd->tag_set.nr_hw_queues = 1;
	nbd->tag_set.queue_depth = 128;
	nbd->tag_set.numa_node = NUMA_NO_NODE;
	nbd->tag_set.cmd_size = sizeof(struct nbd_cmd);
	nbd->tag_set.flags = BLK_MQ_F_BLOCKING;
	nbd->tag_set.driver_data = nbd;
	INIT_WORK(&nbd->remove_work, nbd_dev_remove_work);
	nbd->backend = NULL;

	err = blk_mq_alloc_tag_set(&nbd->tag_set);
	if (err)
		goto out_free_nbd;

	mutex_lock(&nbd_index_mutex);
	if (index >= 0) {
		err = idr_alloc(&nbd_index_idr, nbd, index, index + 1,
				GFP_KERNEL);
		if (err == -ENOSPC)
			err = -EEXIST;
	} else {
		err = idr_alloc(&nbd_index_idr, nbd, 0,
				(MINORMASK >> part_shift) + 1, GFP_KERNEL);
		if (err >= 0)
			index = err;
	}
	nbd->index = index;
	mutex_unlock(&nbd_index_mutex);
	if (err < 0)
		goto out_free_tags;

	disk = blk_mq_alloc_disk(&nbd->tag_set, &lim, NULL);
	if (IS_ERR(disk)) {
		err = PTR_ERR(disk);
		goto out_free_idr;
	}
	nbd->disk = disk;

	nbd->recv_workq = alloc_workqueue("nbd%d-recv",
					  WQ_MEM_RECLAIM | WQ_HIGHPRI |
					  WQ_UNBOUND, 0, nbd->index);
	if (!nbd->recv_workq) {
		dev_err(disk_to_dev(nbd->disk), "Could not allocate knbd recv work queue.\n");
		err = -ENOMEM;
		goto out_err_disk;
	}

	mutex_init(&nbd->config_lock);
	refcount_set(&nbd->config_refs, 0);
	/*
	 * Start out with a zero references to keep other threads from using
	 * this device until it is fully initialized.
	 */
	refcount_set(&nbd->refs, 0);
	INIT_LIST_HEAD(&nbd->list);
	disk->major = NBD_MAJOR;
	disk->first_minor = index << part_shift;
	disk->minors = 1 << part_shift;
	disk->fops = &nbd_fops;
	disk->private_data = nbd;
	sprintf(disk->disk_name, "nbd%d", index);
	err = add_disk(disk);
	if (err)
		goto out_free_work;

	/*
	 * Now publish the device.

Annotation

Implementation Notes