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

Commit 4c93b256 authored by Daniel Rosenberg's avatar Daniel Rosenberg
Browse files

fs_mgr: Support checkpoints

Adds support for partitions with checkpointing enabled. If the
checkpoint= fs_mgr flag is set, and the system has checkpointing on,
the partition will be mounted in checkpointing mode.

Test: Use vdc checkpoint commands, the checkpoint=fs fs_mgr flag
      in the fstab, and a kernel containing the f2fs checkpoint
      changes. https://lkml.org/lkml/2018/8/21/22
Change-Id: I3ea8da932de06fcfd2eed06b8640a8b1df837f1f
parent 3da42a6c
Loading
Loading
Loading
Loading
+72 −3
Original line number Diff line number Diff line
@@ -805,6 +805,23 @@ static bool call_vdc(const std::vector<std::string>& args) {
    return true;
}

static bool call_vdc_ret(const std::vector<std::string>& args, int* ret) {
    std::vector<char const*> argv;
    argv.emplace_back("/system/bin/vdc");
    for (auto& arg : args) {
        argv.emplace_back(arg.c_str());
    }
    LOG(INFO) << "Calling: " << android::base::Join(argv, ' ');
    int err = android_fork_execvp(argv.size(), const_cast<char**>(argv.data()), ret, false, true);
    if (err != 0) {
        LOG(ERROR) << "vdc call failed with error code: " << err;
        return false;
    }
    LOG(DEBUG) << "vdc finished successfully";
    *ret = WEXITSTATUS(*ret);
    return true;
}

bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
    // Logical partitions are specified with a named partition rather than a
    // block device, so if the block device is a path, then it has already
@@ -823,6 +840,24 @@ bool fs_mgr_update_logical_partition(struct fstab_rec* rec) {
    return true;
}

bool fs_mgr_update_checkpoint_partition(struct fstab_rec* rec) {
    if (fs_mgr_is_checkpoint(rec)) {
        if (!strcmp(rec->fs_type, "f2fs")) {
            std::string opts(rec->fs_options);

            opts += ",checkpoint=disable";
            free(rec->fs_options);
            rec->fs_options = strdup(opts.c_str());
        } else {
            LERROR << rec->fs_type << " does not implement checkpoints.";
        }
    } else if (rec->fs_mgr_flags & MF_CHECKPOINT_BLK) {
        LERROR << "Block based checkpoint not implemented.";
        return false;
    }
    return true;
}

/* When multiple fstab records share the same mount_point, it will
 * try to mount each one in turn, and ignore any duplicates after a
 * first successful mount.
@@ -836,6 +871,7 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
    int mret = -1;
    int mount_errno = 0;
    int attempted_idx = -1;
    int need_checkpoint = -1;
    FsManagerAvbUniquePtr avb_handle(nullptr);

    if (!fstab) {
@@ -882,6 +918,18 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
            }
        }

        if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
            if (need_checkpoint == -1 &&
                !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
                LERROR << "Failed to find if checkpointing is needed. Assuming no.";
                need_checkpoint = 0;
            }
            if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
                LERROR << "Could not set up checkpoint partition, skipping!";
                continue;
            }
        }

        if (fstab->recs[i].fs_mgr_flags & MF_WAIT &&
            !fs_mgr_wait_for_file(fstab->recs[i].blk_device, 20s)) {
            LERROR << "Skipping '" << fstab->recs[i].blk_device << "' during mount_all";
@@ -1081,9 +1129,8 @@ int fs_mgr_do_mount_one(struct fstab_rec *rec)
 * If multiple fstab entries are to be mounted on "n_name", it will try to mount each one
 * in turn, and stop on 1st success, or no more match.
 */
