在嵌入式Linux开发中,经常需要对OpenWrt固件的分区布局进行调整。最近我在为某工业路由器项目定制固件时,就遇到了需要新增数据存储分区的需求。经过对OpenWrt构建系统的深入研究,找到了通过修改镜像生成脚本实现分区扩展的可靠方案。下面将完整分享我的实现过程和关键细节。
提示:本方案基于OpenWrt 23.05版本,采用源码编译方式。不同版本可能存在差异,建议先备份原始文件。
OpenWrt的固件镜像生成是一个多阶段过程:
gen_image_generic.sh脚本打包最终镜像核心的镜像生成工作由scripts/gen_image_generic.sh脚本完成,它主要负责:
ptgen是OpenWrt自带的轻量级分区表生成工具,具有以下特点:
其源代码位于staging_dir/host/bin/ptgen,编译时会被自动构建。相比传统的fdisk或parted,ptgen更适合自动化构建环境,因为它:
找到scripts/gen_image_generic.sh文件,定位到ptgen调用部分。原始代码通常类似:
bash复制set $(ptgen -o "$OUTPUT" -h $head -s $sect ${GUID:+-g} \
-t "${KERNELPARTTYPE}" -p "${KERNELSIZE}m${PARTOFFSET:+@$PARTOFFSET}" \
-t "${ROOTFSPARTTYPE}" -p "${ROOTFSSIZE}m" \
${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE} ${GUID:+-G $GUID})
要新增一个32MB的Linux分区(类型83),修改为:
bash复制set $(ptgen -o "$OUTPUT" -h $head -s $sect ${GUID:+-g} \
-t "${KERNELPARTTYPE}" -p "${KERNELSIZE}m${PARTOFFSET:+@$PARTOFFSET}" \
-t "${ROOTFSPARTTYPE}" -p "${ROOTFSSIZE}m" \
-t 83 -p 32m \ # 新增分区参数
${ALIGN:+-l $ALIGN} ${SIGNATURE:+-S 0x$SIGNATURE} ${GUID:+-G $GUID})
ptgen会返回各分区的偏移和大小信息,原始脚本只处理前4个参数(内核和根分区)。新增分区后,需要扩展参数解析:
bash复制KERNELOFFSET="$(($1 / 512))" # 单位转换:字节→扇区
KERNELSIZE="$2"
ROOTFSOFFSET="$(($3 / 512))"
ROOTFSSIZE="$(($4 / 512))"
# 新增分区参数处理
EXPANDOFFSET="$(($5 / 512))" # 新分区偏移
EXPANDSIZE="$6" # 新分区大小
在脚本中找到文件系统创建部分,添加对新分区的处理。以ext4格式为例:
bash复制# 创建ext4文件系统
make_ext4fs -L expand -l "$EXPANDSIZE" "$OUTPUT.expand"
# 将文件系统写入镜像
dd if="$OUTPUT.expand" of="$OUTPUT" bs=512 seek="$EXPANDOFFSET" conv=notrunc
# 清理临时文件
rm -f "$OUTPUT.expand"
关键参数说明:
-L expand:设置卷标为"expand"-l "$EXPANDSIZE":指定文件系统大小bs=512:设置块大小为512字节(扇区大小)seek="$EXPANDOFFSET":指定写入位置执行以下命令重新生成镜像:
bash复制make target/linux/install V=s
成功编译后,可以在日志中看到类似输出:
code复制Image file: openwrt-23.05-x86-64-generic-ext4-combined.img
Kernel: offset=2048, size=8192
RootFS: offset=10240, size=262144
Expand: offset=272384, size=65536 # 新增分区信息
现象:镜像刷入设备后无法启动
排查:
bash复制fdisk -l output/image.img # 检查分区表
解决:
现象:make_ext4fs报错
排查:
bash复制# 检查可用空间
df -h /tmp
# 检查make_ext4fs版本
make_ext4fs -V
解决:
现象:系统启动后看不到新分区
排查:
bash复制dmesg | grep mmcblk # 查看块设备日志
lsblk # 列出块设备
解决:
现代存储设备通常需要1MB对齐以获得最佳性能:
bash复制# 在ptgen参数中添加
-l 1048576 # 1MB对齐
通过环境变量控制分区大小,增加灵活性:
bash复制# 在脚本开头定义默认值
: ${EXPAND_SIZE:=32m}
# 调用ptgen时使用
-t 83 -p "$EXPAND_SIZE"
编译时可覆盖默认值:
bash复制EXPAND_SIZE=64m make target/linux/install
如需添加多个分区,可继续扩展ptgen参数:
bash复制set $(ptgen ... \
-t 83 -p 32m \ # 分区1
-t 83 -p 64m \ # 分区2
...)
并相应增加参数解析:
bash复制PART1_OFFSET="$(($5 / 512))"
PART1_SIZE="$6"
PART2_OFFSET="$(($7 / 512))"
PART2_SIZE="$8"
分区规划原则:
文件系统选型:
自动化集成:
bash复制# 在package/base-files/files/lib/upgrade/common.sh中
# 添加对新分区的处理
export EXPAND_DEV="/dev/mmcblk0p3"
生产环境验证:
这个方案已经在我负责的多个工业级路由器项目中得到验证,最长的稳定运行时间已超过400天。关键是要确保分区边界计算准确,并选择适合存储介质特性的文件系统。