fs_mgr: fs_mgr_has_shared_blocks() needs logical blk_device

For logical partitions, the fstab supplied during
fs_mgr_overlayfs_setup() does not have the correct blk_device and
thus check in fs_mgr_has_shared_blocks() inside
fs_mgr_overlayfs_enabled() will fail to provide the correct status.

Call fs_mgr_update_logical_partition() to fix this up.  Side effect
is an API change where fstab can no longer be considered const when
passed into fs_mgr_overlayfs_mount_all() and
fs_mgr_overlayfs_required_devices().

Some additional minor cleanup as well.  Move fs_mgr_rm_all() higher
up as-is in the file as it has no dependencies, which will complicate
future changes.  Add --help to adb-remount-test.sh unit test script,
improve error handling and checking.

Test: adb-remount-test.sh
Bug: 109821005
Bug: 117605276
Change-Id: I548d3797d49661529490d1a0bf96b63e57491704
This commit is contained in:
Mark Salyzyn 2018-10-25 09:02:08 -07:00
parent 55d31ecd86
commit 1b066c313b
3 changed files with 92 additions and 73 deletions

View file

@ -41,6 +41,7 @@
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <ext4_utils/ext4_utils.h>
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
#include <fs_mgr_overlayfs.h>
#include <fstab/fstab.h>
@ -127,13 +128,63 @@ bool fs_mgr_filesystem_has_space(const char* mount_point) {
return (vst.f_bfree >= (vst.f_blocks * kPercentThreshold / 100));
}
bool fs_mgr_overlayfs_enabled(const struct fstab_rec* fsrec) {
bool fs_mgr_overlayfs_enabled(struct fstab_rec* fsrec) {
// readonly filesystem, can not be mount -o remount,rw
// if squashfs or if free space is (near) zero making such a remount
// virtually useless, or if there are shared blocks that prevent remount,rw
return ("squashfs"s == fsrec->fs_type) ||
fs_mgr_has_shared_blocks(fsrec->mount_point, fsrec->blk_device) ||
!fs_mgr_filesystem_has_space(fsrec->mount_point);
if (("squashfs"s == fsrec->fs_type) || !fs_mgr_filesystem_has_space(fsrec->mount_point)) {
return true;
}
if (fs_mgr_is_logical(fsrec)) {
fs_mgr_update_logical_partition(fsrec);
}
return fs_mgr_has_shared_blocks(fsrec->mount_point, fsrec->blk_device);
}
bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
auto save_errno = errno;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
if (!dir) {
if (errno == ENOENT) {
errno = save_errno;
return true;
}
PERROR << "opendir " << path << " depth=" << level;
if ((errno == EPERM) && (level != 0)) {
errno = save_errno;
return true;
}
return false;
}
dirent* entry;
auto ret = true;
while ((entry = readdir(dir.get()))) {
if (("."s == entry->d_name) || (".."s == entry->d_name)) continue;
auto file = path + "/" + entry->d_name;
if (entry->d_type == DT_UNKNOWN) {
struct stat st;
save_errno = errno;
if (!lstat(file.c_str(), &st) && (st.st_mode & S_IFDIR)) entry->d_type = DT_DIR;
errno = save_errno;
}
if (entry->d_type == DT_DIR) {
ret &= fs_mgr_rm_all(file, change, level + 1);
if (!rmdir(file.c_str())) {
if (change) *change = true;
} else {
if (errno != ENOENT) ret = false;
PERROR << "rmdir " << file << " depth=" << level;
}
continue;
}
if (!unlink(file.c_str())) {
if (change) *change = true;
} else {
if (errno != ENOENT) ret = false;
PERROR << "rm " << file << " depth=" << level;
}
}
return ret;
}
const auto kUpperName = "upper"s;
@ -235,7 +286,7 @@ std::vector<std::string> fs_mgr_overlayfs_verity_enabled_list() {
return ret;
}
bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
bool fs_mgr_wants_overlayfs(fstab_rec* fsrec) {
if (!fsrec) return false;
auto fsrec_mount_point = fsrec->mount_point;
@ -260,53 +311,6 @@ bool fs_mgr_wants_overlayfs(const fstab_rec* fsrec) {
return true;
}
bool fs_mgr_rm_all(const std::string& path, bool* change = nullptr, int level = 0) {
auto save_errno = errno;
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
if (!dir) {
if (errno == ENOENT) {
errno = save_errno;
return true;
}
PERROR << "opendir " << path << " depth=" << level;
if ((errno == EPERM) && (level != 0)) {
errno = save_errno;
return true;
}
return false;
}
dirent* entry;
auto ret = true;
while ((entry = readdir(dir.get()))) {
if (("."s == entry->d_name) || (".."s == entry->d_name)) continue;
auto file = path + "/" + entry->d_name;
if (entry->d_type == DT_UNKNOWN) {
struct stat st;
save_errno = errno;
if (!lstat(file.c_str(), &st) && (st.st_mode & S_IFDIR)) entry->d_type = DT_DIR;
errno = save_errno;
}
if (entry->d_type == DT_DIR) {
ret &= fs_mgr_rm_all(file, change, level + 1);
if (!rmdir(file.c_str())) {
if (change) *change = true;
} else {
if (errno != ENOENT) ret = false;
PERROR << "rmdir " << file << " depth=" << level;
}
continue;
}
if (!unlink(file.c_str())) {
if (change) *change = true;
} else {
if (errno != ENOENT) ret = false;
PERROR << "rm " << file << " depth=" << level;
}
}
return ret;
}
constexpr char kOverlayfsFileContext[] = "u:object_r:overlayfs_file:s0";
bool fs_mgr_overlayfs_setup_dir(const std::string& dir, std::string* overlay, bool* change) {
@ -532,8 +536,7 @@ bool fs_mgr_overlayfs_mount(const std::string& mount_point) {
}
}
std::vector<std::string> fs_mgr_candidate_list(const fstab* fstab,
const char* mount_point = nullptr) {
std::vector<std::string> fs_mgr_candidate_list(fstab* fstab, const char* mount_point = nullptr) {
std::vector<std::string> mounts;
if (!fstab) return mounts;
@ -734,7 +737,7 @@ bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device)
} // namespace
bool fs_mgr_overlayfs_mount_all(const fstab* fstab) {
bool fs_mgr_overlayfs_mount_all(fstab* fstab) {
auto ret = false;
if (!fs_mgr_wants_overlayfs()) return ret;
@ -761,7 +764,7 @@ bool fs_mgr_overlayfs_mount_all(const fstab* fstab) {
return ret;
}
std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab) {
std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab) {
if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) {
return {};
}

View file

@ -21,8 +21,8 @@
#include <string>
#include <vector>
bool fs_mgr_overlayfs_mount_all(const fstab* fstab);
std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab);
bool fs_mgr_overlayfs_mount_all(fstab* fstab);
std::vector<std::string> fs_mgr_overlayfs_required_devices(fstab* fstab);
bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr,
bool* change = nullptr);
bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr);

