![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
blk) The blk layer turns a single physical storage backend into one or more RT-Thread block devices that applications and DFS can open, read/write by sector, and control with standard IOCTLs. Hardware drivers implement **struct rt_blk_disk_ops** on an embedded **struct rt_blk_disk**; the core registers the disk, scans partition tables, and creates child volumes (**struct rt_blk_device**) such as **sda1** or **mmcsd0p1**.
Header: components/drivers/include/drivers/blk.h. IOCTLs and geometry: components/drivers/include/drivers/classes/block.h. Core: components/drivers/block/blk.c, blk_dev.c, blk_partition.c.
| Layer | Struct | Document |
|---|---|---|
| Physical disk | struct rt_blk_disk | Physical disk (rt_blk_disk) |
| Partition table | (on-disk metadata) | Disk partition probing |
| Volume (partition) | struct rt_blk_device | This page — application-facing nodes |
Both disk and volume nodes use **RT_Device_Class_Block**. Applications normally open volumes (sda1), not the raw disk device, unless probing created a single full-disk volume with **partno == 0**.
| Option | Role |
|---|---|
**RT_USING_BLK** | Master switch for components/drivers/block/ |
**RT_BLK_PARTITION_EFI** | GPT / protective MBR parser (partitions/efi.c) |
**RT_BLK_PARTITION_DFS** | Legacy DFS superblock layout on sector 0 (partitions/dfs.c, needs **RT_USING_DFS**) |
**rt_hw_blk_disk_register** always calls **rt_blk_disk_probe_partition**; partition scan errors are ignored (register still succeeds).
Same usage model as other char/block devices: find → open → read/write → control → close. Sector index is 0-based within the opened device (for a partition device, sector 0 is the start of that partition).
| Parameter | Description |
|---|---|
name | Volume name, e.g. **sda0**, **sda1**, **mmcsd0**, **nvme0n1** (from DM naming — see Physical disk (rt_blk_disk)) |
| Return | Device handle, or **RT_NULL** if not found |
oflag | Notes |
|---|---|
**RT_DEVICE_OFLAG_RDONLY** | Always valid |
**RT_DEVICE_OFLAG_WRONLY** | Fails on disk/volume if backend is read-only (**ops->write == NULL** sets **read_only**) |
Opening a partition device (rt_blk_device) internally opens the parent disk (blk_dev_open → rt_device_open(&blk->disk->parent)).
For block class devices, **pos** is the starting sector number, **size** is sector count (not bytes).
| Parameter | Partition volume | Whole disk |
|---|---|---|
pos | 0 … sector_count - 1 (relative to partition) | 0 … disk capacity − 1 |
size | Sectors to transfer | Same |
| Return | Sectors actually transferred, or negative error | Same |
| Command | args type | Partition volume | Raw disk |
|---|---|---|---|
**RT_DEVICE_CTRL_BLK_GETGEOME** | struct rt_device_blk_geometry * | **sector_count** = partition size; **bytes_per_sector** from disk | Full disk geometry |
**RT_DEVICE_CTRL_BLK_SYNC** | ignored | Flushes parent disk | **ops->sync** under lock |
**RT_DEVICE_CTRL_BLK_ERASE** | ignored | Only if **disk->partitions <= 1**; else **-RT_EIO** | May remove all partitions then **ops->erase** |
**RT_DEVICE_CTRL_BLK_AUTOREFRESH** | rt_bool_t * / pointer treated as enable flag | Delegates to disk if single partition | **ops->autorefresh** |
**RT_DEVICE_CTRL_BLK_PARTITION** | struct dfs_partition * | Copies **blk->partition** | **-RT_EINVAL** on disk node |
| Command | Role |
|---|---|
**RT_DEVICE_CTRL_BLK_SSIZEGET** | Fills *(rt_off_t *)args with bytes per sector |
**RT_DEVICE_CTRL_ALL_BLK_SSIZEGET** | Total byte size = sectors × bytes_per_sector (used by DFS v2 POSIX layer) |
Vendor-specific IOCTLs pass through **disk->ops->control(disk, blk, cmd, args)** on the volume path; on the disk path **blk is NULL**.
Defined in **blk.h** when DFS headers are available.
| Field | Meaning |
|---|---|
disk | Parent **rt_blk_disk** |
sector_start / sector_count | Slice on the physical disk (LBA range) |
partno | Index used in device name (spd / sd) |
partition | **struct dfs_partition** for DFS mount; **partition.lock** → **disk->usr_lock** |
list | Node on **disk->part_nodes** |
| Operation | Behavior |
|---|---|
| read/write | Translates to **disk->parent** at **sector_start + pos** |
| GETGEOME | Disk geometry with **sector_count** replaced by partition length |
| SYNC | **rt_device_control(&disk->parent, SYNC)** |
| ERASE / AUTOREFRESH | Allowed only when **disk->partitions <= 1** |
**disk_add_blk_dev** (blk_dev.c):
–'z'** (e.g. **sda**): volume name **sdap1** (spd).Otherwise (e.g. **mmcsd0**, **nvme0n1**): **mmcsd0p1**, **nvme0n1p2** (sd`).Each volume gets its own **rt_dm_ida_alloc(disk->ida)** slot under the same **master_id** as the disk.
When **RT_USING_DFS** and **RT_USING_POSIX_DEVIO** (and DFS v2 as implemented in-tree), **blk_dfs.c** registers file operations that:
GETGEOME** + **ALL_BLK_SSIZEGET** for file size.rt_device_control**.Mount the volume device name (not the disk) with the appropriate filesystem driver after partition probe.
These drivers embed **struct rt_blk_disk**, set **ops**, **ida**, and call **rt_hw_blk_disk_register** when media is present:
| Driver | File | Typical name | Notable rt_blk_disk fields |
|---|---|---|---|
| NVMe | nvme/nvme.c | nvme0n1, … | **parallel_io = RT_TRUE**, per-namespace disk, **max_partitions = RT_BLK_PARTITION_MAX** |
| SDIO/MMC | sdio/dev_block.c | host name / mmcsd0p* | **removable**, **max_partitions = RT_MMCSD_MAX_PARTITION**, sets geometry before register |
| SCSI disk | scsi/scsi_sd.c | sda, sdb, … | **parallel_io** from host, READ CAPACITY 10/16, **sd_ida** |
| SCSI CD-ROM | scsi/scsi_cdrom.c | optical media | Read-only style backend |
AHCI/SATA path: **ata/ahci.c** exposes SCSI devices; SD card goes through **scsi_sd** or MMC dev_block, then blk.
Details: Physical disk (rt_blk_disk).
| Mechanism | Scope |
|---|---|
**disk->usr_lock** (semaphore) | Serializes disk **read/write/sync** when **parallel_io == 0** |
**disk->lock** (spinlock) | Partition list, unregister, erase path |
**parallel_io == 1** | Disk **read/write** skip **usr_lock** — backend must be safe for concurrent I/O |
Partition volume I/O still goes through the disk node and follows the disk’s **parallel_io** / lock rules.
struct rt_blk_disk** (often embedded in driver private data).rt_blk_disk_ops**; set **ida**, name, flags (**read_only**, **removable**, **parallel_io**, **max_partitions**).rt_hw_blk_disk_register(disk)** — partition probe runs automatically.rt_device_find("sda1")**, mount DFS, or run filesystem code.rt_hw_blk_disk_unregister(disk)** after unmount — syncs, removes all volumes, checks **ref_count**.To re-scan partitions after media change, unregister, update geometry, register again (or call **rt_blk_disk_probe_partition** only if **disk->partitions == 0**).
| Topic | Guidance |
|---|---|
| Name before register | First character of **disk->parent.parent.name** must be non-NUL |
**ida** | Mandatory with **RT_USING_DM**; disk and each volume consume IDA slots |
| Probe errors | Ignored at register — check **disk->partitions** or open volumes explicitly |
**max_partitions** | Set **RT_BLK_PARTITION_NONE** to skip table parsing |
| Read-only | Omit **write** in **ops** — core forces **read_only** |
| Unmount first | **unregister** returns **-RT_EBUSY** if **ref_count > 0** |
| Erase | Disk erase IOCTL removes all partition devices first |
rt_blk_disk) — rt_blk_disk / rt_blk_disk_ops / register APIcomponents/drivers/block/blk.ccomponents/drivers/block/blk_dev.ccomponents/drivers/block/blk_partition.c