Merge "Fix mounting /data on Virtual A/B devices without metadata encryption." am: 21394f6e85 am: 3f52b42db0
Change-Id: Ic49aeb48693985d0b2ee38230c9e3a55698d3a83
This commit is contained in:
commit
593c5eb8cb
1 changed files with 85 additions and 0 deletions
|
|
@ -101,6 +101,7 @@ using android::base::Timer;
|
||||||
using android::base::unique_fd;
|
using android::base::unique_fd;
|
||||||
using android::dm::DeviceMapper;
|
using android::dm::DeviceMapper;
|
||||||
using android::dm::DmDeviceState;
|
using android::dm::DmDeviceState;
|
||||||
|
using android::dm::DmTargetLinear;
|
||||||
|
|
||||||
// Realistically, this file should be part of the android::fs_mgr namespace;
|
// Realistically, this file should be part of the android::fs_mgr namespace;
|
||||||
using namespace android::fs_mgr;
|
using namespace android::fs_mgr;
|
||||||
|
|
@ -1114,6 +1115,83 @@ std::string fs_mgr_find_bow_device(const std::string& block_device) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static constexpr const char* kUserdataWrapperName = "userdata-wrapper";
|
||||||
|
|
||||||
|
static void WrapUserdata(FstabEntry* entry, dev_t dev, const std::string& block_device) {
|
||||||
|
DeviceMapper& dm = DeviceMapper::Instance();
|
||||||
|
if (dm.GetState(kUserdataWrapperName) != DmDeviceState::INVALID) {
|
||||||
|
// This will report failure for us. If we do fail to get the path,
|
||||||
|
// we leave the device unwrapped.
|
||||||
|
dm.GetDmDevicePathByName(kUserdataWrapperName, &entry->blk_device);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_fd fd(open(block_device.c_str(), O_RDONLY | O_CLOEXEC));
|
||||||
|
if (fd < 0) {
|
||||||
|
PLOG(ERROR) << "open failed: " << entry->blk_device;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dev_str = android::base::StringPrintf("%u:%u", major(dev), minor(dev));
|
||||||
|
uint64_t sectors = get_block_device_size(fd) / 512;
|
||||||
|
|
||||||
|
android::dm::DmTable table;
|
||||||
|
table.Emplace<DmTargetLinear>(0, sectors, dev_str, 0);
|
||||||
|
|
||||||
|
std::string dm_path;
|
||||||
|
if (!dm.CreateDevice(kUserdataWrapperName, table, &dm_path, 20s)) {
|
||||||
|
LOG(ERROR) << "Failed to create userdata wrapper device";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
entry->blk_device = dm_path;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When using Virtual A/B, partitions can be backed by /data and mapped with
|
||||||
|
// device-mapper in first-stage init. This can happen when merging an OTA or
|
||||||
|
// when using adb remount to house "scratch". In this case, /data cannot be
|
||||||
|
// mounted directly off the userdata block device, and e2fsck will refuse to
|
||||||
|
// scan it, because the kernel reports the block device as in-use.
|
||||||
|
//
|
||||||
|
// As a workaround, when mounting /data, we create a trivial dm-linear wrapper
|
||||||
|
// if the underlying block device already has dependencies. Note that we make
|
||||||
|
// an exception for metadata-encrypted devices, since dm-default-key is already
|
||||||
|
// a wrapper.
|
||||||
|
static void WrapUserdataIfNeeded(FstabEntry* entry, const std::string& actual_block_device = {}) {
|
||||||
|
const auto& block_device =
|
||||||
|
actual_block_device.empty() ? entry->blk_device : actual_block_device;
|
||||||
|
if (entry->mount_point != "/data" || !entry->key_dir.empty() ||
|
||||||
|
android::base::StartsWith(block_device, "/dev/block/dm-")) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct stat st;
|
||||||
|
if (stat(block_device.c_str(), &st) < 0) {
|
||||||
|
PLOG(ERROR) << "stat failed: " << block_device;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string path = android::base::StringPrintf("/sys/dev/block/%u:%u/holders",
|
||||||
|
major(st.st_rdev), minor(st.st_rdev));
|
||||||
|
std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), closedir);
|
||||||
|
if (!dir) {
|
||||||
|
PLOG(ERROR) << "opendir failed: " << path;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct dirent* d;
|
||||||
|
bool has_holders = false;
|
||||||
|
while ((d = readdir(dir.get())) != nullptr) {
|
||||||
|
if (strcmp(d->d_name, ".") != 0 && strcmp(d->d_name, "..") != 0) {
|
||||||
|
has_holders = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_holders) {
|
||||||
|
WrapUserdata(entry, st.st_rdev, block_device);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static bool IsMountPointMounted(const std::string& mount_point) {
|
static bool IsMountPointMounted(const std::string& mount_point) {
|
||||||
// Check if this is already mounted.
|
// Check if this is already mounted.
|
||||||
Fstab fstab;
|
Fstab fstab;
|
||||||
|
|
@ -1193,6 +1271,8 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WrapUserdataIfNeeded(¤t_entry);
|
||||||
|
|
||||||
if (!checkpoint_manager.Update(¤t_entry)) {
|
if (!checkpoint_manager.Update(¤t_entry)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -1463,6 +1543,9 @@ int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) {
|
||||||
}
|
}
|
||||||
std::string block_device;
|
std::string block_device;
|
||||||
if (auto entry = GetEntryForMountPoint(&proc_mounts, "/data"); entry != nullptr) {
|
if (auto entry = GetEntryForMountPoint(&proc_mounts, "/data"); entry != nullptr) {
|
||||||
|
// Note: we don't care about a userdata wrapper here, since it's safe
|
||||||
|
// to remount on top of the bow device instead, there will be no
|
||||||
|
// conflicts.
|
||||||
block_device = entry->blk_device;
|
block_device = entry->blk_device;
|
||||||
} else {
|
} else {
|
||||||
LERROR << "/data is not mounted";
|
LERROR << "/data is not mounted";
|
||||||
|
|
@ -1581,6 +1664,8 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WrapUserdataIfNeeded(&fstab_entry, n_blk_device);
|
||||||
|
|
||||||
if (!checkpoint_manager.Update(&fstab_entry, n_blk_device)) {
|
if (!checkpoint_manager.Update(&fstab_entry, n_blk_device)) {
|
||||||
LERROR << "Could not set up checkpoint partition, skipping!";
|
LERROR << "Could not set up checkpoint partition, skipping!";
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue