drivers/block/loop.c
Source file repositories/reference/linux-study-clean/drivers/block/loop.c
File Facts
- System
- Linux kernel
- Corpus path
drivers/block/loop.c- Extension
.c- Size
- 59763 bytes
- Lines
- 2330
- 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.
- Touches user memory; correctness depends on fault-safe copying and privilege boundary handling.
- 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/module.hlinux/moduleparam.hlinux/sched.hlinux/fs.hlinux/pagemap.hlinux/file.hlinux/stat.hlinux/errno.hlinux/major.hlinux/wait.hlinux/blkpg.hlinux/init.hlinux/swap.hlinux/slab.hlinux/compat.hlinux/suspend.hlinux/freezer.hlinux/mutex.hlinux/writeback.hlinux/completion.hlinux/highmem.hlinux/splice.hlinux/sysfs.hlinux/miscdevice.hlinux/falloc.hlinux/uio.hlinux/ioprio.hlinux/blk-cgroup.hlinux/sched/mm.hlinux/statfs.hlinux/uaccess.hlinux/blk-mq.h
Detected Declarations
struct loop_devicestruct loop_cmdstruct loop_workerstruct compat_loop_infofunction loop_global_lock_killablefunction loop_global_unlockfunction lo_calculate_sizefunction lo_can_use_diofunction loop_update_diofunction loop_set_sizefunction loop_clear_limitsfunction lo_fallocatefunction lo_req_flushfunction lo_complete_rqfunction lo_rw_aio_do_completionfunction lo_rw_aio_completefunction lo_rw_aiofunction rq_for_each_bvecfunction do_req_filebackedfunction loop_reread_partitionsfunction loop_query_min_dio_sizefunction is_loop_devicefunction loop_validate_filefunction loop_assign_backing_filefunction loop_check_backing_filefunction loop_change_fdfunction loop_validate_filefunction loop_attr_showfunction loop_attr_backing_file_showfunction loop_attr_offset_showfunction loop_attr_sizelimit_showfunction loop_attr_autoclear_showfunction loop_attr_partscan_showfunction loop_attr_dio_showfunction loop_sysfs_initfunction loop_sysfs_exitfunction loop_get_discard_configfunction blkdev_issue_zerooutfunction queue_on_root_workerfunction queue_on_root_workerfunction loop_queue_workfunction loop_set_timerfunction loop_free_idle_workersfunction loop_free_idle_workers_timerfunction loop_set_status_from_infofunction loop_default_blocksizefunction loop_update_limitsfunction loop_configure
Annotated Snippet
static const struct blk_mq_ops loop_mq_ops = {
.queue_rq = loop_queue_rq,
.complete = lo_complete_rq,
};
static int loop_add(int i)
{
struct queue_limits lim = {
/*
* Random number picked from the historic block max_sectors cap.
*/
.max_hw_sectors = 2560u,
};
struct loop_device *lo;
struct gendisk *disk;
int err;
err = -ENOMEM;
lo = kzalloc_obj(*lo);
if (!lo)
goto out;
lo->worker_tree = RB_ROOT;
INIT_LIST_HEAD(&lo->idle_worker_list);
timer_setup(&lo->timer, loop_free_idle_workers_timer, TIMER_DEFERRABLE);
WRITE_ONCE(lo->lo_state, Lo_unbound);
err = mutex_lock_killable(&loop_ctl_mutex);
if (err)
goto out_free_dev;
/* allocate id, if @id >= 0, we're requesting that specific id */
if (i >= 0) {
err = idr_alloc(&loop_index_idr, lo, i, i + 1, GFP_KERNEL);
if (err == -ENOSPC)
err = -EEXIST;
} else {
err = idr_alloc(&loop_index_idr, lo, 0, 0, GFP_KERNEL);
}
mutex_unlock(&loop_ctl_mutex);
if (err < 0)
goto out_free_dev;
i = err;
lo->tag_set.ops = &loop_mq_ops;
lo->tag_set.nr_hw_queues = 1;
lo->tag_set.queue_depth = hw_queue_depth;
lo->tag_set.numa_node = NUMA_NO_NODE;
lo->tag_set.cmd_size = sizeof(struct loop_cmd);
lo->tag_set.flags = BLK_MQ_F_STACKING | BLK_MQ_F_NO_SCHED_BY_DEFAULT;
lo->tag_set.driver_data = lo;
err = blk_mq_alloc_tag_set(&lo->tag_set);
if (err)
goto out_free_idr;
disk = lo->lo_disk = blk_mq_alloc_disk(&lo->tag_set, &lim, lo);
if (IS_ERR(disk)) {
err = PTR_ERR(disk);
goto out_cleanup_tags;
}
lo->lo_queue = lo->lo_disk->queue;
/*
* Disable partition scanning by default. The in-kernel partition
* scanning can be requested individually per-device during its
* setup. Userspace can always add and remove partitions from all
* devices. The needed partition minors are allocated from the
* extended minor space, the main loop device numbers will continue
* to match the loop minors, regardless of the number of partitions
* used.
*
* If max_part is given, partition scanning is globally enabled for
* all loop devices. The minors for the main loop devices will be
* multiples of max_part.
*
* Note: Global-for-all-devices, set-only-at-init, read-only module
* parameteters like 'max_loop' and 'max_part' make things needlessly
* complicated, are too static, inflexible and may surprise
* userspace tools. Parameters like this in general should be avoided.
*/
if (!part_shift)
set_bit(GD_SUPPRESS_PART_SCAN, &disk->state);
mutex_init(&lo->lo_mutex);
lo->lo_number = i;
spin_lock_init(&lo->lo_lock);
spin_lock_init(&lo->lo_work_lock);
INIT_WORK(&lo->rootcg_work, loop_rootcg_workfn);
INIT_LIST_HEAD(&lo->rootcg_cmd_list);
disk->major = LOOP_MAJOR;
disk->first_minor = i << part_shift;
Annotation
- Immediate include surface: `linux/module.h`, `linux/moduleparam.h`, `linux/sched.h`, `linux/fs.h`, `linux/pagemap.h`, `linux/file.h`, `linux/stat.h`, `linux/errno.h`.
- Detected declarations: `struct loop_device`, `struct loop_cmd`, `struct loop_worker`, `struct compat_loop_info`, `function loop_global_lock_killable`, `function loop_global_unlock`, `function lo_calculate_size`, `function lo_can_use_dio`, `function loop_update_dio`, `function loop_set_size`.
- Atlas domain: Driver Families / drivers/block.
- Implementation status: pattern implementation candidate.
- This snippet crosses the user/kernel memory boundary; validate fault handling and access checks before translating the pattern.
- 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.