Merge "init: add umount_all builtin."

This commit is contained in:
Yifan Hong 2019-04-16 22:46:52 +00:00 committed by Gerrit Code Review
commit e438843ead
11 changed files with 166 additions and 18 deletions

View file

@ -1268,6 +1268,46 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
}
}
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) {
AvbUniquePtr avb_handle(nullptr);
int ret = FsMgrUmountStatus::SUCCESS;
for (auto& current_entry : *fstab) {
if (!IsMountPointMounted(current_entry.mount_point)) {
continue;
}
if (umount(current_entry.mount_point.c_str()) == -1) {
PERROR << "Failed to umount " << current_entry.mount_point;
ret |= FsMgrUmountStatus::ERROR_UMOUNT;
continue;
}
if (current_entry.fs_mgr_flags.logical) {
if (!fs_mgr_update_logical_partition(&current_entry)) {
LERROR << "Could not get logical partition blk_device, skipping!";
ret |= FsMgrUmountStatus::ERROR_DEVICE_MAPPER;
continue;
}
}
if (current_entry.fs_mgr_flags.avb || !current_entry.avb_keys.empty()) {
if (!AvbHandle::TearDownAvbHashtree(&current_entry, true /* wait */)) {
LERROR << "Failed to tear down AVB on mount point: " << current_entry.mount_point;
ret |= FsMgrUmountStatus::ERROR_VERITY;
continue;
}
} else if ((current_entry.fs_mgr_flags.verify)) {
if (!fs_mgr_teardown_verity(&current_entry, true /* wait */)) {
LERROR << "Failed to tear down verified partition on mount point: "
<< current_entry.mount_point;
ret |= FsMgrUmountStatus::ERROR_VERITY;
continue;
}
}
}
return ret;
}
// wrapper to __mount() and expects a fully prepared fstab_rec,
// unlike fs_mgr_do_mount which does more things with avb / verity etc.
int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) {

View file

@ -193,7 +193,7 @@ bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_s
timeout_ms, path);
}
bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
DeviceMapper& dm = DeviceMapper::Instance();
std::string path;
if (timeout_ms > std::chrono::milliseconds::zero()) {
@ -206,6 +206,13 @@ bool DestroyLogicalPartition(const std::string& name, const std::chrono::millise
LERROR << "Timed out waiting for device path to unlink: " << path;
return false;
}
return true;
}
bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) {
if (!UnmapDevice(name, timeout_ms)) {
return false;
}
LINFO << "Unmapped logical partition " << name;
return true;
}

View file

@ -103,3 +103,11 @@ int load_verity_state(const android::fs_mgr::FstabEntry& entry, int* mode);
bool fs_mgr_is_ext4(const std::string& blk_device);
bool fs_mgr_is_f2fs(const std::string& blk_device);
bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab, bool wait);
namespace android {
namespace fs_mgr {
bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms);
} // namespace fs_mgr
} // namespace android

View file

@ -44,6 +44,7 @@
#include "fec/io.h"
#include "fs_mgr.h"
#include "fs_mgr_dm_linear.h"
#include "fs_mgr_priv.h"
// Realistically, this file should be part of the android::fs_mgr namespace;
@ -882,3 +883,12 @@ out:
return retval;
}
bool fs_mgr_teardown_verity(FstabEntry* entry, bool wait) {
const std::string mount_point(basename(entry->mount_point.c_str()));
if (!android::fs_mgr::UnmapDevice(mount_point, wait ? 1000ms : 0ms)) {
return false;
}
LINFO << "Unmapped verity device " << mount_point;
return true;
}

View file

@ -93,3 +93,14 @@ int fs_mgr_setup_verity(android::fs_mgr::FstabEntry* fstab, bool wait_for_verity
// specified, the super partition for the corresponding metadata slot will be
// returned. Otherwise, it will use the current slot.
std::string fs_mgr_get_super_partition_name(int slot = -1);
enum FsMgrUmountStatus : int {
SUCCESS = 0,
ERROR_UNKNOWN = 1 << 0,
ERROR_UMOUNT = 1 << 1,
ERROR_VERITY = 1 << 2,
ERROR_DEVICE_MAPPER = 1 << 3,
};
// fs_mgr_umount_all() is the reverse of fs_mgr_mount_all. In particular,
// it destroys verity devices from device mapper after the device is unmounted.
int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab);

View file

@ -449,6 +449,29 @@ AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait
return AvbHashtreeResult::kSuccess;
}
bool AvbHandle::TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait) {
if (!fstab_entry) {
return false;
}
const std::string device_name(GetVerityDeviceName(*fstab_entry));
// TODO: remove duplicated code with UnmapDevice()
android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance();
std::string path;
if (wait) {
dm.GetDmDevicePathByName(device_name, &path);
}
if (!dm.DeleteDevice(device_name)) {
return false;
}
if (!path.empty() && !WaitForFile(path, 1000ms, FileWaitMode::DoesNotExist)) {
return false;
}
return true;
}
std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) const {
if (vbmeta_images_.size() < 1) {
return "";

View file

@ -110,6 +110,11 @@ class AvbHandle {
static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry,
bool wait_for_verity_dev = true);
// Tear down dm devices created by SetUp[Standalone]AvbHashtree
// The 'wait' parameter makes this function wait for the verity device to get destroyed
// before return.
static bool TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait);
static bool IsDeviceUnlocked();
std::string GetSecurityPatchLevel(const FstabEntry& fstab_entry) const;

View file

@ -27,6 +27,7 @@
// Target functions to test:
using android::fs_mgr::BytesToHex;
using android::fs_mgr::FileWaitMode;
using android::fs_mgr::HexToBytes;
using android::fs_mgr::NibbleValue;
using android::fs_mgr::WaitForFile;
@ -175,7 +176,7 @@ TEST(BasicUtilTest, WaitForFileDeferCreation) {
// Waits this path.
base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir");
ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */));
auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms);
auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms, FileWaitMode::Exists);
// Sleeps 100ms before creating the wait_path.
std::this_thread::sleep_for(100ms);
@ -196,7 +197,7 @@ TEST(BasicUtilTest, WaitForFileDeferCreationFailure) {
// Waits this path.
base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir");
ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */));
auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms);
auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms, FileWaitMode::Exists);
// Sleeps 100ms before creating the wait_path.
std::this_thread::sleep_for(100ms);