View file

@ -1,14 +1,21 @@
#! /bin/bash
#
# adb remount tests (overlayfs focus)
#
# Conditions:
# - Must be a userdebug build.
# - Must be in adb mode.
# - Kernel must have overlayfs enabled and patched to support override_creds.
# - Must have either squashfs, ext4-dedupe or right-sized partitions.
# - Minimum expectation system and vender are overlayfs covered partitions.
#
USAGE="USAGE: `basename ${0}` [-s <SerialNumber>]
adb remount tests (overlayfs focus)
Conditions:
- Must be a userdebug build.
- Must be in adb mode.
- Kernel must have overlayfs enabled and patched to support override_creds.
- Must have either squashfs, ext4-dedupe or right-sized partitions.
- Minimum expectation system and vender are overlayfs covered partitions.
"
if [ X"${1}" = X"--help" -o X"${1}" = X"-h" -o X"${1}" = X"-?" ]; then
echo "${USAGE}" >&2
exit 0
fi
# Helper Variables
@ -86,11 +93,15 @@ adb_reboot() {
adb reboot remount-test
}
[ "USAGE: adb_wait
[ "USAGE: adb_wait [timeout]
Returns: waits until the device has returned" ]
Returns: waits until the device has returned or the optional timeout" ]
adb_wait() {
adb wait-for-device
if [ -n "${1}" ]; then
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
else
adb wait-for-device
fi
}
[ "USAGE: adb_root
@ -178,6 +189,10 @@ if [ X"-s" = X"${1}" -a -n "${2}" ]; then
fi
inFastboot && die "device in fastboot mode"
if ! inAdb; then
echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode ... waiting 2 minutes"
adb_wait 2m
fi
inAdb || die "device not in adb mode"
isDebuggable || die "device not a debug build"
@ -205,8 +220,9 @@ adb_sh ls -d /cache/overlay </dev/null >/dev/null 2>&1 ||
adb_reboot &&
adb_wait &&
adb_sh df -k </dev/null | head -1 &&
adb_sh df -k </dev/null | grep "^overlay " &&
adb_sh df -k </dev/null | grep "^overlay .* /system\$" >/dev/null ||
adb_sh df -k </dev/null | grep "^overlay " ||
die "overlay takeover failed"
adb_sh df -k </dev/null | grep "^overlay .* /system\$" >/dev/null ||
echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover before remount not complete" >&2
adb_root &&