3. 分区基本概念

在嵌入式系统里,分区(Partition)并不是一个抽象名词,而是存储介质上一段被明确划定、可被引导程序与操作系统共同识别的连续逻辑区域。它把一块物理 Flash、eMMC 或 UFS 切分成若干职责单一的“容器”,让引导、内核、根文件系统、配置、日志、恢复镜像各居其位。理解分区,本质上是在理解“地址边界”和“职责边界”如何同时被定义。

分区设计的核心目标只有三句话:让启动链能找到该找的东西;让升级与恢复不会互相破坏;让剩余空间与寿命满足产品生命周期。

一、分区定义与分区表

分区定义包含四个要素:起始偏移、大小、类型标识、名称。这四个要素被记录在分区表中。嵌入式常见的分区表形态有三类:

  • MBR/GPT:多用于 eMMC、SSD、UFS 等块设备,GPT 支持更多分区与 64 位 LBA,是当前主流。
  • MTD 分区表:用于裸 NAND/NOR,通常在设备树或内核命令行中通过 mtdparts 描述。
  • 厂商自定义表:如 Rockchip 的 parameter、Allwinner 的 sys_config,本质是引导阶段的偏移-长度映射。

无论哪种形式,分区表都必须先于文件系统被解析。因此它通常位于存储介质的固定位置,并由 BootROM 或一级引导程序读取。下面是一个典型的分区表片段:

# mtdparts 示例
mtdparts=nand0:1M(boot),4M(kernel),8M(rootfs),2M(config),-(data)

# GPT 分区表示例(sgdisk -p)
Number  Start (sector)  End (sector)  Size    Code  Name
   1        2048          4095       1.0 MiB  8300  boot
   2        4096         12287       4.0 MiB  8300  kernel
   3       12288         28671       8.0 MiB  8300  rootfs
   4       28672         32767       2.0 MiB  8300  config
   5       32768        262143     112.0 MiB  8300  data

二、分区类型与命名

分区类型决定“这块区域放什么”,命名则决定“系统如何引用它”。类型通常分为引导类、系统类、数据类、恢复类与保留类。命名应遵循可读、稳定、可脚本化的原则,避免使用 partition1 这类无语义名称。

类型典型名称内容是否可写
引导类boot / spl / ubootBootROM 后的一级、二级引导升级时写
系统类kernel / rootfs内核镜像、根文件系统只读优先
配置类config / env环境变量、设备参数可写
数据类data / userdata用户数据、日志可写
恢复类recovery / backup恢复镜像、出厂备份受控写

命名还要与设备节点对应。例如 Linux 下 eMMC 常见为 /dev/mmcblk0p1,MTD 下为 /dev/mtdblock3,U-Boot 中则通过 mmcblk0:3 或分区名引用。命名一旦确定,升级脚本、OTA 包和恢复流程都应统一使用同一套名称。

三、分区对齐

对齐是分区设计中最容易被忽视、却直接影响性能与寿命的参数。Flash 的擦除块、eMMC 的写保护组、UFS 的逻辑单元都有最小操作粒度。若分区起始地址未对齐,一次写入可能跨越两个物理块,引发读-改-写放大。

  • eMMC/UFS:起始扇区通常按 1 MiB 或 4 MiB 对齐,兼顾 GPT 与闪存页。
  • NAND:起始偏移按擦除块大小对齐,常见 128 KiB 或 256 KiB。
  • NOR:按扇区大小对齐,常见 4 KiB 或 64 KiB。
判断对齐是否合理,可以看分区起始偏移能否被擦除块大小整除。不能整除时,即使容量足够,也应调整前一个分区大小。

四、分区大小规划原则

分区大小不是“把总容量分完”的算术题,而是对增长、冗余和坏块管理的预留。建议遵循以下原则:

  1. 引导区留双份:A/B 双备份或主备引导,防止升级断电变砖。
  2. 内核与根文件系统按版本增长预留 20%~30%,避免每次裁剪都改分区表。
  3. 配置区独立且可写,与只读系统区隔离,恢复出厂设置时只擦配置区。
  4. 数据区放最后,便于动态扩展或按剩余空间自动计算。
  5. 保留区不省略:用于坏块替换、日志或未来功能,通常留总容量 5%~10%。

下面是一段根据总容量自动计算 data 分区大小的脚本思路:

total=4096          # MiB
boot=8; kernel=16; rootfs=512; config=8; recovery=64
reserved=$((total/20))          # 预留 5%
data=$((total - boot - kernel - rootfs - config - recovery - reserved))
echo "data=${data}MiB"

五、案例与常见误区

某工业网关使用 4 GiB eMMC,最初分区为 boot 4 MiB、kernel 8 MiB、rootfs 256 MiB、data 剩余。量产后发现内核升级后体积超过 8 MiB,且 rootfs 因加入调试工具接近上限,只能返工改分区表。复盘后调整为:boot 双份各 4 MiB、kernel 16 MiB、rootfs 512 MiB、config 8 MiB、recovery 64 MiB、data 动态剩余,并统一按 1 MiB 对齐。

常见误区:把分区表写在文件系统内部;用未对齐的偏移追求“刚好分完”;把配置与数据混在同一可写分区;只规划当前版本大小而不留增长空间。这些问题在样机阶段往往不暴露,量产升级时才集中爆发。
嵌入式存储分区布局与对齐关系 物理存储介质(eMMC / NAND / NOR) 擦除块 / 页 / 逻辑单元决定最小对齐粒度 boot 引导 双份 kernel 内核 预留增长 rootfs 根文件系统 只读优先 config 配置 可写 recovery 恢复 受控写 data 用户数据 / 日志 动态剩余 起始偏移 1 MiB 对齐 擦除块对齐 独立可写 按剩余空间计算 分区表:记录起始偏移、大小、类型、名称 → 引导程序解析 → 内核挂载 → 升级脚本引用

把分区定义、分区表、类型、命名、对齐与大小规划放在一起看,会发现它们共同构成一条从物理介质到系统职责的映射链。分区表是契约,对齐是性能底线,大小规划是生命周期保障。只有三者同时成立,后续的引导、升级与恢复才有稳定的基础。