View file

@ -82,12 +82,17 @@ std::string BytesToHex(const uint8_t* bytes, size_t bytes_len) {
return hex;
}
bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout) {
// TODO: remove duplicate code with fs_mgr_wait_for_file
bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout,
FileWaitMode file_wait_mode) {
auto start_time = std::chrono::steady_clock::now();
while (true) {
if (0 == access(filename.c_str(), F_OK) || errno != ENOENT) {
return true;
int rv = access(filename.c_str(), F_OK);
if (file_wait_mode == FileWaitMode::Exists) {
if (!rv || errno != ENOENT) return true;
} else if (file_wait_mode == FileWaitMode::DoesNotExist) {
if (rv && errno == ENOENT) return true;
}
std::this_thread::sleep_for(50ms);

View file

@ -52,7 +52,9 @@ bool HexToBytes(uint8_t* bytes, size_t bytes_len, const std::string& hex);
std::string BytesToHex(const uint8_t* bytes, size_t bytes_len);
bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout);
enum class FileWaitMode { Exists, DoesNotExist };
bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout,
FileWaitMode wait_mode = FileWaitMode::Exists);
bool IsDeviceUnlocked();

View file

@ -451,13 +451,13 @@ static void import_late(const std::vector<std::string>& args, size_t start_index
if (false) DumpState();
}
/* mount_fstab
/* handle_fstab
*
* Call fs_mgr_mount_all() to mount the given fstab
* Read the given fstab file and execute func on it.
*/
static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
static Result<int> handle_fstab(const std::string& fstabfile, std::function<int(Fstab*)> func) {
/*
* Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and
* Call fs_mgr_[u]mount_all() to [u]mount all filesystems. We fork(2) and
* 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.
@ -478,25 +478,51 @@ static Result<int> mount_fstab(const char* fstabfile, int mount_mode) {
return Error() << "child aborted";
}
} else if (pid == 0) {
/* child, call fs_mgr_mount_all() */
/* child, call fs_mgr_[u]mount_all() */
// So we can always see what fs_mgr_mount_all() does.
// So we can always see what fs_mgr_[u]mount_all() does.
// Only needed if someone explicitly changes the default log level in their init.rc.
android::base::ScopedLogSeverity info(android::base::INFO);
Fstab fstab;
ReadFstabFromFile(fstabfile, &fstab);
int child_ret = fs_mgr_mount_all(&fstab, mount_mode);
if (child_ret == -1) {
PLOG(ERROR) << "fs_mgr_mount_all returned an error";
}
int child_ret = func(&fstab);
_exit(child_ret);
} else {
return Error() << "fork() failed";
}
}
/* mount_fstab
*
* Call fs_mgr_mount_all() to mount the given fstab
*/
static Result<int> mount_fstab(const std::string& fstabfile, int mount_mode) {
return handle_fstab(fstabfile, [mount_mode](Fstab* fstab) {
int ret = fs_mgr_mount_all(fstab, mount_mode);
if (ret == -1) {
PLOG(ERROR) << "fs_mgr_mount_all returned an error";
}
return ret;
});
}
/* umount_fstab
*
* Call fs_mgr_umount_all() to umount the given fstab
*/
static Result<int> umount_fstab(const std::string& fstabfile) {
return handle_fstab(fstabfile, [](Fstab* fstab) {
int ret = fs_mgr_umount_all(fstab);
if (ret != 0) {
PLOG(ERROR) << "fs_mgr_umount_all returned " << ret;
}
return ret;
});
}
/* Queue event based on fs_mgr return code.
*
* code: return code of fs_mgr_mount_all
@ -583,7 +609,7 @@ static Result<Success> do_mount_all(const BuiltinArguments& args) {
bool import_rc = true;
bool queue_event = true;
int mount_mode = MOUNT_MODE_DEFAULT;
const char* fstabfile = args[1].c_str();
const auto& fstabfile = args[1];
std::size_t path_arg_end = args.size();
const char* prop_post_fix = "default";
@ -626,6 +652,15 @@ static Result<Success> do_mount_all(const BuiltinArguments& args) {
return Success();
}
/* umount_all <fstab> */
static Result<Success> do_umount_all(const BuiltinArguments& args) {
auto umount_fstab_return_code = umount_fstab(args[1]);
if (!umount_fstab_return_code) {
return Error() << "umount_fstab() failed " << umount_fstab_return_code.error();
}
return Success();
}
static Result<Success> do_swapon_all(const BuiltinArguments& args) {
Fstab fstab;
if (!ReadFstabFromFile(args[1], &fstab)) {
@ -1165,6 +1200,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const {
{"mount", {3, kMax, {false, do_mount}}},
{"parse_apex_configs", {0, 0, {false, do_parse_apex_configs}}},
{"umount", {1, 1, {false, do_umount}}},
{"umount_all", {1, 1, {false, do_umount_all}}},
{"readahead", {1, 2, {true, do_readahead}}},
{"restart", {1, 1, {false, do_restart}}},
{"restorecon", {1, kMax, {true, do_restorecon}}},