int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                    char *tmp_mount_point)
{
static int fs_mgr_do_mount_helper(struct fstab* fstab, const char* n_name, char* n_blk_device,
                                  char* tmp_mount_point, int need_checkpoint) {
    int i = 0;
    int mount_errors = 0;
    int first_mount_errno = 0;
@@ -1116,6 +1163,18 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
            }
        }

        if (fs_mgr_is_checkpoint(&fstab->recs[i])) {
            if (need_checkpoint == -1 &&
                !call_vdc_ret({"checkpoint", "needsCheckpoint"}, &need_checkpoint)) {
                LERROR << "Failed to find if checkpointing is needed. Assuming no.";
                need_checkpoint = 0;
            }
            if (need_checkpoint == 1 && !fs_mgr_update_checkpoint_partition(&fstab->recs[i])) {
                LERROR << "Could not set up checkpoint partition, skipping!";
                continue;
            }
        }

        /* First check the filesystem if requested */
        if (fstab->recs[i].fs_mgr_flags & MF_WAIT && !fs_mgr_wait_for_file(n_blk_device, 20s)) {
            LERROR << "Skipping mounting '" << n_blk_device << "'";
@@ -1185,6 +1244,16 @@ int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
    return FS_MGR_DOMNT_FAILED;
}

int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device,
                    char* tmp_mount_point) {
    return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, -1);
}

int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device,
                    char* tmp_mount_point, bool needs_cp) {
    return fs_mgr_do_mount_helper(fstab, n_name, n_blk_device, tmp_mount_point, needs_cp);
}

/*
 * mount a tmpfs filesystem at the given point.
 * return 0 on success, non-zero on failure.
+45 −31
Original line number Diff line number Diff line
@@ -110,6 +110,8 @@ static struct flag_list fs_mgr_flags[] = {
        {"sysfs_path=", MF_SYSFS},
        {"defaults", 0},
        {"logical", MF_LOGICAL},
        {"checkpoint=block", MF_CHECKPOINT_BLK},
        {"checkpoint=fs", MF_CHECKPOINT_FS},
        {0, 0},
};

@@ -1004,3 +1006,15 @@ int fs_mgr_has_sysfs_path(const struct fstab_rec *fstab)
int fs_mgr_is_logical(const struct fstab_rec* fstab) {
    return fstab->fs_mgr_flags & MF_LOGICAL;
}

int fs_mgr_is_checkpoint(const struct fstab_rec* fstab) {
    return fstab->fs_mgr_flags & (MF_CHECKPOINT_FS | MF_CHECKPOINT_BLK);
}

int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab) {
    return fstab->fs_mgr_flags & MF_CHECKPOINT_FS;
}

int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab) {
    return fstab->fs_mgr_flags & MF_CHECKPOINT_BLK;
}
+2 −0
Original line number Diff line number Diff line
@@ -113,6 +113,8 @@
#define MF_KEYDIRECTORY    0X4000000
#define MF_SYSFS           0X8000000
#define MF_LOGICAL        0x10000000
#define MF_CHECKPOINT_BLK 0x20000000
#define MF_CHECKPOINT_FS  0x40000000
// clang-format on

#define DM_BUF_SIZE 4096
+2 −0
Original line number Diff line number Diff line
@@ -70,6 +70,8 @@ int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);

int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device,
                    char *tmp_mount_point);
int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device,
                    char* tmp_mount_point, bool need_cp);
int fs_mgr_do_mount_one(struct fstab_rec *rec);
int fs_mgr_do_tmpfs_mount(const char *n_name);
struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab);
+3 −0
Original line number Diff line number Diff line
@@ -86,6 +86,9 @@ int fs_mgr_is_nofail(const struct fstab_rec* fstab);
int fs_mgr_is_latemount(const struct fstab_rec* fstab);
int fs_mgr_is_quota(const struct fstab_rec* fstab);
int fs_mgr_is_logical(const struct fstab_rec* fstab);
int fs_mgr_is_checkpoint(const struct fstab_rec* fstab);
int fs_mgr_is_checkpoint_fs(const struct fstab_rec* fstab);
int fs_mgr_is_checkpoint_blk(const struct fstab_rec* fstab);
int fs_mgr_has_sysfs_path(const struct fstab_rec* fstab);

std::string fs_mgr_get_slot_suffix();