android文件系统挂载分析(1)---正常开机挂载_weixin_30872733的博客-程序员秘密

技术标签: 移动开发  

未完,更新中 。。。

 

"android"系列分为三部分:

1.正常开机挂载

2.encryption

3.dm-verity

 

  我们知道android有很多分区,如"system","userdata","cache",他们是何时挂载的?如何挂载的?这个系列的文章进行分析。这里介绍第一部分,android手机正常开机各分区的挂载。这里我们以mtk平台进行分析,高通与mtk差别不是很大。

 

  我们知道kernel起来以后执行的第一个文件是init进程,init进程会根据init.rc的规则启动进程或者服务。init.rc通过"import /init.${ro.hardware}.rc"语句导入平台的规则。

device/mediatek/mt6797/init.mt6797.rc

on fs
    write /proc/bootprof "INIT:Mount_START"
    mount_all /fstab.mt6797
    chown system system /mobile_info
    chmod 0771 /mobile_info
    exec /system/bin/tune2fs -O has_journal -u 10010 -r 4096 /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/userdata
    write /proc/bootprof "INIT:Mount_END"

mount_all是一条命令,/fstab.mt6797是传入的参数

system/core/init/keywords.h

.....
   KEYWORD(mount_all,   COMMAND, 1, do_mount_all)
.....

从上面我们可以看出,mount_all命令对应的是do_mount_all函数,/fstab.mt6797是do_mount_all函数的传入参数

system/core/init/builtins.cpp

int do_mount_all(int nargs, char **args)
{
    pid_t pid;
    int ret = -1;
    int child_ret = -1;
    int status;
    struct fstab *fstab;

    if (nargs != 2) {
        return -1;
    }

    /*
     * Call fs_mgr_mount_all() to mount all filesystems.  We fork(2) and         //使用fs_mgr_mount_all()函数去挂载所有的文件系统,我们使用fork()函数分配一个新的进程,在子进程中做挂载的事情,这样即使挂载出现问题,也能保护init主进程。
     * do the call in the child to provide protection to the main init
     * process if anything goes wrong (crash or memory leak), and wait for
     * the child to finish in the parent.
     */
    pid = fork();
    if (pid > 0) {                   //父进程,等待子进程(pid=0)返回
        /* Parent.  Wait for the child to return */
        int wp_ret = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
        if (wp_ret < 0) {
            /* Unexpected error code. We will continue anyway. */
            NOTICE("waitpid failed rc=%d: %s\n", wp_ret, strerror(errno));
        }

        if (WIFEXITED(status)) {
            ret = WEXITSTATUS(status);
        } else {
            ret = -1;
        }
    } else if (pid == 0) {     //子进程
        /* child, call fs_mgr_mount_all() */
        klog_set_level(6);  /* So we can see what fs_mgr_mount_all() does */    //修改kernel log的等级,让我们可以看到fs_mgr_mount_all函数的log
        fstab = fs_mgr_read_fstab(args[1]);      //args[1]是传入的参数/fstab.mt6797,是一个文件。      加载分区挂载文件的内容到fstab结构体中。
        child_ret = fs_mgr_mount_all(fstab);     //挂载分区*******************
        fs_mgr_free_fstab(fstab);
        if (child_ret == -1) {
            ERROR("fs_mgr_mount_all returned an error\n");
        }
        _exit(child_ret);
    } else {
        /* fork failed, return an error */
        return -1;
    }

    if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
        property_set("vold.decrypt", "trigger_encryption");
    } else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
        property_set("ro.crypto.state", "encrypted");
        property_set("ro.crypto.type", "block");
        property_set("vold.decrypt", "trigger_default_encryption");
    } else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
        property_set("ro.crypto.state", "unencrypted");
        /* If fs_mgr determined this is an unencrypted device, then trigger
         * that action.
         */
        action_for_each_trigger("nonencrypted", action_add_queue_tail);
    } else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
        /* Setup a wipe via recovery, and reboot into recovery */
        ERROR("fs_mgr_mount_all suggested recovery, so wiping data via recovery.\n");
        ret = wipe_data_via_recovery();
        /* If reboot worked, there is no return. */
    } else if (ret == FS_MGR_MNTALL_DEV_DEFAULT_FILE_ENCRYPTED) {
        if (e4crypt_install_keyring()) {
            return -1;
        }
        property_set("ro.crypto.state", "encrypted");
        property_set("ro.crypto.type", "file");

        // Although encrypted, we have device key, so we do not need to
        // do anything different from the nonencrypted case.
        action_for_each_trigger("nonencrypted", action_add_queue_tail);
    } else if (ret == FS_MGR_MNTALL_DEV_NON_DEFAULT_FILE_ENCRYPTED) {
        if (e4crypt_install_keyring()) {
            return -1;
        }
        property_set("ro.crypto.state", "encrypted");
        property_set("ro.crypto.type", "file");
        property_set("vold.decrypt", "trigger_restart_min_framework");
    } else if (ret > 0) {
        ERROR("fs_mgr_mount_all returned unexpected error %d\n", ret);
    }
    /* else ... < 0: error */

    return ret;
}

 

fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。返回值小于0为error,返回值等于0为子进程,返回值大于0为父进程。

 

args[1]是传入的参数/fstab.mt6797,是一个文件,生成的位置在/out/target/product/xxx/root/fstab.mt6797,生成这个文件的源文件位于vendor/mediatek/proprietary/hardware/fstab/mt6797/,根据编译规则确定fstab.mt6797文件的内容。

在do_mount_all()函数中,比较重要的两个函数如下,我们分析一下这两个函数

stab = fs_mgr_read_fstab(args[1]); 

child_ret = fs_mgr_mount_all(fstab);

 

首先我们看下fstab结构体和fstab.mt6797文件,fstab结构提要存储fstab.mt6797文件中的挂载信息,

 

struct fstab {
    int num_entries;
    struct fstab_rec *recs;
    char *fstab_filename;
};

struct fstab_rec {
    char *blk_device;
    char *mount_point;
    char *fs_type;
    unsigned long flags;
    char *fs_options;
    int fs_mgr_flags;
    char *key_loc;
    char *verity_loc;
    long long length;
    char *label;
    int partnum;
    int swap_prio;
    unsigned int zram_size;
};

 

out/target/product/xxx/root/fstab.mt6797
# 1 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in"
# 1 "<built-in>"
# 1 "<命令行>"
# 1 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in"
# 20 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in"
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/system /system ext4 ro wait,verify

/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/userdata /data ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check,resize,forceencrypt=/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/metadata,
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/cache /cache ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/protect1 /protect_f ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/protect2 /protect_s ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/nvdata /nvdata ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check,formattable
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/nvcfg /nvcfg ext4 noatime,nosuid,nodev,noauto_da_alloc,commit=1,nodelalloc wait,check,formattable
/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/mobile_info /mobile_info ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check
# 39 "vendor/mediatek/proprietary/hardware/fstab/mt6797/fstab.in"
/devices/mtk-msdc.0/11230000.msdc0* auto vfat defaults voldmanaged=sdcard0:auto
/devices/mtk-msdc.0/11240000.msdc1* auto auto defaults voldmanaged=sdcard1:auto,encryptable=userdata
/devices/soc/11270000.usb3_xhci* auto vfat defaults voldmanaged=usbotg:auto

.................

 

我们先分析fstab结构体存放的挂载信息,通过fs_mgr_read_fstab实现

system/core/fs_mgr_fstab.c

struct fstab *fs_mgr_read_fstab(const char *fstab_path)                //从上面可以知道fstab_path为/fstab.mt6797
{
    FILE *fstab_file;
    int cnt, entries;
    ssize_t len;
    size_t alloc_len = 0;
    char *line = NULL;
    const char *delim = " \t";
    char *save_ptr, *p;
    struct fstab *fstab = NULL;
    struct fs_mgr_flag_values flag_vals;
#define FS_OPTIONS_LEN 1024
    char tmp_fs_options[FS_OPTIONS_LEN];

    fstab_file = fopen(fstab_path, "r");           //打开文件
    if (!fstab_file) {
        ERROR("Cannot open file %s\n", fstab_path);
        return 0;
    }

    entries = 0;
    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {   //一行一行的读取文件内容,line是指向存放该行字符的指针         第一次读取文件内容,填充fstab结构体的内容
        /* if the last character is a newline, shorten the string by 1 byte */
        if (line[len - 1] == '\n') {          //如果最后一行是新行,缩短一字节的字符串
            line[len - 1] = '\0';
        }
        /* Skip any leading whitespace */
        p = line;                  
        while (isspace(*p)) {    
            p++;
        }
        /* ignore comments or empty lines */    //忽略注释和空格开始的行
        if (*p == '#' || *p == '\0')
            continue;
        entries++;   //有用信息的行数
    }

