Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fc86f244 authored by Sandeep Patil's avatar Sandeep Patil
Browse files

init: fstab: add support to read fstab entries from device tree



for early mount, we need a way to tell init where to find vendor,
odm partitions (also system in case of non-A/B devices). Also, that
needs to be independent of kernel cmdline since the cmdline will likely
exceed its limit.

The change adds support for parse and create fstab entries that can be
directly sent to the fs_mgr for mounting partitions early in init first
stage.

Sample DT entry to mount vendor partition early on angler-

firmware {
    android {
        compatible = "android,firmware";
        fstab {
            compatible = "android,fstab";
            vendor {
                compatible = "android,vendor";
                dev = "/dev/block/platform/soc.0/f9824900.sdhci/by-name/vendor";
                type = "ext4";
                mnt_flags = "ro,barrier=1,inode_readahead_blks=8";
                fsmgr_flags = "wait";
            };
        };
    };
};

b/27805372

Test: Boot angler and sailfish with early "vendor" partition mount by
adding aforementioned DT node and enable CONFIG_PROC_DEVICETREE in kernel

Change-Id: I669013e3fdb157e88719436534f63989dec95d60
Signed-off-by: default avatarSandeep Patil <sspatil@google.com>
parent 35403eba
Loading
Loading
Loading
Loading
+179 −99
Original line number Diff line number Diff line
@@ -477,28 +477,48 @@ static void export_kernel_boot_props() {
    }
}

static void process_kernel_dt() {
    static const char android_dir[] = "/proc/device-tree/firmware/android";
static constexpr char android_dt_dir[] = "/proc/device-tree/firmware/android";

    std::string file_name = StringPrintf("%s/compatible", android_dir);
static bool is_dt_compatible() {
    std::string dt_value;
    std::string file_name = StringPrintf("%s/compatible", android_dt_dir);

    std::string dt_file;
    android::base::ReadFileToString(file_name, &dt_file);
    if (!dt_file.compare("android,firmware")) {
    android::base::ReadFileToString(file_name, &dt_value);
    if (!dt_value.compare("android,firmware")) {
        LOG(ERROR) << "firmware/android is not compatible with 'android,firmware'";
        return;
        return false;
    }

    return true;
}

static bool is_dt_fstab_compatible() {
    std::string dt_value;
    std::string file_name = StringPrintf("%s/%s/compatible", android_dt_dir, "fstab");

    android::base::ReadFileToString(file_name, &dt_value);
    if (!dt_value.compare("android,fstab")) {
        LOG(ERROR) << "firmware/android/fstab is not compatible with 'android,fstab'";
        return false;
    }

    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dir), closedir);
    return true;
}

static void process_kernel_dt() {
    if (!is_dt_compatible()) return;

    std::unique_ptr<DIR, int(*)(DIR*)>dir(opendir(android_dt_dir), closedir);
    if (!dir) return;

    std::string dt_file;
    struct dirent *dp;
    while ((dp = readdir(dir.get())) != NULL) {
        if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") || !strcmp(dp->d_name, "name")) {
            continue;
        }

        file_name = StringPrintf("%s/%s", android_dir, dp->d_name);
        std::string file_name = StringPrintf("%s/%s", android_dt_dir, dp->d_name);

        android::base::ReadFileToString(file_name, &dt_file);
        std::replace(dt_file.begin(), dt_file.end(), ',', '.');
@@ -625,34 +645,98 @@ static void set_usb_controller() {
    }
}

