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
This commit is contained in:
Daniel Rosenberg 2018-08-28 01:41:18 -07:00
parent 3da42a6c05
commit 4c93b256f6
5 changed files with 124 additions and 34 deletions

View file

@ -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.

View file

@ -80,37 +80,39 @@ static struct flag_list mount_flags[] = {
};
static struct flag_list fs_mgr_flags[] = {
{"wait", MF_WAIT},
{"check", MF_CHECK},
{"encryptable=", MF_CRYPT},
{"forceencrypt=", MF_FORCECRYPT},
{"fileencryption=", MF_FILEENCRYPTION},
{"forcefdeorfbe=", MF_FORCEFDEORFBE},
{"keydirectory=", MF_KEYDIRECTORY},
{"nonremovable", MF_NONREMOVABLE},
{"voldmanaged=", MF_VOLDMANAGED},
{"length=", MF_LENGTH},
{"recoveryonly", MF_RECOVERYONLY},
{"swapprio=", MF_SWAPPRIO},
{"zramsize=", MF_ZRAMSIZE},
{"max_comp_streams=", MF_MAX_COMP_STREAMS},
{"verifyatboot", MF_VERIFYATBOOT},
{"verify", MF_VERIFY},
{"avb", MF_AVB},
{"noemulatedsd", MF_NOEMULATEDSD},
{"notrim", MF_NOTRIM},
{"formattable", MF_FORMATTABLE},
{"slotselect", MF_SLOTSELECT},
{"nofail", MF_NOFAIL},
{"latemount", MF_LATEMOUNT},
{"reservedsize=", MF_RESERVEDSIZE},
{"quota", MF_QUOTA},
{"eraseblk=", MF_ERASEBLKSIZE},
{"logicalblk=", MF_LOGICALBLKSIZE},
{"sysfs_path=", MF_SYSFS},
{"defaults", 0},
{"logical", MF_LOGICAL},
{0, 0},
{"wait", MF_WAIT},
{"check", MF_CHECK},
{"encryptable=", MF_CRYPT},
{"forceencrypt=", MF_FORCECRYPT},
{"fileencryption=", MF_FILEENCRYPTION},
{"forcefdeorfbe=", MF_FORCEFDEORFBE},
{"keydirectory=", MF_KEYDIRECTORY},
{"nonremovable", MF_NONREMOVABLE},
{"voldmanaged=", MF_VOLDMANAGED},
{"length=", MF_LENGTH},
{"recoveryonly", MF_RECOVERYONLY},
{"swapprio=", MF_SWAPPRIO},
{"zramsize=", MF_ZRAMSIZE},
{"max_comp_streams=", MF_MAX_COMP_STREAMS},
{"verifyatboot", MF_VERIFYATBOOT},
{"verify", MF_VERIFY},
{"avb", MF_AVB},
{"noemulatedsd", MF_NOEMULATEDSD},
{"notrim", MF_NOTRIM},
{"formattable", MF_FORMATTABLE},
{"slotselect", MF_SLOTSELECT},
{"nofail", MF_NOFAIL},
{"latemount", MF_LATEMOUNT},
{"reservedsize=", MF_RESERVEDSIZE},
{"quota", MF_QUOTA},
{"eraseblk=", MF_ERASEBLKSIZE},
{"logicalblk=", MF_LOGICALBLKSIZE},
{"sysfs_path=", MF_SYSFS},
{"defaults", 0},
{"logical", MF_LOGICAL},
{"checkpoint=block", MF_CHECKPOINT_BLK},
{"checkpoint=fs", MF_CHECKPOINT_FS},
{0, 0},
};
#define EM_AES_256_XTS 1
@ -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;
}

View file

@ -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

View file

@ -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);

View file

@ -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();