
1. 项目缘起为什么嵌入式开发者必须掌握存储介质管理在嵌入式Linux开发中无论是调试一块新的核心板还是为产品部署固件我们几乎每天都要和各种存储介质打交道。eMMC和SD卡这两者可以说是嵌入式领域的“左膀右臂”。eMMC以其高集成度和稳定性成为众多工控、物联网设备的标准内置存储而SD卡则凭借其便携性和灵活性是系统烧录、数据交换和现场升级的常客。然而很多刚入行的朋友甚至一些有经验的开发者在面对这些存储介质时常常会陷入一些误区。比如拿到一块全新的RK3562开发板想查看eMMC大小却不知道除了df -h还有什么更底层的命令或者在ESP32-P4上为LVGL配置SD卡文件系统时卡在了分区和格式化这一步更常见的是辛辛苦苦编译好的系统镜像用dd命令烧录到SD卡后设备却无法启动最后发现是分区表没弄对。这些问题的根源往往是对Linux下存储设备的管理逻辑一知半解。我们习惯了在Windows下右键点击驱动器进行格式化但在Linux的命令行世界里你需要理解从物理设备到可用文件系统的完整链条设备识别、分区操作、文件系统创建、以及最后的挂载使用。这个过程环环相扣一步出错就可能让整个存储设备“变砖”或数据丢失。网上那些“5T移动硬盘误操作后整个消失”的惨案多半就是在分区管理这一步翻了车。因此掌握fdisk,parted,mkfs,dd这些命令不是简单的背诵而是要理解它们背后的原理和适用场景。这篇内容我就结合自己多年在嵌入式Linux开发中的实际经验抛开那些笼统的“常用命令大全”带你深入eMMC和SD卡的格式化与分区管理讲清楚每一步“为什么要这么做”以及那些手册里不会写的“坑”和技巧。2. 基础认知eMMC与SD卡在Linux系统中的身份标识在动手之前我们必须先搞清楚系统是如何看待这些存储介质的。这是所有操作的基础很多错误都源于对设备节点的误解。2.1 设备节点的命名规则当你把一块SD卡插入开发板的卡槽或者你的设备已经焊接了eMMC芯片Linux内核会通过MMC子系统驱动它们并在/dev/目录下创建对应的设备节点。SD卡/TF卡通常显示为/dev/mmcblkX其中X是一个数字从0开始编号。例如第一块SD卡就是/dev/mmcblk0。eMMC对于很多SoC如RK3562、STM32MP1其内置的eMMC存储也通过MMC控制器驱动所以同样会显示为/dev/mmcblkX。你可能会有多块MMC设备比如/dev/mmcblk0是eMMC/dev/mmcblk1是插入的SD卡。顺序取决于驱动加载和硬件探测的顺序并非绝对。分区如果设备被分区每个分区会有一个pY的后缀。例如/dev/mmcblk0p1代表第一块MMC设备的第一个分区。重要提示在操作前务必使用lsblk或fdisk -l命令确认你的设备节点名。误操作了错误的设备比如把系统盘/dev/sda当成了SD卡会导致灾难性数据丢失。lsblk命令以树状图显示非常直观。2.2 如何准确查看存储介质容量与信息df -h命令查看的是已挂载文件系统的使用情况对于未格式化的全新设备或者想查看物理容量它无能为力。我们需要更底层的工具。使用fdisk -l这个命令会列出所有块设备包括硬盘、eMMC、SD卡的详细信息。你需要有sudo权限。sudo fdisk -l在输出中找到你的设备如/dev/mmcblk0你会看到类似下面的信息Disk /dev/mmcblk0: 14.6 GiB, 15634268160 bytes, 30535680 sectors Units: sectors of 1 * 512 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: dos Disk identifier: 0x12345678这里清晰地显示了总容量14.6GiB、字节数、扇区总数以及扇区大小通常是512字节但现代eMMC可能支持4K。“Disklabel type”指明了当前的分区表类型dos就是MBRgpt就是GPT。查看内核信息有时为了确认硬件连接是否正常可以查看内核消息。dmesg | tail -20插入SD卡后观察最后几条信息内核会打印出检测到的设备信息。专用工具查看eMMC信息对于像RK3562这样的芯片原厂SDK可能会提供更详细的工具比如rkflash工具包里的命令可以读取eMMC的CID、CSD寄存器信息获取硬件层面的详细规格。但在标准Linux环境下fdisk -l和lsblk已经足够。3. 分区表抉择MBR与GPT的实战选型指南创建分区第一步不是运行命令而是决定使用哪种分区表。这个选择会影响设备的兼容性、支持的分区数量以及最大容量。3.1 MBR老将的局限与适用场景MBRMaster Boot Record是历史最悠久的分区方案。优点兼容性极佳。几乎所有系统包括老旧的嵌入式设备、传统的BIOS、以及大多数U-Boot引导程序都能毫无障碍地识别MBR。缺点最多4个主分区如果你需要更多分区必须将其中一个主分区创建为“扩展分区”然后在其中创建逻辑分区。管理上稍显繁琐。2TB容量限制MBR使用32位存储扇区地址最大支持2^32个扇区。以512字节扇区计算就是2TB。对于现在动辄32GB、64GB甚至128GB的eMMC/SD卡虽然远未到2TB但这个限制是固有的。何时选择MBR你的嵌入式设备Bootloader如U-Boot比较老旧明确不支持GPT。你的系统需要被非常老旧的电脑或设备读取。你的存储设备小于2TB且分区数量不超过4个或可以通过扩展分区解决。3.2 GPT现代系统的首选GPTGUID Partition Table是新一代标准。优点近乎无限的分区数量标准支持128个分区完全够用。巨量容量支持理论上是8ZB泽字节对于未来可见的所有存储设备都绰绰有余。更安全在磁盘首尾各存一份分区表头具备CRC校验一份损坏可用另一份恢复。缺点需要系统固件UEFI或支持GPT的U-Boot和操作系统的支持。一些非常老的嵌入式环境可能无法从GPT分区启动。何时选择GPT你的设备使用U-Boot等较新的Bootloader且其编译时包含了GPT支持通常默认都有。你的eMMC/SD卡容量非常大虽然现在少见但未来可期。你计划创建多个分区例如一个boot分区、一个rootfs分区、一个数据分区、一个恢复分区等。实操心得在2024年的嵌入式Linux开发中除非遇到明确的兼容性问题我强烈建议新项目一律使用GPT分区表。它不仅更现代、更健壮而且避免了未来因分区数量或容量带来的潜在麻烦。大多数主流SoC的BSP如NXP i.MX、TI Sitara、Rockchip RK系列其U-Boot都已良好支持GPT。3.3 查看与更改分区表类型如果你拿到一个已经使用过的设备可以用fdisk -l查看当前的Disklabel type。如果你想更改它例如从MBR改为GPT请注意这将会清除设备上所有的分区和数据你需要使用parted工具。sudo parted /dev/mmcblk0 (parted) mklabel gpt # 或 msdos (即MBR) Warning: The existing disk label on /dev/mmcblk0 will be destroyed and all data on this disk will be lost. Do you want to continue? Yes/No? Yes # 确认操作数据将全部丢失 (parted) quit4. 分区实战使用fdisk与parted的详细步骤这里我们以一块32GB的SD卡/dev/mmcblk0为例演示如何创建一个典型的嵌入式系统分区布局一个512MB的FAT32格式的boot分区用于存放内核、设备树剩余空间作为ext4格式的rootfs分区。我们选择GPT分区表。4.1 方案一使用经典的fdisk工具fdisk交互直观适合简单分区。启动fdisksudo fdisk /dev/mmcblk0创建新的GPT分区表如果设备已有分区表此步会清除所有数据 在fdisk提示符下输入g然后回车创建新的GPT磁盘标签。创建第一个分区boot分区输入n创建新分区。分区号、第一个扇区、最后一个扇区通常可以直接回车用默认值分区号1从2048扇区开始。但我们需要指定大小。在Last sector提示时不要直接回车输入512M来指定分区大小为512MB。系统会询问分区类型。输入t来更改。分区1的类型代码输入1(对应EFI System在Linux中常用来作FAT boot分区) 或者直接保持默认Linux filesystem稍后格式化时指定格式也行。创建第二个分区rootfs分区再次输入n。分区号回车用2。第一个扇区直接回车会紧接上一个分区之后开始。最后一个扇区直接回车会使用所有剩余空间。分区类型保持默认的“Linux filesystem”代码83即可。检查与写入输入p打印当前的分区表布局确认无误。输入w将分区表写入磁盘并退出。这是一个不可逆的操作。退出fdisk后系统可能会提示需要重新读取分区表。你可以使用partprobe /dev/mmcblk0命令通知内核更新或者直接拔插SD卡。4.2 方案二使用更强大的parted工具parted支持更灵活的尺寸单位且适合脚本化操作。sudo parted /dev/mmcblk0 --script -- mklabel gpt sudo parted /dev/mmcblk0 --script -- mkpart primary fat32 1MiB 513MiB sudo parted /dev/mmcblk0 --script -- mkpart primary ext4 513MiB 100%--script表示非交互模式适合写入脚本。mklabel gpt创建GPT分区表。mkpart primary fat32 1MiB 513MiB创建一个主分区文件系统类型为fat32从1MiB开始到513MiB结束正好512MB大小。这里从1MiB2048扇区开始是为了满足分区对齐这对eMMC/SD卡的性能和寿命有益。mkpart primary ext4 513MiB 100%创建第二个主分区格式为ext4从513MiB开始到设备末尾。踩坑记录曾经有一次我在一个旧项目中使用fdisk默认的扇区起始位置63结果在某个eMMC上性能奇差。后来发现是分区没有对齐到4K边界。现代eMMC的擦除块Erase Block和闪存页Page大小通常是128KB或256KB的倍数分区从1MiB2048个512B扇区开始能很好地对齐这些边界避免读写放大显著提升性能和使用寿命。所以无论用fdisk还是parted都建议分区起始于1MiB边界。5. 文件系统创建为分区赋予灵魂分区只是划好了“地盘”文件系统才是管理地盘上“房屋和道路”的规则。现在我们有/dev/mmcblk0p1和/dev/mmcblk0p2两个分区。5.1 Boot分区的格式化FAT32/VFATBoot分区通常需要被Bootloader如U-Boot和PC用于拷贝内核镜像都能识别因此FAT32在Linux中称为VFAT是最通用的选择。sudo mkfs.vfat -F 32 -n BOOT /dev/mmcblk0p1-F 32强制指定为FAT32格式。对于512MB分区这是合适的。-n BOOT为分区设置一个卷标Label方便识别。在挂载后你可以通过/dev/disk/by-label/BOOT来访问它这比记设备节点更可靠。5.2 Rootfs分区的格式化ext4根文件系统需要支持Linux权限、符号链接等特性ext4是嵌入式领域最稳定、最主流的选择。sudo mkfs.ext4 -L ROOTFS /dev/mmcblk0p2-L ROOTFS设置卷标为ROOTFS。进阶考虑ext4的保留块与日志。mkfs.ext4默认会保留5%的空间给root用户对于大容量的数据分区比如一个32GB的纯数据分区这有点浪费。你可以用-m 0参数将保留比例设为0。同时日志journal是ext4用于保证数据一致性的机制但对于某些只读的rootfs或者对寿命极其敏感的存储介质可以考虑在创建时关闭日志-O ^has_journal但这会牺牲掉意外断电时的数据安全性需谨慎评估。5.3 其他可选文件系统F2FS专为闪存存储设计能减少写入放大延长eMMC/SD卡寿命在频繁写入的场景下性能优于ext4。如果你的内核支持数据分区可以考虑使用它。sudo mkfs.f2fs -l DATA /dev/mmcblk0p3SquashFS一种高度压缩的只读文件系统。常用于将最终的rootfs制作成固件镜像以节省空间。但它不能直接mkfs到块设备上而是需要先制作成镜像文件再用dd写入。6. 完整工作流从空白SD卡到可启动系统盘让我们串联起整个流程假设你要为一块树莓派或类似开发板制作一个系统盘。插入SD卡确认设备节点lsblk # 假设识别为 /dev/sdb 注意在PC的USB读卡器上SD卡可能显示为 /dev/sdX彻底清空与创建新分区表警告以下操作会清除/dev/sdb上所有数据sudo parted /dev/sdb --script -- mklabel gpt创建分区sudo parted /dev/sdb --script -- mkpart primary fat32 1MiB 513MiB sudo parted /dev/sdb --script -- set 1 boot on # 在某些架构下可能需要设置boot标志 sudo parted /dev/sdb --script -- mkpart primary ext4 513MiB 100%格式化分区sudo mkfs.vfat -F 32 -n BOOT /dev/sdb1 sudo mkfs.ext4 -L ROOTFS /dev/sdb2挂载并写入数据mkdir -p /mnt/boot /mnt/rootfs sudo mount /dev/sdb1 /mnt/boot sudo mount /dev/sdb2 /mnt/rootfs # 将你的内核镜像zImage或Image、设备树.dtb、启动脚本等拷贝到 /mnt/boot # 将你的根文件系统例如用tar解压一个rootfs.tar.gz拷贝到 /mnt/rootfs sudo tar -xzf rootfs.tar.gz -C /mnt/rootfs # 同步数据并卸载 sync sudo umount /mnt/boot /mnt/rootfs安全弹出在物理拔除SD卡前确保数据同步完成。sync命令和umount已经做了这件事。现在可以安全移除了。7. 高级管理与故障排查7.1 扩容分区填满剩余空间有时烧录完一个现成的镜像后你会发现rootfs分区只占用了镜像大小比如2GB而你的SD卡有16GB剩余空间未分配。这时需要扩容分区。步骤先调整分区边界再调整文件系统。使用parted删除原有分区并重建注意数据会丢失不适用——这是错误做法。正确做法是使用growpart和resize2fs针对ext4# 首先确保分区是最后一个分区且后面有未分配空间。 sudo parted /dev/mmcblk0 print # 使用growpart工具可能需要安装cloud-utils包 sudo growpart /dev/mmcblk0 2 # 扩展第二个分区 # 然后扩展文件系统 sudo resize2fs /dev/mmcblk0p2这个过程是在线、无损的前提是文件系统支持在线扩容ext4支持。7.2 修复损坏的分区与文件系统当系统提示“需要格式化”或挂载失败时不要急于格式化检查文件系统sudo fsck -y /dev/mmcblk0p2-y参数自动回答“yes”来修复发现的问题。对于FAT分区使用sudo fsck.vfat -a /dev/mmcblk0p1。分区表损坏或丢失如果fdisk -l看到设备容量正确但分区信息混乱或为空可能是分区表损坏。如果你有备份的分区表信息例如之前用sfdisk -d /dev/mmcblk0 part_table.backup备份过可以尝试恢复sudo sfdisk /dev/mmcblk0 part_table.backup如果没有备份且数据重要请立即停止写入操作寻求专业数据恢复工具帮助。盲目操作可能导致数据被覆盖。7.3dd命令的陷阱与正确使用dd是强大的扇区级拷贝工具常用于烧录系统镜像如.img文件。sudo dd ifsystem-image.img of/dev/mmcblk0 bs4M statusprogress convfsyncbs4M设置块大小增大可以提升拷贝速度。statusprogress显示拷贝进度较新的dd版本支持。convfsync确保数据完全写入物理设备后再返回。最大的陷阱of输出文件目标一定要指定为整个设备/dev/mmcblk0而不是某个分区/dev/mmcblk0p1。烧录.img文件会覆盖整个设备包括分区表。如果你只想更新某个分区比如boot分区应该挂载该分区后直接拷贝文件或者使用dd指定分区并注意镜像大小dd ifu-boot.img of/dev/mmcblk0p1。另一个常见错误是设备名弄错务必用lsblk再三确认。8. 嵌入式场景下的特殊考量在真实的嵌入式产品开发中eMMC/SD卡的管理不止于单板开发阶段。8.1 量产烧录效率与一致性在工厂生产时不可能对每一片eMMC都手动分区格式化。通常的做法是在开发板上准备一个“黄金样板”SD卡或eMMC包含完整的分区和系统。使用dd命令将这个“黄金样板”完整地克隆成一个镜像文件.img。sudo dd if/dev/mmcblk0 ofgolden_image.img bs4M statusprogress convfsync在量产烧录器上将这个.img文件一次性烧录到每一片设备的eMMC中。这保证了所有设备的状态绝对一致。8.2 固件升级OTA与分区设计一个健壮的OTA方案离不开巧妙的分区设计。常见的A/B系统分区布局如下boot_a,boot_b: 两个相同的boot分区存放可交替启动的内核和设备树。rootfs_a,rootfs_b: 两个相同的rootfs分区用于无缝切换和回滚。misc: 存放启动控制信息当前启动哪个槽位。persist或data: 存放用户数据独立于系统分区。OTA更新时新的系统被下载并写入非活动分区例如rootfs_b更新完成后通过修改misc分区的信息下次启动即切换到新分区。即使新系统启动失败也可以回滚到旧分区。这种设计强烈依赖于你对分区管理的熟练掌握。8.3 文件系统只读化与数据保护很多嵌入式设备要求系统分区在运行时为只读以防止意外修改或断电损坏。对于ext4可以在挂载时指定ro参数或者更彻底地在制作根文件系统镜像时将其制作为SquashFS格式然后通过overlayfs在data分区上叠加一个可读写的层。这需要对内核和启动流程有更深的理解。管理Linux下的eMMC和SD卡是一项从硬件识别到文件系统、再到量产和升级的系统性工程。核心在于理解每个命令背后的意图和影响并在动手前明确自己的目标。记住那句老话“在按下回车键之前永远要 double-check 设备节点。”尤其是在生产环境中一次误操作的成本可能是巨大的。希望这些从实际项目中总结出的步骤、原理和坑点能让你在下次面对存储介质时多一份从容少一份焦虑。