/* Imports the fstab info from cmdline. */
static std::string import_cmdline_fstab() {
    std::string fstabfile;
    import_kernel_cmdline(false,
        [&](const std::string& key, const std::string& value, bool in_qemu __attribute__((__unused__))) {
            if (key == "androidboot.fstab") {
                fstabfile = value;
static std::string import_dt_fstab() {
    std::string fstab;
    if (!is_dt_compatible() || !is_dt_fstab_compatible()) {
        return fstab;
    }
        });
    return fstabfile;

    std::string fstabdir_name = StringPrintf("%s/fstab", android_dt_dir);
    std::unique_ptr<DIR, int (*)(DIR*)> fstabdir(opendir(fstabdir_name.c_str()), closedir);
    if (!fstabdir) return fstab;

    dirent* dp;
    while ((dp = readdir(fstabdir.get())) != NULL) {
        // skip over name and compatible
        if (dp->d_type != DT_DIR) {
            continue;
        }

/* Early mount vendor and ODM partitions. The fstab info is read from kernel cmdline. */
        // skip if its not 'vendor', 'odm' or 'system'
        if (strcmp(dp->d_name, "odm") && strcmp(dp->d_name, "system") &&
            strcmp(dp->d_name, "vendor")) {
            continue;
        }

        // create <dev> <mnt_point>  <type>  <mnt_flags>  <fsmgr_flags>\n
        std::vector<std::string> fstab_entry;
        std::string file_name;
        std::string value;
        file_name = StringPrintf("%s/%s/dev", fstabdir_name.c_str(), dp->d_name);
        if (!android::base::ReadFileToString(file_name, &value)) {
            LOG(ERROR) << "dt_fstab: Failed to find device for partition " << dp->d_name;
            fstab.clear();
            break;
        }
        // trim the terminating '\0' out
        value.resize(value.size() - 1);
        fstab_entry.push_back(value);
        fstab_entry.push_back(StringPrintf("/%s", dp->d_name));

        file_name = StringPrintf("%s/%s/type", fstabdir_name.c_str(), dp->d_name);
        if (!android::base::ReadFileToString(file_name, &value)) {
            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
            fstab.clear();
            break;
        }
        value.resize(value.size() - 1);
        fstab_entry.push_back(value);

        file_name = StringPrintf("%s/%s/mnt_flags", fstabdir_name.c_str(), dp->d_name);
        if (!android::base::ReadFileToString(file_name, &value)) {
            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
            fstab.clear();
            break;
        }
        value.resize(value.size() - 1);
        fstab_entry.push_back(value);

        file_name = StringPrintf("%s/%s/fsmgr_flags", fstabdir_name.c_str(), dp->d_name);
        if (!android::base::ReadFileToString(file_name, &value)) {
            LOG(ERROR) << "dt_fstab: Failed to find type for partition " << dp->d_name;
            fstab.clear();
            break;
        }
        value.resize(value.size() - 1);
        fstab_entry.push_back(value);

        fstab += android::base::Join(fstab_entry, " ");
        fstab += '\n';
    }

    return fstab;
}

/* Early mount vendor and ODM partitions. The fstab is read from device-tree. */
static bool early_mount() {
    // TODO:  read fstab entries from device tree instead of
    // kernel cmdline
    std::string fstab_file = import_cmdline_fstab();
    if (fstab_file.empty()) {
        LOG(INFO) << "Early mount skipped (missing fstab argument)";
    std::string fstab = import_dt_fstab();
    if (fstab.empty()) {
        LOG(INFO) << "Early mount skipped (missing fstab in device tree)";
        return true;
    }

    std::unique_ptr<struct fstab, void(*)(fstab*)> tab(fs_mgr_read_fstab(fstab_file.c_str()),
                                                       fs_mgr_free_fstab);
    std::unique_ptr<FILE, decltype(&fclose)> fstab_file(
        fmemopen(static_cast<void*>(const_cast<char*>(fstab.c_str())), fstab.length(), "r"), fclose);
    if (!fstab_file) {
        PLOG(ERROR) << "Early mount failed to open fstab file in memory";
        return false;
    }

    std::unique_ptr<struct fstab, decltype(&fs_mgr_free_fstab)> tab(
        fs_mgr_read_fstab_file(fstab_file.get()), fs_mgr_free_fstab);
    if (!tab) {
        LOG(ERROR) << "Early mount failed to read fstab: " << fstab_file;
        // continue to allow booting normally if this happened.
        return true;
        LOG(ERROR) << "Early mount fsmgr failed to load fstab from kernel:" << std::endl << fstab;
        return false;
    }

    // find out fstab records for odm, system and vendor
@@ -674,8 +758,7 @@ static bool early_mount() {
    int count_odm = 0, count_vendor = 0, count_system = 0;

    // create the devices we need..
    device_init(nullptr,
        [&](uevent* uevent) -> coldboot_action_t {
    device_init(nullptr, [&](uevent* uevent) -> coldboot_action_t {
        if (!strncmp(uevent->subsystem, "firmware", 8)) {
            return COLDBOOT_CONTINUE;
        }
@@ -696,8 +779,7 @@ static bool early_mount() {
            // prefix match partition names so we create device nodes for
            // A/B-ed partitions
            if (!found_odm && !strncmp(uevent->partition_name, "odm", 3)) {
                    LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name
                                 << ") partition";
                LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";

                // wait twice for A/B-ed partitions
                count_odm++;
@@ -709,8 +791,7 @@ static bool early_mount() {

                create_this_node = true;
            } else if (!found_system && !strncmp(uevent->partition_name, "system", 6)) {
                    LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name
                                 << ") partition";
                LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";

                count_system++;
                if (!is_ab) {
@@ -721,8 +802,7 @@ static bool early_mount() {

                create_this_node = true;
            } else if (!found_vendor && !strncmp(uevent->partition_name, "vendor", 6)) {
                    LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name
                                 << ") partition";
                LOG(VERBOSE) << "early_mount: found (" << uevent->partition_name << ") partition";
                count_vendor++;
                if (!is_ab) {
                    found_vendor = true;