    if (!entries) {       
        ERROR("No entries found in fstab\n");
        goto err;
    }

    /* Allocate and init the fstab structure */
    fstab = calloc(1, sizeof(struct fstab));        //给fstab结构体分配内存
    fstab->num_entries = entries;        //fstab->num_entries  存放可用信息的总行数
    fstab->fstab_filename = strdup(fstab_path);     // fstab->fstab_filename 存放"fstab.mt6797"名称
    fstab->recs = calloc(fstab->num_entries, sizeof(struct fstab_rec));   //给fstab->recs结构体分配内存

    fseek(fstab_file, 0, SEEK_SET);      

    cnt = 0;
    while ((len = getline(&line, &alloc_len, fstab_file)) != -1) {        //第一次读取文件内容,填充结构体fstab->recs的内容
        /* if the last character is a newline, shorten the string by 1 byte */
        if (line[len - 1] == '\n') {
            line[len - 1] = '\0';
        }

        /* Skip any leading whitespace */
        p = line;
        while (isspace(*p)) {
            p++;
        }
        /* ignore comments or empty lines */
        if (*p == '#' || *p == '\0')
            continue;

        /* If a non-comment entry is greater than the size we allocated, give an
         * error and quit.  This can happen in the unlikely case the file changes
         * between the two reads.
         */
        if (cnt >= entries) {
            ERROR("Tried to process more entries than counted\n");
            break;
        }
 //下面以/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/userdata /data ext4 noatime,nosuid,nodev,noauto_da_alloc,discard wait,check,resize,forceencrypt=/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/metadata,为例
        if (!(p = strtok_r(line, delim, &save_ptr))) {    //strtok_r字符串分割函数,line表示要分割的字符串,delim要分割的标志,p存放分割后的字符串
            ERROR("Error parsing mount source\n");
            goto err;
        }
        fstab->recs[cnt].blk_device = strdup(p);   //fstab->recs[cnt].blk_device  存放文件系统绝对路径 /dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/userdata

        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
            ERROR("Error parsing mount_point\n");
            goto err;
        }
        fstab->recs[cnt].mount_point = strdup(p);   //fstab->recs[cnt].mount_point  挂载点 /data

        if (!(p = strtok_r(NULL, delim, &save_ptr))) {
            ERROR("Error parsing fs_type\n");
            goto err;
        }
        fstab->recs[cnt].fs_type = strdup(p);    //fstab->recs[cnt].fs_type  文件系统类型  ext4

