SigmaStar SSD202 openwrt 系统下ubi根文件系统挂载过程
關于UBI介紹可以參考官方文檔
http://www.linux-mtd.infradead.org/doc/ubifs.html
下面是一張簡介圖,大概的介紹就是UBIFS依賴kernel UBI子系統,運行在MTD設備之上,應用上UBI可做自己的分區管理
SSD202的簡介可以參考我另一篇博文
目前國內有幾個廠家在推廣使用且出了相關的核心板,我目前使用的是啟明云端的開發板(啟明云端已移植好openwrt系統,我在此之上進行相關分析)
首先看系統分區:
root@wireless-tag:/# cat /proc/mtd dev: size erasesize name mtd0: 00060000 00020000 "IPL0" mtd1: 00060000 00020000 "IPL1" mtd2: 00060000 00020000 "IPL_CUST0" mtd3: 00060000 00020000 "IPL_CUST1" mtd4: 000c0000 00020000 "UBOOT0" mtd5: 000c0000 00020000 "UBOOT1" mtd6: 00060000 00020000 "ENV0" mtd7: 00020000 00020000 "KEY_CUST" mtd8: 00060000 00020000 "LOGO" mtd9: 00060000 00020000 "wtinfo" mtd10: 03000000 00020000 "ubi" mtd11: 03000000 00020000 "ubi2" mtd12: 09a80000 00020000 "opt"Openwrt系統有個特點,Kernel和ROOTFS是一起打包的,且支持overlayfs,對應的分區為UBI,UBI2是備份分區,
其使用地方有兩個:在uboot啟動失敗時使用和sysupgrade升級系統時使用,具體詳細的分析在此不展開,后面有空再單獨介紹
分析一個系統或者一個模塊的執行過程,運行日志是很好的切入點,首先我們看下UBI相關的運行日志
[ 1.971721] UBI: auto-attach mtd10 [ 1.974967] ubi0: attaching mtd10 [ 2.021832] UBI: EOF marker found, PEBs from 65 will be erased [ 2.097352] ubi0: scanning is finished [ 2.125345] ubi0: volume 2 ("rootfs_data") re-sized from 9 to 277 LEBs [ 2.132520] ubi0: attached mtd10 (name "ubi", size 48 MiB) [ 2.137870] ubi0: PEB size: 131072 bytes (128 KiB), LEB size: 126976 bytes [ 2.144726] ubi0: min./max. I/O unit sizes: 2048/2048, sub-page size 2048 [ 2.151529] ubi0: VID header offset: 2048 (aligned 2048), data offset: 4096 [ 2.158487] ubi0: good PEBs: 384, bad PEBs: 0, corrupted PEBs: 0 [ 2.164483] ubi0: user volume: 3, internal volumes: 1, max. volumes count: 128 [ 2.171724] ubi0: max/mean erase counter: 1/0, WL threshold: 4096, image sequence number: 263505868 [ 2.180769] ubi0: available PEBs: 0, total reserved PEBs: 384, PEBs reserved for bad PEB handling: 40 [ 2.190013] ubi0: background thread "ubi_bgt0d" started, PID 504 [ 2.205930] block ubiblock0_1: created from ubi0:1(rootfs) [ 2.211260] ubiblock: device ubiblock0_1 (rootfs) set to be root filesystem其核心地方有3個
第一,UBI: auto-attach mtd10, auto-attach 名為自動掛載,理解這個之前我們得先看一下cmdline關于rootfs相關的部分“rootfstype=squashfs,ubifs rootwait=1”,啟動參數中只指定了類型,沒有指定rootdev,所以此處的auto-attach尤其重要
第二,ubi0: user volume: 3, internal volumes: 1, max. volumes count: 128,說明ubi0有3個卷,此處為ubifs的一個特點,也跟openwrt ubi.img制作的方式有關,3個卷分別為kernel,rootfs和rootfs_data(也就是overlay)
第三,ubiblock: device ubiblock0_1 (rootfs) set to be root filesystem, 即ubi0的rootfs卷被掛載為系統的rootfs
從這3處初略可以看出系統是如何掛載哪里的rootfs,大致就是自動找到有roofs的ubi分區,然后自動attach,接著將其掛載為系統rootfs
下面針對這3個地方進行詳細分析:
一、自動掛載ubi分區UBI: auto-attach mtd10
其主要機制從一個patch文件即可看出 490-ubi-auto-attach-mtd-device-named-ubi-or-data-on-boot.patch
From: Daniel Golle <daniel@makrotopia.org> Subject: ubi: auto-attach mtd device named "ubi" or "data" on bootSigned-off-by: Daniel Golle <daniel@makrotopia.org> ---drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++1 file changed, 36 insertions(+)--- a/drivers/mtd/ubi/build.c +++ b/drivers/mtd/ubi/build.c @@ -1226,6 +1226,73 @@ static struct mtd_info * __init open_mtdreturn mtd;}+/* + * This function tries attaching mtd partitions named either "ubi" or "data" + * during boot. + */ +static void __init ubi_auto_attach(void) +{ + int err; + struct mtd_info *mtd; + loff_t offset = 0; + size_t len; + char magic[4]; + + /* try attaching mtd device named "ubi" or "data" */ + mtd = open_mtd_device("ubi"); + if (IS_ERR(mtd)) + mtd = open_mtd_device("data"); + + if (IS_ERR(mtd)) + return; + + /* get the first not bad block */ + if (mtd_can_have_bb(mtd)) + while (mtd_block_isbad(mtd, offset)) { + offset += mtd->erasesize; + + if (offset > mtd->size) { + pr_err("UBI error: Failed to find a non-bad " + "block on mtd%d\n", mtd->index); + goto cleanup; + } + } + + /* check if the read from flash was successful */ + err = mtd_read(mtd, offset, 4, &len, (void *) magic); + if ((err && !mtd_is_bitflip(err)) || len != 4) { + pr_err("UBI error: unable to read from mtd%d\n", mtd->index); + goto cleanup; + } + + /* check for a valid ubi magic */ + if (strncmp(magic, "UBI#", 4)) { + pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index); + goto cleanup; + } + + /* don't auto-add media types where UBI doesn't makes sense */ + if (mtd->type != MTD_NANDFLASH && + mtd->type != MTD_NORFLASH && + mtd->type != MTD_DATAFLASH && + mtd->type != MTD_MLCNANDFLASH) + goto cleanup; + + mutex_lock(&ubi_devices_mutex); + pr_notice("UBI: auto-attach mtd%d\n", mtd->index); + err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0); + mutex_unlock(&ubi_devices_mutex); + if (err < 0) { + pr_err("UBI error: cannot attach mtd%d\n", mtd->index); + goto cleanup; + } + + return; + +cleanup: + put_mtd_device(mtd); +} +static int __init ubi_init(void){int err, i, k; @@ -1309,6 +1376,12 @@ static int __init ubi_init(void)}}+ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd + * parameter was given */ + if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) && + !ubi_is_module() && !mtd_devs) + ubi_auto_attach(); +err = ubiblock_init();if (err) {pr_err("UBI error: block: cannot initialize, error %d", err);其執行過程在ubi_init中觸發,需要內核開啟CONFIG_MTD_ROOTFS_ROOT_DEV支持,自動查找名為ubi或data的分區,然后自動進行attach
二、加載rootfs卷
其過程也是一個patch文件 491-ubi-auto-create-ubiblock-device-for-rootfs.patch
From: Daniel Golle <daniel@makrotopia.org> Subject: ubi: auto-create ubiblock device for rootfsSigned-off-by: Daniel Golle <daniel@makrotopia.org> ---drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++1 file changed, 42 insertions(+)--- a/drivers/mtd/ubi/block.c +++ b/drivers/mtd/ubi/block.c @@ -635,6 +635,44 @@ static void __init ubiblock_create_from_}}+#define UBIFS_NODE_MAGIC 0x06101831 +static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc) +{ + int ret; + uint32_t magic_of, magic; + ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4); + if (ret) + return 0; + magic = le32_to_cpu(magic_of); + return magic == UBIFS_NODE_MAGIC; +} + +static void __init ubiblock_create_auto_rootfs(void) +{ + int ubi_num, ret, is_ubifs; + struct ubi_volume_desc *desc; + struct ubi_volume_info vi; + + for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) { + desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY); + if (IS_ERR(desc)) + continue; + + ubi_get_volume_info(desc, &vi); + is_ubifs = ubi_vol_is_ubifs(desc); + ubi_close_volume(desc); + if (is_ubifs) + break; + + ret = ubiblock_create(&vi); + if (ret) + pr_err("UBI error: block: can't add '%s' volume, err=%d\n", + vi.name, ret); + /* always break if we get here */ + break; + } +} +static void ubiblock_remove_all(void){struct ubiblock *next; @@ -667,6 +705,10 @@ int __init ubiblock_init(void)*/ubiblock_create_from_param();+ /* auto-attach "rootfs" volume if existing and non-ubifs */ + if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV)) + ubiblock_create_auto_rootfs(); +/** Block devices are only created upon user requests, so we ignore* existing volumes.在函數ubiblock_init中進行ubiblock_create_auto_rootfs,硬編碼為rootfs,注釋已非常明確 /* auto-attach "rootfs" volume if existing and non-ubifs */
三、設置根文件系統
在分析之前我們先需要了解一下linux的根文件系統加載過程,此處介紹devtmpfs過程,devtmpfs網上介紹很多,大致就是在內核啟動過程中自動創建/dev/xxx文件
系統運行過程中關于devtmpfs的日志只有兩條:
[ 0.636686] devtmpfs: initialized ... [ 2.321714] devtmpfs: mounteddevtmpfs: initialized 執行時機為cpu啟動之后,具體在driver_init初始化的過程中
driver_init -->devtmpfs_init-->register_filesystem
static struct file_system_type dev_fs_type = {.name = "devtmpfs",.mount = dev_mount,.kill_sb = kill_litter_super, };在devtmpfs環境準備好之后,才有VFS初始化過程以及MTD分區檢索
linux根文件系統掛載入口為prepare_namespace
具體過程為:
kernel_init --> kernel_init_freeable --> prepare_namespace
/** Prepare the namespace - decide what/where to mount, load ramdisks, etc.*/ void __init prepare_namespace(void) {int is_floppy;printk(KERN_INFO "prepare_namespace root_delay=%d, cmd_root_dev [%s]\n", root_delay, saved_root_name);if (root_delay) {printk(KERN_INFO "Waiting %d sec before mounting root device...\n",root_delay);ssleep(root_delay);}/** wait for the known devices to complete their probing** Note: this is a potential source of long boot delays.* For example, it is not atypical to wait 5 seconds here* for the touchpad of a laptop to initialize.*/wait_for_device_probe();md_run_setup();if (saved_root_name[0]) {root_device_name = saved_root_name;if (!strncmp(root_device_name, "mtd", 3) ||!strncmp(root_device_name, "ubi", 3)) {mount_block_root(root_device_name, root_mountflags);goto out;}ROOT_DEV = name_to_dev_t(root_device_name);if (strncmp(root_device_name, "/dev/", 5) == 0)root_device_name += 5;}if (initrd_load())goto out;/* wait for any asynchronous scanning to complete */if ((ROOT_DEV == 0) && root_wait) {printk(KERN_INFO "Waiting for root device %s...\n",saved_root_name);while (driver_probe_done() != 0 ||(ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)msleep(100);async_synchronize_full();}is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;if (is_floppy && rd_doload && rd_load_disk(0))ROOT_DEV = Root_RAM0;mount_root(); out:devtmpfs_mount("dev");sys_mount(".", "/", NULL, MS_MOVE, NULL);sys_chroot("."); }其中有幾個關鍵的參數:
cmdline中的root,rootwait,rootdelay,rootfstype
root指定掛載分區,在 auto-attach 章節里,如果cmdline中指定了root設備,那么就不用自動探測,當然在openwrt系統中,kernel和rootfs是一體的,設置自動探測與其特有的固件打包方式有關;
一般來說,當rootfs占有一個獨立的mtd分區的時候,啟動參數才指定root分區
rootfstype,說明掛載類型,在openwrt中傳遞的是“rootfstype=squashfs,ubifs“
詳細日志參照:
[ 2.269712] prepare_namespace root_delay=0, cmd_root_dev [] [ 2.275130] VFS: under CONFIG_MTD_ROOTFS_ROOT_DEV to mount_ubi_rootfs [ 2.287905] VFS: to do_mount_root [squashfs] from cmdlines rootfstype [ 2.304145] VFS: Mounted root (squashfs filesystem) readonly on device 254:0. [ 2.321714] devtmpfs: mounted to [dev]主要掛載過程在mount_root中
void __init mount_root(void) { #ifdef CONFIG_ROOT_NFSif (ROOT_DEV == Root_NFS) {if (mount_nfs_root())return;printk(KERN_ERR "VFS: Unable to mount root fs via NFS, trying floppy.\n");ROOT_DEV = Root_FD0;} #endif #ifdef CONFIG_BLK_DEV_FDif (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) {/* rd_doload is 2 for a dual initrd/ramload setup */if (rd_doload==2) {if (rd_load_disk(1)) {ROOT_DEV = Root_RAM1;root_device_name = NULL;}} elsechange_floppy("root floppy");} #endif #ifdef CONFIG_MTD_ROOTFS_ROOT_DEVprintk(KERN_NOTICE "VFS: under CONFIG_MTD_ROOTFS_ROOT_DEV to mount_ubi_rootfs\n");if (!mount_ubi_rootfs())return; #endif #ifdef CONFIG_BLOCK{int err = create_dev("/dev/root", ROOT_DEV);if (err < 0)pr_emerg("Failed to create /dev/root: %d\n", err);mount_block_root("/dev/root", root_mountflags);} #endif }由于使能了CONFIG_MTD_ROOTFS_ROOT_DEV,前面有UBI的自動attach,因此在此處直接掛載ubifs
static int __init mount_ubi_rootfs(void) {int flags = MS_SILENT;int err, tried = 0;while (tried < 2) {err = do_mount_root("ubi0:rootfs", "ubifs", flags, \root_mount_data);switch (err) {case -EACCES:flags |= MS_RDONLY;tried++;break;default:return err;}}return -EINVAL; }至此UBI根文件系統掛載完畢
四、關于overlayfs掛載
主要在openwrt的mount_root中,日志為
[ 4.376589] mount_root: overlay filesystem has not been fully initialized yet [ 4.383875] mount_root: switching to ubifs overlay具體overlay機制,openwrt中資料很多,在此不作介紹
?
?
總結
以上是生活随笔為你收集整理的SigmaStar SSD202 openwrt 系统下ubi根文件系统挂载过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CPU方案简介UIS8190 - LTE
- 下一篇: Linux虚拟内存映射分析以及CMA测试