Openwrt preinit mount文件系统启动流程

一 入口脚本函数:

do_mount_ubifs_overlay() {
    ubifs_error_check_and_recover
    { ubifs_volume_support && \
    try_ubifs_syscfg_mount && \
    ubifs_syscfg_rootfs_pivot ; } || mount_no_ubifs_syscfg_mtd
}

首先介绍Shell脚本的一些基础知识。

1 在一个脚本函数中一个{}中的语句是作为一个整体的block执行。

2 cmda && cmdb 是指只有cmda执行成功(Shell中命令执行成功是指命令返回0)cmdb才会执行;

3 cmda || cmdb 是指cmda执行失败,cmdb命令才会执行。

基于如上,这个Shell函数先执行

ubifs_error_check_and_recover

然后执行{}的内容,作为一个整体block,执行成功后不会执行mount_no_ubifs_syscfg_mtd,

执行失败后才会执行mount_no_ubifs_syscfg_mtd。

下边看{}中的内容。

{ ubifs_volume_support && try_ubifs_syscfg_mount && ubifs_syscfg_rootfs_pivot ; }

先执行ubifs_volume_support,如果执行成功继续执行try_ubifs_syscfg_mount,如果执行成功继续执行ubifs_syscfg_rootfs_pivot。

中间有一个执行失败就会中断,且整体{}的结果是执行失败。

二  ubifs_error_check_and_recover

ubifs_error_check_and_recover() {
    local mtdnum

    ubifs_err="$(cat /proc/sys/kernel/ubifs_error)"
    [ -z "$ubifs_err" -o "$ubifs_err" = "0" ] && return 0

    mtdnum=$(($ubifs_err >> 16))
    mtdnum=$(($mtdnum & 0xff))

    echo "erase mtd${mtdnum} to recover ubifs error $ubifs_err"
    mtd erase /dev/mtd${mtdnum}
    echo 0 > /proc/sys/kernel/ubifs_error
    return 0
}

/proc/sys/kernel/ubifs_error具体的含义可以参考kernel源码fs/ubifs/io.c里的ramdump_ubifs_flag的赋值,如果ubi文件系统有错误的时候,kernel会把相应的mtdnum的信息置入/proc/sys/kernel/ubifs_error。所以后边可以通过ubifs_error的值反算出是哪个mtd出现了错误。这里的修复方法是重新erase掉该mtd分区。

三 ubifs_volume_support

# return 1 on failed 0 for success
ubifs_volume_support() {
    mtdpart_idx="$(find_mtd_index rootfs_data)"
    [ -z "$mtdpart_idx" ] && return 1
    # for SDTIM support
    mtdpart_idx_oem="$(find_mtd_index oem_data$SLOT-mount)"
    if [ -z "$mtdpart_idx_oem" ]
    then
        mtdpart_idx_oem="$(find_mtd_index oem_data$SLOT)"
        if [ -z "$mtdpart_idx_oem" ]
        then
            # oem_data may has only one partition
            mtdpart_idx_oem="$(find_mtd_index oem_data)"
            [ -z "$mtdpart_idx_oem" ] && return 1
        fi
    fi
    grep -qs ubifs /proc/filesystems ||  return 1
    echo "found rootfs_data partition and ubifs support"
    return 0
}

这里边的find_mtd_index是为了找寻一个分区的mtd序号。$SLOT是指"-a"或者"-b",或者为空。这个Shell函数主要是为了做一个基本判断,是不是支持ubi文件系统,是不是能找到系统预置的一些基本ubi分区信息。

四 try_ubifs_syscfg_mount