        if (!(p = strtok_r(NULL, delim, &save_ptr))) {   //此时的p存放的参数 noatime,nosuid,nodev,noauto_da_alloc,discard 
            ERROR("Error parsing mount_flags\n");
            goto err;
        }
        tmp_fs_options[0] = '\0';
        fstab->recs[cnt].flags = parse_flags(p, mount_flags, NULL,        //fstab->recs[cnt].flags 表示这行有无参数
                                       tmp_fs_options, FS_OPTIONS_LEN);

/*
static struct flag_list mount_flags[] = {
    { "noatime",    MS_NOATIME },
    { "noexec",     MS_NOEXEC },
    { "nosuid",     MS_NOSUID },
    { "nodev",      MS_NODEV },
    { "nodiratime", MS_NODIRATIME },
    { "ro",         MS_RDONLY },
    { "rw",         0 },
    { "remount",    MS_REMOUNT },
    { "bind",       MS_BIND },
    { "rec",        MS_REC },
    { "unbindable", MS_UNBINDABLE },
    { "private",    MS_PRIVATE },
    { "slave",      MS_SLAVE },
    { "shared",     MS_SHARED },
    { "defaults",   0 },
    { 0,            0 },
};
*/
/* fs_options are optional */ if (tmp_fs_options[0]) {                   //是个flags list,读取noatime,nosuid,nodev,noauto_da_alloc,discard fstab->recs[cnt].fs_options = strdup(tmp_fs_options); } else { fstab->recs[cnt].fs_options = NULL; } if (!(p = strtok_r(NULL, delim, &save_ptr))) {           //此时p存放剩下的参数wait,check,resize,forceencrypt=/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/metadata ERROR("Error parsing fs_mgr_options\n"); goto err; } fstab->recs[cnt].fs_mgr_flags = parse_flags(p, fs_mgr_flags, &flag_vals, NULL, 0);

/*
static struct flag_list fs_mgr_flags[] = {
    { "wait",        MF_WAIT },
    { "check",       MF_CHECK },
    { "encryptable=",MF_CRYPT },
    { "forceencrypt=",MF_FORCECRYPT },
    { "fileencryption",MF_FILEENCRYPTION },
    { "nonremovable",MF_NONREMOVABLE },
    { "voldmanaged=",MF_VOLDMANAGED},
    { "length=",     MF_LENGTH },
    { "recoveryonly",MF_RECOVERYONLY },
    { "swapprio=",   MF_SWAPPRIO },
    { "zramsize=",   MF_ZRAMSIZE },
    { "verify",      MF_VERIFY },
    { "noemulatedsd", MF_NOEMULATEDSD },
    { "notrim",       MF_NOTRIM },
    { "formattable", MF_FORMATTABLE },
#ifdef MTK_FSTAB_FLAGS
    { "resize",      MF_RESIZE },
#endif
    { "defaults",    0 },
    { 0,             0 },
};

*/
fstab
->recs[cnt].key_loc = flag_vals.key_loc;    //fstab->recs[cnt].key_loc 存放"="后的内容  这里是    "/dev/block/platform/mtk-msdc.0/11230000.msdc0/by-name/metadata" fstab->recs[cnt].verity_loc = flag_vals.verity_loc; fstab->recs[cnt].length = flag_vals.part_length; fstab->recs[cnt].label = flag_vals.label; fstab->recs[cnt].partnum = flag_vals.partnum; fstab->recs[cnt].swap_prio = flag_vals.swap_prio; fstab->recs[cnt].zram_size = flag_vals.zram_size; cnt++; } fclose(fstab_file); free(line); return fstab; err: fclose(fstab_file); free(line); if (fstab) fs_mgr_free_fstab(fstab); return NULL; }

 fstab.mt6797文件的内容已经读取到fstab结构提中,下面开始分析挂载函数fs_mgr_mount_all,传入的参数就是上面分析的fstab。

system/core/fs_mgr/fs_mgr.c

int fs_mgr_mount_all(struct fstab *fstab)
{
    int i = 0;
    int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTED;            //这个变量涉及到encryption加密,后面的文章会详细介绍这块
    int error_count = 0;
    int mret = -1;
    int mount_errno = 0;
    int attempted_idx = -1;

    if (!fstab) {                
        return -1;
    }

    for (i = 0; i < fstab->num_entries; i++) {
        /* Don't mount entries that are managed by vold */
        if (fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) {
            continue;
        }

        /* Skip swap and raw partition entries such as boot, recovery, etc */
        if (!strcmp(fstab->recs[i].fs_type, "swap") ||
            !strcmp(fstab->recs[i].fs_type, "emmc") ||
            !strcmp(fstab->recs[i].fs_type, "mtd")) {
            continue;
        }

        /* Translate LABEL= file system labels into block devices */
        if (!strcmp(fstab->recs[i].fs_type, "ext2") ||
            !strcmp(fstab->recs[i].fs_type, "ext3") ||
            !strcmp(fstab->recs[i].fs_type, "ext4")) {
            int tret = translate_ext_labels(&fstab->recs[i]);
            if (tret < 0) {
                ERROR("Could not translate label to block device\n");
                continue;
            }
        }
       ERROR("blk device name %s\n", fstab->recs[i].blk_device);
#if defined(MTK_UBIFS_SUPPORT) || defined (MTK_FTL_SUPPORT)                //这里支持UBIFS/FTL,这里没有使用
    if (strcmp(fstab->recs[i].fs_type, "ubifs") == 0 && strncmp("ubi@", fstab->recs[i].blk_device, 4) == 0) {
        char tmp[25];
        int n = ubi_attach_mtd(fstab->recs[i].blk_device + 4);
        if (n < 0) {
            ERROR("ubi_attach_mtd fail device name %s\n", fstab->recs[i].blk_device+4);
            return -1;
        }

        n = sprintf(tmp, "/dev/ubi%d_0", n);
        free(fstab->recs[i].blk_device);
        fstab->recs[i].blk_device = malloc(n+1);
        sprintf(fstab->recs[i].blk_device, "%s", tmp);
        ERROR("debug : ubifs blk_device %s", fstab->recs[i].blk_device);
    } else if (!strcmp(fstab->recs[i].fs_type, "rawfs") || !strcmp(fstab->recs[i].fs_type, "yaffs2")) {
        char tmp[25];
        int n = mtd_name_to_number(fstab->recs[i].blk_device + 4);
        if (n < 0) {
            return -1;
        }

       n = sprintf(tmp, "/dev/block/mtdblock%d", n);
       free(fstab->recs[i].blk_device);
       fstab->recs[i].blk_device = malloc(n+1);
       sprintf(fstab->recs[i].blk_device, "%s", tmp);
       ERROR("debug : rawfs blk_device %s", fstab->recs[i].blk_device);
    }
#ifdef MTK_FTL_SUPPORT
    else if (!strcmp(fstab->recs[i].fs_type, "ext4") && strstr(fstab->recs[i].blk_device, "ftl")) {
        char tmp[30];
        int err = 0;
        int n = -1;
        int ubi_num = fstab->recs[i].blk_device[21] - '0';
        ERROR("debug : mtk_ftl_blk %s ubi_num %d\n", fstab->recs[i].blk_device, ubi_num);
        if(strstr(fstab->recs[i].mount_point, "system")){
            n = ubi_attach_mtd("system");
        }else if(strstr(fstab->recs[i].mount_point, "data")){
            n = ubi_attach_mtd("userdata");
        }else if(strstr(fstab->recs[i].mount_point, "cache")){
            n = ubi_attach_mtd("cache");
        }
        if((n != ubi_num) && (n >= 0))
        {
            ERROR("ubi number: %d == %d\n", n, ubi_num);
            ubi_num = n;
        }
        n = sprintf(tmp, "/dev/ubi%d_0", ubi_num);
        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {
            int ret = wait_for_file(tmp, WAIT_TIMEOUT);
            ERROR("wait_for_file(%s) ret = %d, errno = %s\n", fstab->recs[i].blk_device, ret, strerror(errno));
        }
        err = ftl_attach_ubi(ubi_num);
        if (err < 0) {
            return -1;
        }
    }
#endif
#endif
        if (fstab->recs[i].fs_mgr_flags & MF_WAIT) {          //当有"wait"关键字时,让系统sleep一会
            wait_for_file(fstab->recs[i].blk_device, WAIT_TIMEOUT);
        }

        if ((fstab->recs[i].fs_mgr_flags & MF_VERIFY) && device_is_secure()) {        //这个if涉及到system的挂载问题,系统默认是把system挂载到dm-01上,用户不可以remount,使能这个if,用户可以remount,这块会在后面的文章详细介绍
            int rc = fs_mgr_setup_verity(&fstab->recs[i]);
            if (device_is_debuggable() && rc == FS_MGR_SETUP_VERITY_DISABLED) {
           
                INFO("Verity disabled");
            } else if (rc != FS_MGR_SETUP_VERITY_SUCCESS) {
                ERROR("Could not set up verified partition, skipping!\n");
                continue;
            }
        }                     
//正常开机mount主要从是下面的代码
int last_idx_inspected; int top_idx = i; mret = mount_with_alternatives(fstab, i, &last_idx_inspected, &attempted_idx, encryptable);     //函数挂载 i = last_idx_inspected; mount_errno = errno; /* Deal with encryptability. */ if (!mret) { int status = handle_encryptable(fstab, &fstab->recs[attempted_idx]);   //处理加密 if (status == FS_MGR_MNTALL_FAIL) { /* Fatal error - no point continuing */ return status; } if (status != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { if (encryptable != FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) { // Log and continue ERROR("Only one encryptable/encrypted partition supported\n"); } encryptable = status; } /* Success! Go get the next one */ continue; } /* mount(2) returned an error, handle the encryptable/formattable case */ bool wiped = partition_wiped(fstab->recs[top_idx].blk_device); if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_formattable(&fstab->recs[top_idx]) && wiped) { /* top_idx and attempted_idx point at the same partition, but sometimes * at two different lines in the fstab. Use the top one for formatting * as that is the preferred one. */ ERROR("%s(): %s is wiped and %s %s is formattable. Format it.\n", __func__, fstab->recs[top_idx].blk_device, fstab->recs[top_idx].mount_point, fstab->recs[top_idx].fs_type); if (fs_mgr_is_encryptable(&fstab->recs[top_idx]) && strcmp(fstab->recs[top_idx].key_loc, KEY_IN_FOOTER)) { int fd = open(fstab->recs[top_idx].key_loc, O_WRONLY, 0644); if (fd >= 0) { INFO("%s(): also wipe %s\n", __func__, fstab->recs[top_idx].key_loc); wipe_block_device(fd, get_file_size(fd)); close(fd); } else { ERROR("%s(): %s wouldn't open (%s)\n", __func__, fstab->recs[top_idx].key_loc, strerror(errno)); } } if (fs_mgr_do_format(&fstab->recs[top_idx]) == 0) { /* Let's replay the mount actions. */ i = top_idx - 1; continue; } } if (mret && mount_errno != EBUSY && mount_errno != EACCES && fs_mgr_is_encryptable(&fstab->recs[attempted_idx])) { if (wiped) { ERROR("%s(): %s is wiped and %s %s is encryptable. Suggest recovery...\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY; continue; } else { /* Need to mount a tmpfs at this mountpoint for now, and set * properties that vold will query later for decrypting */ ERROR("%s(): possibly an encryptable blkdev %s for mount %s type %s )\n", __func__, fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_type); if (fs_mgr_do_tmpfs_mount(fstab->recs[attempted_idx].mount_point) < 0) { ++error_count; continue; } } encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; } else { ERROR("Failed to mount an un-encryptable or wiped partition on" "%s at %s options: %s error: %s\n", fstab->recs[attempted_idx].blk_device, fstab->recs[attempted_idx].mount_point, fstab->recs[attempted_idx].fs_options, strerror(mount_errno)); ++error_count; continue; } } if (error_count) { return -1; } else { return encryptable; } }

 

转载于:https://www.cnblogs.com/xiaolei-kaiyuan/p/5501104.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30872733/article/details/95193270

智能推荐

一款超好用的第三方评论插件--Gittalk_乘梦碧溪的博客-程序员秘密

使用GITALK的背景:1. 最近在做一个基于Java的个人博客系统,已经基本完工了,突然发现怎么没有评论的操作,如果再从头开始从数据库开始写的话,花费的代价有点大,于是乎我就在网上寻找一款适合我的第三方评论插件,第一次我找到了“畅言”,结果很令人失望,因为我的网站没有备案,所以无法使用“畅言”。于是Gitalk就映入了我的眼帘。2. Gitalk 最初推出来,应该是想配合在 github...

arm-himix100-linux-gcc no such file or directory 解决办法_wazihe的博客-程序员秘密

ubuntu上安装arm的交叉编译器arm-himix100-linux-gcc,运行arm-himix100-linux-gcc -v命令,总提示No such file or directory。然后去arm-linux-gcc所在的目录下,发现不缺少任何文件。而且环境变量配置也是正确的(环境变量很easy,只要配置个path路径就行),因为arm-是可以补全的。原因是:本人的ubuntu是64位,而下载的这些交叉编译器是32位的。因此需要安装32位-libs库执行命令如下即可:sudo apt

CAD几何引擎和图形引擎的关系_cad开发与几何_CAD.Graphics的博客-程序员秘密

近年来,国家开始大力发展工业基础软件,工业软件大有兴起之势。总体来说,国家的扶持对行业的发展有很大促进作用,同时也会吸引更多的人才进入该领域,这是一件值得令人欣慰的事情。但是,相比于互联网软件,工业软件是有门槛的,想要发展工业软件需要有行业知识,以及行业经验规范的积累。但同时也绕不开的一个关键问题,那就是需要有成熟的几何引擎。1.几何引擎为什么离不开几何引擎呢,因为大部分的工业软件都需要造型或者对模型进行编辑修改的功能,比如常见的三维CAD软件NX、Catia等,BIM软件Revit,仿真分析软件A

Linux驱动实践:中断处理函数如何【发送信号】给应用层?- 驱动与应用层数据交互(二)_send_sig_info_生活需要深度的博客-程序员秘密

因为它是共享的中断,因此当键盘被按下的时候,操作系统就会依次调用所有的中断处理函数,当然就包括我们的驱动程序所注册的这个函数。一步一步的发展历史,甚至有些人还会专门去研究 Linux 0.11 版本的内核源码,因为很多基本思想都是一样的。在中断处理函数中,目标是发送信号 SIGUSR1 到应用层,因此驱动程序需要知道应用程序的进程号(PID)。只有明白了这些最基础的知识点之后,再去看那些进化出来的高级玩意,才会有一步一个脚印的获得感。如果缺少了这些基础的环节,很多深层次的东西,学起来就有点空中楼阁的感觉。

VMware+TrueNAS Scale 全新安装并配置plex实现公网访问私网_truenas vmware_乐亦的博客-程序员秘密

下载TrueNAS Scale镜像(官网链接:https://www.truenas.com/download-truenas-scale)也可以访问我的阿里云盘(暂时不行)新建虚拟机,选择如下

随便推点

【工利其器】必会工具之 git常用命令篇_李肖遥的博客-程序员秘密

关注、星标公众号,直达精彩内容来源:网络整理:李肖遥ID:技术让梦想更伟大 常言道,好记性不如烂笔头,更何况笔者的记性也不是太好,于是就有了这篇“烂笔头”系列之一的git命令...

FPGA-时序分析基础(2)_Martin_MaB的博客-程序员秘密

必需的SDC约束(Required SDC Constraints)(1)时钟约束:理想时钟约束(Ideal clock constraints)有两种类型的时钟约束:基本时钟:绝对时钟/基准时钟:由器件输入管脚输入的时钟;虚拟时钟:驱动外部器件的时钟,不真正进入fpga内部,为IO时序分析确定正确的发送、锁存沿的相对关系。衍生时钟:(来自fpga内部的基本时钟或其他的衍生时钟,其与时钟源之间必须定义明确的关系)如:pll的输出时钟就是衍生时钟,它在一定程度上与pll的输入时钟相关

ajax同步和异步请求的区别_ajax异步请求和同步请求的区别_晚风914的博客-程序员秘密

我们在使用 ajax 一般都会使用异步处理。默认是async:true:异步,async:false:同步。异步处理:我们通过事件触发 ajax,请求服务器,在这个期间无论服务器有没有响应,客户端的其他代码一样可以运行。同步处理:我们通过事件触发 ajax,请求服务器,在这个期间等待服务器处理请求, 在这个期间客户端不能做任何处理。当 ajax 执行完毕才会继续执行其他代码。同步:提交请求-&gt;等待服务器处理-&gt;处理完毕返回 这个期间客户端浏览器不能干任何事异步: 请求通过事件触发-&g

服务器内存不足上传文件解决办法,电脑内存不足的解决方法_知乎你踏马有病的博客-程序员秘密

电脑内存不够怎么解决?如今就和我一起看一看电脑内存不够的解决方案。问题分析:提示信息的内存不够是系统软件分派的虚拟内存不够,系统软件的虚拟内存默认为“全自动管理方法全部控制器的分页文件尺寸”(Win7/Win8)或“Windows管理方法虚拟内存”(WinXP),也就是虚拟内存的管理方法是系统软件全自动的,伴随着计算机系统的发展趋势,一些系统软件升级后要求的物理内存也随着提升 ,尤其是一些大中型手...

蓝凌OA自定义公式样例库_蓝凌oa公式定义器_烧硬盘的博客-程序员秘密

判断表单多值属性框(复选框/下拉菜单)是否勾选了某个选项$列表.包含$($多值属性框$.split(";"), "选项的值")获取员工编号$申请人$.getFdNo()获取所属机构$申请人$.getFdParentOrg()获取组织架构全路径,以“/”为分隔$申请人$.getFdParentsName("/")判断某部门是否在某机构之内$XX部门$.getFdParentsName().contains("XX机构的名称")获取申请人所在部门的名称$申请人$.getFdPar

Hadoop权威指南(第二版)pdf中文版_jessezhang1981的博客-程序员秘密

今天终于找到 hadoop权威指南第二版的中文pdf版本了,发给大家共享一下  下载地址:http://dl.dbank.com/c0hh1arjiz ----------------------------------------------------------------------------------------------

推荐文章

热门文章

相关标签