Split fstab mount into 2 phases

This will make it possible to start some key services before mounting
data partition

Bug: 30118894
Change-Id: Ia9f8cc035de6cc0df9a61605864915efa0266d7f
This commit is contained in:
Wei Wang 2016-08-23 11:58:09 -07:00
parent d65a664599
commit abfbec342f
8 changed files with 122 additions and 34 deletions

View file

@ -486,7 +486,7 @@ static int handle_encryptable(const struct fstab_rec* rec)
* first successful mount.
* Returns -1 on error, and FS_MGR_MNTALL_* otherwise.
*/
int fs_mgr_mount_all(struct fstab *fstab)
int fs_mgr_mount_all(struct fstab *fstab, int mount_mode)
{
int i = 0;
int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE;
@ -500,8 +500,10 @@ int fs_mgr_mount_all(struct fstab *fstab)
}
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)) {
/* Don't mount entries that are managed by vold or not for the mount mode*/
if ((fstab->recs[i].fs_mgr_flags & (MF_VOLDMANAGED | MF_RECOVERYONLY)) ||
((mount_mode == MOUNT_MODE_LATE) && !fs_mgr_is_latemount(&fstab->recs[i])) ||
((mount_mode == MOUNT_MODE_EARLY) && fs_mgr_is_latemount(&fstab->recs[i]))) {
continue;
}

View file

@ -78,6 +78,7 @@ static struct flag_list fs_mgr_flags[] = {
{ "formattable", MF_FORMATTABLE },
{ "slotselect", MF_SLOTSELECT },
{ "nofail", MF_NOFAIL },
{ "latemount", MF_LATEMOUNT },
{ "defaults", 0 },
{ 0, 0 },
};
@ -553,3 +554,8 @@ int fs_mgr_is_nofail(struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_NOFAIL;
}
int fs_mgr_is_latemount(struct fstab_rec *fstab)
{
return fstab->fs_mgr_flags & MF_LATEMOUNT;
}

View file

@ -95,7 +95,7 @@ int main(int argc, char *argv[])
fstab = fs_mgr_read_fstab(fstab_file);
if (a_flag) {
return fs_mgr_mount_all(fstab);
return fs_mgr_mount_all(fstab, MOUNT_MODE_DEFAULT);
} else if (n_flag) {
return fs_mgr_do_mount(fstab, n_name, n_blk_dev, 0);
} else if (u_flag) {

View file

@ -48,7 +48,7 @@ __BEGIN_DECLS
*
* <fs_mgr_options> is a comma separated list of flags that control the operation of
* the fs_mgr program. The list includes "wait", which will wait till
* the <source> file exists, and "check", which requests that the fs_mgr
* the <source> file exists, and "check", which requests that the fs_mgr
* run an fscheck program on the <source> before mounting the filesystem.
* If check is specifed on a read-only filesystem, it is ignored.
* Also, "encryptable" means that filesystem can be encrypted.
@ -83,6 +83,7 @@ __BEGIN_DECLS
#define MF_FORMATTABLE 0x4000
#define MF_SLOTSELECT 0x8000
#define MF_FORCEFDEORFBE 0x10000
#define MF_LATEMOUNT 0x20000
#define MF_NOFAIL 0x40000
#define DM_BUF_SIZE 4096

View file

@ -42,6 +42,13 @@ enum verity_mode {
VERITY_MODE_DEFAULT = VERITY_MODE_RESTART
};
// Mount modes
enum mount_mode {
MOUNT_MODE_DEFAULT = 0,
MOUNT_MODE_EARLY = 1,
MOUNT_MODE_LATE = 2
};
/*
* The entries must be kept in the same order as they were seen in the fstab.
* Unless explicitly requested, a lookup on mount point should always
@ -85,7 +92,7 @@ void fs_mgr_free_fstab(struct fstab *fstab);
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1
#define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0
#define FS_MGR_MNTALL_FAIL (-1)
int fs_mgr_mount_all(struct fstab *fstab);
int fs_mgr_mount_all(struct fstab *fstab, int mount_mode);
#define FS_MGR_DOMNT_FAILED (-1)
#define FS_MGR_DOMNT_BUSY (-2)
@ -113,6 +120,7 @@ int fs_mgr_is_noemulatedsd(const struct fstab_rec *fstab);
int fs_mgr_is_notrim(struct fstab_rec *fstab);
int fs_mgr_is_formattable(struct fstab_rec *fstab);
int fs_mgr_is_nofail(struct fstab_rec *fstab);
int fs_mgr_is_latemount(struct fstab_rec *fstab);
int fs_mgr_swapon_all(struct fstab *fstab);
int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer);

View file

@ -465,9 +465,9 @@ exit_success:
*
* start_index: index of the first path in the args list
*/
static void import_late(const std::vector<std::string>& args, size_t start_index) {
static void import_late(const std::vector<std::string>& args, size_t start_index, size_t end_index) {
Parser& parser = Parser::GetInstance();
if (args.size() <= start_index) {
if (end_index <= start_index) {
// Use the default set if no path is given
static const std::vector<std::string> init_directories = {
"/system/etc/init",
@ -479,21 +479,19 @@ static void import_late(const std::vector<std::string>& args, size_t start_index
parser.ParseConfig(dir);
}
} else {
for (size_t i = start_index; i < args.size(); ++i) {
for (size_t i = start_index; i < end_index; ++i) {
parser.ParseConfig(args[i]);
}
}
}
/* mount_all <fstab> [ <path> ]*
/* mount_fstab
*
* This function might request a reboot, in which case it will
* not return.
* Call fs_mgr_mount_all() to mount the given fstab
*/
static int do_mount_all(const std::vector<std::string>& args) {
static int mount_fstab(const char* fstabfile, int mount_mode) {
int ret = -1;
const char* fstabfile = args[1].c_str();
/*
* Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
* do the call in the child to provide protection to the main init
@ -523,7 +521,7 @@ static int do_mount_all(const std::vector<std::string>& args) {
android::base::ScopedLogSeverity info(android::base::INFO);
struct fstab* fstab = fs_mgr_read_fstab(fstabfile);
int child_ret = fs_mgr_mount_all(fstab);
int child_ret = fs_mgr_mount_all(fstab, mount_mode);
fs_mgr_free_fstab(fstab);
if (child_ret == -1) {
PLOG(ERROR) << "fs_mgr_mount_all returned an error";
@ -533,28 +531,38 @@ static int do_mount_all(const std::vector<std::string>& args) {
/* fork failed, return an error */
return -1;
}
return ret;
}
/* Paths of .rc files are specified at the 2nd argument and beyond */
import_late(args, 2);
if (ret == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
/* Queue event based on fs_mgr return code.
*
* code: return code of fs_mgr_mount_all
*
* This function might request a reboot, in which case it will
* not return.
*
* return code is processed based on input code
*/
static int queue_fs_event(int code) {
int ret = code;
if (code == FS_MGR_MNTALL_DEV_NEEDS_ENCRYPTION) {
ActionManager::GetInstance().QueueEventTrigger("encrypt");
} else if (ret == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
} else if (code == FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED) {
property_set("ro.crypto.state", "encrypted");
property_set("ro.crypto.type", "block");
ActionManager::GetInstance().QueueEventTrigger("defaultcrypto");
} else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTED) {
property_set("ro.crypto.state", "unencrypted");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
} else if (code == FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE) {
property_set("ro.crypto.state", "unsupported");
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
} else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY) {
/* Setup a wipe via recovery, and reboot into recovery */
PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery.";
ret = wipe_data_via_recovery("wipe_data_via_recovery");
/* If reboot worked, there is no return. */
} else if (ret == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
} else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) {
if (e4crypt_install_keyring()) {
return -1;
}
@ -564,14 +572,55 @@ static int do_mount_all(const std::vector<std::string>& args) {
// Although encrypted, we have device key, so we do not need to
// do anything different from the nonencrypted case.
ActionManager::GetInstance().QueueEventTrigger("nonencrypted");
} else if (ret > 0) {
PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << ret;
} else if (code > 0) {
PLOG(ERROR) << "fs_mgr_mount_all returned unexpected error " << code;
}
/* else ... < 0: error */
return ret;
}
/* mount_all <fstab> [ <path> ]* [--<options>]*
*
* This function might request a reboot, in which case it will
* not return.
*/
static int do_mount_all(const std::vector<std::string>& args) {
std::size_t na = 0;
bool import_rc = true;
bool queue_event = true;
int mount_mode = MOUNT_MODE_DEFAULT;
const char* fstabfile = args[1].c_str();
std::size_t path_arg_end = args.size();
for (na = args.size() - 1; na > 1; --na) {
if (args[na] == "--early") {
path_arg_end = na;
queue_event = false;
mount_mode = MOUNT_MODE_EARLY;
} else if (args[na] == "--late") {
path_arg_end = na;
import_rc = false;
mount_mode = MOUNT_MODE_LATE;
}
}
int ret = mount_fstab(fstabfile, mount_mode);
if (import_rc) {
/* Paths of .rc files are specified at the 2nd argument and beyond */
import_late(args, 2, path_arg_end);
}
if (queue_event) {
/* queue_fs_event will queue event based on mount_fstab return code
* and return processed return code*/
ret = queue_fs_event(ret);
}
return ret;
}
static int do_swapon_all(const std::vector<std::string>& args) {
struct fstab *fstab;
int ret;

View file

@ -1,4 +1,3 @@
Android Init Language
---------------------
@ -78,6 +77,14 @@ monolithic init .rc files. This additionally will aid in merge
conflict resolution when multiple services are added to the system, as
each one will go into a separate file.
There are two options "early" and "late" in mount_all command
which can be set after optional paths. With "--early" set, the
init executable will skip mounting entries with "latemount" flag
and triggering fs encryption state event. With "--late" set,
init executable will only mount entries with "latemount" flag but skip
importing rc files. By default, no option is set, and mount_all will
mount_all will process all entries in the given fstab.
Actions
-------
Actions are named sequences of commands. Actions have a trigger which
@ -304,10 +311,11 @@ mkdir <path> [mode] [owner] [group]
owned by the root user and root group. If provided, the mode, owner and group
will be updated if the directory exists already.
mount_all <fstab> [ <path> ]*
mount_all <fstab> [ <path> ]* [--<option>]
Calls fs_mgr_mount_all on the given fs_mgr-format fstab and imports .rc files
at the specified paths (e.g., on the partitions just mounted). Refer to the
section of "Init .rc Files" for detail.
at the specified paths (e.g., on the partitions just mounted) with optional
options "early" and "late".
Refer to the section of "Init .rc Files" for detail.
mount <type> <device> <dir> [ <flag> ]* [<options>]
Attempt to mount the named device at the directory <dir>

View file

@ -236,6 +236,9 @@ on init
export DOWNLOAD_CACHE /data/cache
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
# Healthd can trigger a full boot from charger mode by signaling this
# property when the power button is held.
on property:sys.boot_from_charger_mode=1
@ -258,6 +261,11 @@ on firmware_mounts_complete
# Mount filesystems and start core system services.
on late-init
trigger early-fs
# Mount fstab in init.{$device}.rc by mount_all command. Optional parameter
# '--early' can be specified to skip entries with 'latemount'.
# /system and /vendor must be mounted by the end of the fs stage,
# while /data is optional.
trigger fs
trigger post-fs
@ -266,9 +274,18 @@ on late-init
# issued fs triggers have completed.
trigger load_system_props_action
# Mount fstab in init.{$device}.rc by mount_all with '--late' parameter
# to only mount entries with 'latemount'. This is needed if '--early' is
# specified in the previous mount_all command on the fs stage.
# With /system mounted and properties form /system + /factory available,
# some services can be started.
trigger late-fs
# Now we can mount /data. File encryption requires keymaster to decrypt
# /data, which in turn can only be loaded when system properties are present
# /data, which in turn can only be loaded when system properties are present.
trigger post-fs-data
# Load persist properties and override properties (if enabled) from /data.
trigger load_persist_props_action
# Remove a file to wake up anything waiting for firmware.
@ -479,9 +496,6 @@ on boot
hostname localhost
domainname localdomain
# set RLIMIT_NICE to allow priorities from 19 to -20
setrlimit 13 40 40
# Memory management. Basic kernel parameters, and allow the high
# level system server to be able to adjust the kernel OOM driver
# parameters to match how it is managing things.