__try_ubifs_syscfg_mount() {
    overlay_mountpoint=$1
    if [ -z $overlay_mountpoint ]
    then
        overlay_mountpoint=/overlay
    fi
    recover_ubifs=0
    [ ! -e /dev/ubi0 ] && ubiattach /dev/ubi_ctrl -m $mtdpart_idx -d 0 || recover_ubifs=1
    if [ $recover_ubifs -eq 0 ]
    then
        ubi0_nod_id=`cat /sys/class/ubi/ubi0/dev | tr -s ":" " "`
        [ ! -e /dev/ubi0 ] && mknod /dev/ubi0 c ${ubi0_nod_id}
        if [ ! -e /sys/class/ubi/ubi0_0/dev ]
        then
            # no volume
            recover_ubifs=1
        else
            # check for "data" volume
            ubi0_0_nod_id=`cat /sys/class/ubi/ubi0_0/dev | tr -s ":" " "`
            [ ! -e /dev/ubi0_0 ] && mknod /dev/ubi0_0 c ${ubi0_0_nod_id}
            { ubinfo /dev/ubi0_0 | grep Name  | grep -qs "data" ; } || \
            recover_ubifs=1
        fi
    fi
    if [ $recover_ubifs -eq 1 ]
    then
        echo "ubifs syscfg partition is damaged"
        echo "try to recover by formatting $mtdpart..."
        [ -e /dev/ubi0 ] && ubidetach -m $mtdpart_idx
        ubiformat -y -q /dev/mtd$mtdpart_idx
        ubiattach -m $mtdpart_idx /dev/ubi_ctrl
        ubi0_nod_id=`cat /sys/class/ubi/ubi0/dev | tr -s ":" " "`
        [ ! -e /dev/ubi0 ] && mknod /dev/ubi0 c ${ubi0_nod_id}
        ubimkvol /dev/ubi0 -n 1 -N etc -t dynamic -s 5MiB
        ubimkvol /dev/ubi0 -n 2 -N nvm -t dynamic -s 4MiB
        ubimkvol /dev/ubi0 -n 0 -N data -t dynamic --maxavsize
    fi

    # finally mount the ubifs
    mount -t ubifs -o noatime ubi0:data /data || return 1
    mount -t ubifs -o noatime ubi0:data /mnt || return 1
    mount -t ubifs -o noatime ubi0:data /log || return 1
    mount -t ubifs -o noatime ubi0:etc $overlay_mountpoint/etc || return 1
    mount -t ubifs -o noatime ubi0:nvm $overlay_mountpoint/nvm || return 1

    # clean up uci tmp file to avoid wirtable partition full
    rm -rf $overlay_mountpoint/etc/root/config/.*.uci-*
    return 0
}

try_ubifs_syscfg_mount() {
    __try_ubifs_syscfg_mount || {
        echo "roofs_data mount fail, try to recover by erase..."
        umount $overlay_mountpoint/nvm
        umount $overlay_mountpoint/etc
        umount /log
        umount /mnt
        umount /data
        mtd erase rootfs_data
        __try_ubifs_syscfg_mount
    }

    return 0
}
这个Shell函数重点看__try_ubifs_syscfg_mount(syscfg原意是openwrt的系统配置分区,每个vendor平台可能有不同的延伸含义)

overlay_mountpoint这个变量指向的是/overlay。

这里主要关注recover_ubifs

其实这个函数主要是判定ubi0_0分区是否被损坏,然后重新格式化。我们考虑正常情况下

 mount -t ubifs -o noatime ubi0:data /data || return 1
 mount -t ubifs -o noatime ubi0:data /mnt || return 1
 mount -t ubifs -o noatime ubi0:data /log || return 1

ubi0:data这个volume mount到三个目录 /data /mnt /log 一个分区挂载到多个目录,是不建议的,但是这里不知道为啥ASR采用这个机制。


 mount -t ubifs -o noatime ubi0:etc $overlay_mountpoint/etc || return 1
 mount -t ubifs -o noatime ubi0:nvm $overlay_mountpoint/nvm || return 1

ubi0:etc挂载到/overlay/etc

ubi0:nvm挂载到/overlay/nvm

再次梳理:rootfs_data这个mtd分区是ubi0这个占据,然后分为了3个volume!

五  ubifs_syscfg_rootfs_pivot

重点和精华来了,就是overlay和root的切换。

create_overlay() { # <lowerdir> <upper_dir> <target>
    mkdir -p $2/root $2/work
    /bin/mount -o noatime,lowerdir=$1,upperdir=$2/root,workdir=$2/work -t overlay "overlayfs:$2" $3
    /bin/umount $2
}

ubifs_syscfg_rootfs_pivot() {
    echo "switching to ubifs sysfs overlay"

    # PIPE mode need to recover this file in /etc/init.d/network
    cp -rf /etc/config/network /tmp/network_pipe

    # Dir /etc and /NVM can be written after creating overlay
    create_overlay /system/etc $overlay_mountpoint/etc /system/etc
    create_overlay /NVM $overlay_mountpoint/nvm /NVM
    ubifs_oem_data_mount
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值