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.
- 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.
- Defines an operation table; this is where Linux turns generic core objects into subsystem-specific behavior.
- Uses kernel synchronization; read lock ordering, sleepability, and interrupt context assumptions before translating.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/major.hlinux/blkdev.hlinux/module.hlinux/init.hlinux/sched.hlinux/sched/mm.hlinux/fs.hlinux/bio.hlinux/stat.hlinux/errno.hlinux/file.hlinux/ioctl.hlinux/mutex.hlinux/compiler.hlinux/completion.hlinux/err.hlinux/kernel.hlinux/slab.hnet/sock.hlinux/net.hlinux/kthread.hlinux/types.hlinux/debugfs.hlinux/blk-mq.hlinux/uaccess.hasm/types.hlinux/nbd.hlinux/nbd-netlink.hnet/genetlink.htrace/events/nbd.h
Detected Declarations
struct nbd_sockstruct recv_thread_argsstruct link_dead_argsstruct nbd_configstruct nbd_devicestruct nbd_cmdfunction nbd_blksizefunction nbd_requeue_cmdfunction nbd_cmd_handlefunction nbd_handle_to_tagfunction nbd_handle_to_cookiefunction pid_showfunction backend_showfunction nbd_dev_removefunction nbd_dev_remove_workfunction nbd_putfunction nbd_disconnectedfunction nbd_mark_nsock_deadfunction nbd_set_sizefunction nbd_complete_rqfunction sock_shutdownfunction req_to_nbd_cmd_typefunction nbd_xmit_timeoutfunction __sock_xmitfunction scoped_with_kernel_credsfunction sock_xmitfunction was_interruptedfunction nbd_sched_pending_workfunction nbd_send_cmdfunction bio_for_each_segmentfunction nbd_pending_cmd_workfunction nbd_read_replyfunction rq_for_each_segmentfunction recv_workfunction nbd_clear_reqfunction nbd_clear_quefunction find_fallbackfunction wait_for_reconnectfunction nbd_handle_cmdfunction nbd_queue_rqfunction nbd_reclassify_socketfunction nbd_reclassify_socketfunction nbd_reconnect_socketfunction nbd_bdev_resetfunction nbd_parse_flagsfunction send_disconnectsfunction nbd_disconnectfunction nbd_clear_sock
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
- Immediate include surface: `linux/major.h`, `linux/blkdev.h`, `linux/module.h`, `linux/init.h`, `linux/sched.h`, `linux/sched/mm.h`, `linux/fs.h`, `linux/bio.h`.
- Detected declarations: `struct nbd_sock`, `struct recv_thread_args`, `struct link_dead_args`, `struct nbd_config`, `struct nbd_device`, `struct nbd_cmd`, `function nbd_blksize`, `function nbd_requeue_cmd`, `function nbd_cmd_handle`, `function nbd_handle_to_tag`.
- Atlas domain: Driver Families / drivers/block.
- Implementation status: pattern implementation candidate.
- Synchronization appears in or near this file; preserve lock ordering, sleepability, and interrupt-context constraints.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.