ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

RT-Thread 块设备磁盘分区探测:`rt_blk_disk` 分区表解析与 `rt_blk_device` 卷注册机制

RT-Thread 块设备磁盘分区探测:`rt_blk_disk` 分区表解析与 `rt_blk_device` 卷注册机制 操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载本篇技术指南以 RT-Thread 块设备框架的磁盘分区探测为主题围绕 partitions.md 文档展开磁盘驱动调用rt_hw_blk_disk_register完成注册后核心层会通过rt_blk_disk_probe_partition读取磁盘上的分区布局GPT/EFI 或传统 DFS 分区表并为每个分区片注册一个独立的rt_blk_device卷设备。读完本文你将掌握分区探测的完整调用链、两个内置解析器的校验与启用方式、卷设备命名规则以及格式化后重新探测、禁用分区表等实战操作要领。一、分区探测的整体架构RT-Thread 把整块磁盘与磁盘上的卷建模为两层设备struct rt_blk_disk代表物理磁盘如sda、mmcsd0、nvme0n1由底层驱动创建并通过rt_hw_blk_disk_register注册struct rt_blk_device代表磁盘上的一个分区片卷即用户最终挂载文件系统、进行读写操作的对象。两者的衔接点正是分区探测流程磁盘注册完成后核心层自动调用rt_blk_disk_probe_partition读取磁盘上的分区布局每解析出一个分区片就通过blk_put_partition创建一个rt_blk_device并注册为独立设备。核心实现在 blk_partition.c两个分区解析器位于 partitions/ 目录。在 blk.c 中可以看到自动调用点rt_hw_blk_disk_register的末尾约第 339 行直接调用rt_blk_disk_probe_partition(disk)因此对绝大多数正常驱动而言分区探测是全自动的驱动无需额外处理。二、启用哪些分区表Kconfig 配置分区解析器通过 Kconfig 开关编译进partition_list[]解析器数组。两个选项定义在 partitions/Kconfig并被 block/Kconfig 以rsource partitions/Kconfig引入。配置项对应源文件作用RT_BLK_PARTITION_EFIpartitions/efi.c解析 Protective MBR GPTUEFI 风格默认 yRT_BLK_PARTITION_DFSpartitions/dfs.c解析扇区 0 上的 DFS 传统分区表依赖RT_USING_DFS默认 y两个选项可以同时开启。在 blk_partition.c 中partition_list[]的组装顺序固定为EFI 在前、DFS 在后static rt_err_t (*partition_list[])(struct rt_blk_disk *) { #ifdef RT_BLK_PARTITION_EFI efi_partition, #endif #ifdef RT_BLK_PARTITION_DFS dfs_partition, #endif };探测时按顺序逐个调用解析器第一个返回 0成功的解析器胜出后续不再尝试。这解释了原文档给出的工程建议若磁盘上存在 GPT应保证 EFI 解析器可用不要依赖 DFS 解析 GPT 介质。三、rt_blk_disk_probe_partition探测主流程rt_blk_disk_probe_partition见 blk_partition.c 第 103 行是整个探测机制的入口其执行逻辑可用下表概括步骤行为1disk NULL→ 返回-RT_EINVAL2disk-partitions ! 0→ 直接返回成功已探测过避免重复建卷3max_partitions RT_BLK_PARTITION_NONE→ 返回-RT_EEMPTY明确禁用分区表4循环调用partition_listi5某解析器返回-RT_ENOMEM→ 中止探测返回-RT_ENOMEM6某解析器返回0→ 探测成功停止7无解析器匹配 → 创建整盘卷blk_put_partition(disk, RT_NULL, 0, total_sectors, 0)关键设计在第 7 步即使磁盘是空白盘、或分区布局无法被任何解析器识别探测仍会创建一个覆盖整个磁盘的单卷partno 0保证至少有一个可挂载的设备可用。对应的源码分支在 blk_partition.c 第 145–151 行if ((err err ! -RT_ENOMEM) || disk-partitions 0) { /* No partition found */ rt_size_t total_sectors rt_blk_disk_get_capacity(disk); err blk_put_partition(disk, RT_NULL, 0, total_sectors, 0); }四、blk_put_partition卷设备的创建与注册解析器最终都汇聚到blk_put_partition见 blk_partition.c 第 27 行其完整流程如下阶段动作分配rt_calloc一个struct rt_blk_device初始化blk_dev_initialize(blk)填充设备操作集读/写/控制范围记录sector_start start、sector_count count、partnoDFS 元数据填充partition.offset、partition.size并令partition.lock disk-usr_lock与磁盘共用用户锁注册disk_add_blk_dev(disk, blk)→ 内部执行rt_device_register并把设备挂入磁盘的part_nodes链表计数disk-partitions卷设备的读写实现位于 blk_dev.cblk_dev_read/blk_dev_write会先校验扇区偏移与数量是否落在[sector_start, sector_start sector_count]区间内然后将访问地址平移sector_start后转发给底层磁盘设备——这是分区卷与整盘设备在地址空间上的核心差异。控制台日志对非dfs类型的分区blk_put_partition会通过rt_kprintf打印分区信息分区索引、以字节计的开始偏移以及换算成 KB/MB/GB 的人类可读容量。例如打印found part[0], begin: 1048576, size: 512.0MB。换算逻辑位于 blk_partition.c 第 34–57 行start * ssz得到字节偏移count 11得到 MB 数再按size_mb 10进位到 GB。失败处理若中途出错典型为-RT_ENOMEM函数会通过LOG_E记录错误包含磁盘名、分区类型、索引、start/count 与错误字符串并释放已分配的struct rt_blk_device后返回错误码。注意disk-partitions只在disk_add_blk_dev成功后才递增因此失败路径不会留下半注册状态。五、EFI / GPT 解析器partitions/efi.cGPT 解析器是全功能实现支持主/备 GPT 头、CRC 校验、混合 MBR 检测等。5.1 启动参数force_gptefi.c顶部通过INIT_CORE_EXPORT(force_gpt_setup)注册了一个自动初始化函数当编译选项RT_USING_OFW开启时它调用rt_ofw_bootargs_select(gpt, 0)读取启动参数gpt。一旦该参数被设置即使 Protective MBR 校验结果不明确例如磁盘容量被驱动误报、MBR 字段异常也会强制继续尝试 GPT 探测并允许在 Primary GPT 失效时直接使用 Alternate GPT。这对从大盘 dd 镜像到小盘等场景尤为重要。5.2 校验流程源码级对应find_valid_gpt/is_gpt_valid见 efi.c 第 376 行起完整流程为读取 LBA 0检查 Protective MBR分区类型须为0xEEEFI_PMBR_OSTYPE_EFI_GPT起始 LBA 必须等于 1GPT_PRIMARY_PARTITION_TABLE_LBA若还存在其他非 0xEE/0x00 类型则判定为 Hybrid MBRGPT_MBR_HYBRID。读取 Primary GPT 头LBA 1或走force_gpt路径直接读。验证头字段签名必须为EFI PARTGPT_HEADER_SIGNATURE 0x5452415020494645用efi_crc32校验头 CRC校验时先把header_crc32清零再计算比对后恢复原值校验my_lbastart_lba必须等于读取位置校验first_usable_lba/last_usable_lba不超出磁盘容量last_lba()定义为rt_blk_disk_get_capacity(disk) - 1校验sizeof_partition_entry与gpt_entry结构体大小一致。加载分区条目数组alloc_read_gpt_entries并校验条目数组 CRCpartition_entry_array_crc32。逐条创建卷对每个有效条目调用blk_put_partition(disk, gpt, start, size, partno)其中size ending_lba - starting_lba 1partno即条目索引。无效条目Type GUID 为全零、或起止 LBA 超过盘尾会被跳过参考is_pte_valid。此外compare_gpts会对比主备 GPT 头的一致性start_lba/alternate_lba 互指、usable 范围、disk_guid、条目数量与 CRC 等任何不一致都会以LOG_W告警并提示使用 GNU Parted 修复 GPT 错误。5.3 扇区大小约定整个解析过程中所有 LBA 运算都基于rt_blk_disk_get_logical_block_size(disk)返回的逻辑块大小并且要求该值 ≥ 512 且为 512 的整数倍见read_lba的检查。因此驱动上报的 logical block size 必须与getgeome返回的几何信息保持一致否则读写错位会导致解析失败。六、DFS 分区解析器partitions/dfs.cDFS 解析器是 RT-Thread 传统文件系统分区表的兼容路径实现见 dfs.c流程为按逻辑块大小分配一个扇区缓冲区调用disk-ops-read(disk, 0, sector, 1)读取第 0 扇区校验扇区末尾的 MBR 签名偏移0x1FE处必须为0x55、0x1FF处必须为0xAA否则判定为无分区并返回-RT_ERROR循环调用dfs_filesystem_get_partition(part, sector, i)i disk-max_partitions逐条解析对每条解析结果做容量边界检查part_start不得超出磁盘容量、part.size不得为 0、part_end不得越过盘尾越界条目跳过并打LOG_W告警调用blk_put_partition(disk, dfs, part.offset, part.size, i)创建卷。注意 DFS 解析器在blk_put_partition内部不会打印found part[...]日志因为type为dfs被排除同时它要求同时开启RT_USING_DFS与RT_BLK_PARTITION_DFS两个选项Kconfig 中depends on RT_USING_DFS。七、探测后的卷命名规则卷设备的命名由disk_add_blk_dev决定见 blk_dev.c 第 176 行。命名格式取决于磁盘名最后一个字符的类型磁盘名结尾命名格式示例磁盘卷设备示例字母a–z%s%dsdasdap1、sdap2数字或其他字符%sp%dmmcsd0、nvme0n1mmcsd0p1、nvme0n1p2判定逻辑在 blk_dev.c 第 202–209 行disk_name[rt_strlen(disk_name) - 1] a时采用%sp%d格式否则采用%s%d格式。卷设备的type为RT_Device_Class_Block注册标志继承磁盘的RT_DEVICE_FLAG_RDWR。应用层通过RT_DEVICE_CTRL_BLK_PARTITIONIOCTL 可从卷设备取回partition.offset/partition.size等元数据见blk_dev_control。八、何时重新触发探测场景推荐做法正常驱动注册无需干预rt_hw_blk_disk_register末尾自动探测介质刚格式化先注销磁盘再重新注册或仅在disk-partitions 0时调用rt_blk_disk_probe_partition禁用分区表将disk-max_partitions设为RT_BLK_PARTITION_NONE探测直接返回-RT_EEMPTY且不会创建整盘卷RAM 盘 / 单卷介质只要未禁用分区仍会得到一个partno 0的整盘卷如需完全手动管理卷请自行设置max_partitions代码中的调用点blk.crt_hw_blk_disk_register末尾约第 339 行自动调用rt_blk_disk_probe_partition这是主要调用点驱动热插拔后手动调用仓库中少见一般建议注销磁盘后重新走注册流程以保证状态一致。需要说明的是重新探测不支持在已有卷的情况下进行——rt_blk_disk_probe_partition看到disk-partitions ! 0会直接成功返回而不做任何事。若确实需要重扫必须先注销磁盘rt_hw_blk_disk_unregister它会依次移除所有卷设备。九、分区探测与磁盘 IOCTL 的交互卷设备blk_dev_control见 blk_dev.c 第 66 行对多分区磁盘有几处特殊处理IOCTL多分区磁盘上的行为ERASE / AUTOREFRESH作用于卷若disk-partitions 1返回-RT_EIO防止卷级擦除破坏相邻分区ERASE作用于整盘在底层ops-erase之前先移除磁盘上所有卷设备GETGEOME作用于卷sector_count替换为分区自身的sector_count其余几何参数仍来自磁盘getgeomePARTITION作用于卷返回该卷的partition.offset/partition.size/lock元数据SYNC / SSIZEGET透传给底层磁盘或按卷设备处理这种设计保证了在多分区介质上对某个卷执行擦除操作不会被错误地下发到整盘避免误伤相邻分区的文件系统。十、驱动 / BSP 移植速查主题建议解析器顺序EFI 必须排在 DFS 之前只要磁盘上有 GPT 就不要依赖 DFS 解析max_partitions取值SDIO 驱动传入RT_MMCSD_MAX_PARTITIONNVMe 使用RT_BLK_PARTITION_MAX两者均为驱动侧可配置的宏空卡处理即使空白盘探测也会创建覆盖全盘的卷partno 0挂载时可能需要先建立有效文件系统重新探测已有卷时不支持原地重扫必须先注销磁盘会卸载其上已挂载的文件系统再重新注册自定义分区布局两种途径向partition_list[]追加自定义解析器返回 0 表示成功、-RT_ENOMEM表示中止或在驱动代码中直接调用blk_put_partition手动建卷延伸阅读卷设备rt_blk_device的使用与命名约定blk.md磁盘设备rt_blk_disk注册与生命周期disk.md分区探测核心实现blk_partition.cGPT 解析器efi.c 及其头文件 efi.hDFS 解析器dfs.c分区表 Kconfigpartitions/Kconfig卷设备操作集与命名blk_dev.c赞分享操作系统嵌入式物联网嵌入式OSRTOS【免费下载链接】rt-threadRT-Thread is an open source IoT Real-Time Operating System (RTOS). https://rt-thread.github.io/rt-thread/项目地址https://gitcode.com/gh_mirrors/rt/rt-thread点击查看免费下载相关推荐RT-Thread 块设备子系统blk深度解析从 rt_blk_disk 注册、分区扫描到 sda1 卷设备访问RT Thread 块设备子系统blk深度解析从 rt_blk_disk 注册、分区扫描到 sda1 卷设备访问 导读 RT Thread 的 blkB操作系统嵌入式物联网嵌入式OSRTOSRT-Thread 物理磁盘驱动编写指南深入 struct rt_blk_disk 与 rt_blk_disk_opsRT Thread 物理磁盘驱动编写指南深入 struct rt_blk_disk 与 rt_blk_disk_ops RT Thread 的 blk 块设备操作系统嵌入式物联网嵌入式OSRTOSWinBtrfs无分区卷直接挂载磁盘设备Btrfs方案WinBtrfs无分区卷直接挂载磁盘设备Btrfs方案 痛点解析传统分区挂载的三大困境 你是否曾面临这些场景 外接硬盘显示为未分配空间却包含Btrfs驱动开发存储上一篇ClickHouse v25.5.5.19-stable 技术解读Keeper ACL 治理增强、HTTP 响应头兼容与稳定性修复下一篇如何快速实现离线音频转录Buzz桌面应用完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表