![]() |
RT-Thread RTOS
An open source embedded real-time operating system
|
rt_blk_disk) **struct rt_blk_disk** is the physical backing store: one contiguous LBA space implemented by your driver’s **rt_blk_disk_ops**. The blk core wraps it as an **rt_device**, then creates volume children — see Block layer (blk) and Disk partition probing.
Implementation: **components/drivers/block/blk.c**. Header: **components/drivers/include/drivers/blk.h**.
Same documentation pattern as **documentation/6.components/device-driver/ata/ata.md**: fill structures before **rt_hw_blk_disk_register**, implement **ops**, then let the core attach partitions and DFS-facing devices.
| Member | Owner | Rule / meaning |
|---|---|---|
**parent** | Caller | Embedded **rt_device**. Name must be set before register (first char of **parent.parent.name ≠ \0**). |
**ops** | Caller | Required; see **struct rt_blk_disk_ops** below. |
**ida** | Caller (RT_USING_DM) | Non-NULL; shared with all volume children for **rt_dm_ida_alloc**. |
**read_only** | Caller / core | If **ops->write == NULL**, core sets **read_only = RT_TRUE**. |
**parallel_io** | Caller | **RT_TRUE**: disk read/write skip **usr_lock** (NVMe uses this). |
**removable** | Caller | Hint for removable media (e.g. SDIO sets from host). |
**max_partitions** | Caller | Cap for parsers; **RT_BLK_PARTITION_NONE** disables probing. **RT_BLK_PARTITION_MAX** = unlimited. |
**partitions** | Core | Count of registered **rt_blk_device** nodes. |
**part_nodes** | Core | List of **struct rt_blk_device**. |
**lock** | Core | Spinlock for list / unregister / erase. |
**usr_lock** | Core | Semaphore (prio) serializing I/O when not **parallel_io**. |
**__magic** | Core | Set to **RT_BLK_DISK_MAGIC** at register. |
| Callback | Required? | Contract |
|---|---|---|
**read** | Yes (practical) | **sector**, **sector_count** in 512-byte sectors unless **getgeome** says otherwise. Return sectors read or **< 0** error. |
**write** | Optional | **NULL** → disk read-only. Same addressing as **read**. |
**getgeome** | Yes (practical) | Fill **sector_count**, **bytes_per_sector**, **block_size**. Used by partition code and DFS. |
**sync** | Optional | Flush caches; called on unregister and **RT_DEVICE_CTRL_BLK_SYNC**. |
**erase** | Optional | Whole-device erase; disk IOCTL may remove partitions first. |
**autorefresh** | Optional | **RT_DEVICE_CTRL_BLK_AUTOREFRESH** (e.g. SD auto refresh). |
**control** | Optional | Vendor IOCTLs; **blk** is **NULL** on raw disk, non-NULL on volume forwarding. |
getgeome()->bytes_per_sector** must match what **read/write** use.getgeome()->sector_count** is full device capacity in sectors.parallel_io**, **read/write** may overlap — use driver-internal locking or queue depth as needed.| Step | Action |
|---|---|
| 1 | Validate **disk**, **ops**, name, **ida** (DM). |
| 2 | **rt_dm_ida_alloc(disk->ida)** for the disk device id. |
| 3 | Init **usr_lock**, **part_nodes**, **lock**. |
| 4 | Hook **blk_ops** or **blk_parallel_ops** on **parent**. |
| 5 | If **!ops->write** → **read_only = 1**. |
| 6 | **device_set_blk_fops**, **rt_device_register** with RD/WR flags. |
| 7 | **rt_blk_disk_probe_partition(disk)** — errors ignored. |
Return: register error only; partition failure does not fail register.
| Op | parallel_io == 0 | parallel_io == 1 |
|---|---|---|
| read/write | Under **usr_lock** | Direct **ops->read/write** |
| control | **blk_control** → **ops** | Same |
**RT_DEVICE_CTRL_BLK_PARTITION** on the disk node returns **-RT_EINVAL** (use volume devices).
| Step | Action |
|---|---|
| 1 | **ref_count > 0** → **-RT_EBUSY** |
| 2 | **ops->sync** if present |
| 3 | **blk_remove_all** — unregister every **rt_blk_device** |
| 4 | **rt_dm_ida_free** for disk id, **rt_device_unregister** |
Unmount DFS / close handles before unregister.
| API | Role |
|---|---|
**rt_blk_disk_probe_partition(disk)** | Re-run parsers if **partitions == 0**; see Disk partition probing |
**rt_blk_disk_get_capacity(disk)** | **getgeome** → **sector_count** |
**rt_blk_disk_get_logical_block_size(disk)** | **getgeome** → **bytes_per_sector** |
Per namespace:
rt_dm_dev_set_name(&ndev->parent.parent, "%sn%u", nvme->name, nsid)**parallel_io = RT_TRUE**, **ops = &nvme_blk_ops**, **ida = &nvme_ida**max_partitions = RT_BLK_PARTITION_MAX**rt_hw_blk_disk_register(&ndev->parent)** after identifysector_count**, **bytes_per_sector**, **block_size**mmcsd_set_blksize** before registerremovable**, **max_partitions = RT_MMCSD_MAX_PARTITION**host->name** → volumes **hostp1** stylert_dm_dev_set_name(..., "sd%c%c", letter_name(sd_id))** — names like **sda**parallel_io** from SCSI hostida = &scsi_sd_ida**Same blk registration pattern; typically read-only media (**write** omitted or read-only flag).
RT_DM_IDA_INIT** per disk family (e.g. **scsi_sd_ida**, **nvme_ida**, **sdio_ida**).disk->ida** before register.rt_dm_dev_set_name(&disk->parent.parent, ...)**.rt_blk_device** yourself unless you bypass **blk_put_partition**.| Topic | Guidance |
|---|---|
| DMA / buffers | Bounce in **ops** if callers pass non-DMA-safe pointers |
| Capacity change | Unregister, update geometry, register again |
| Hotplug | Remove card → **rt_hw_blk_disk_unregister**; insert → register fresh |
| GPT + DFS | Enable both Kconfig parsers; EFI runs first in **partition_list[]** |
| Custom IOCTL | Implement **control(disk, blk, cmd, args)**; forward unknown cmds from **blk_control** default case |
blk) — application API and volume layercomponents/drivers/block/blk.ccomponents/drivers/include/drivers/blk.h