diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 75ebd94c8..cb6903756 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -1351,38 +1351,9 @@ int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) { return ret; } -static std::string GetUserdataBlockDevice() { - Fstab fstab; - if (!ReadFstabFromFile("/proc/mounts", &fstab)) { - LERROR << "Failed to read /proc/mounts"; - return ""; - } - auto entry = GetEntryForMountPoint(&fstab, "/data"); - if (entry == nullptr) { - LERROR << "Didn't find /data mount point in /proc/mounts"; - return ""; - } - return entry->blk_device; -} - int fs_mgr_remount_userdata_into_checkpointing(Fstab* fstab) { - const std::string& block_device = GetUserdataBlockDevice(); - LINFO << "Userdata is mounted on " << block_device; - auto entry = std::find_if(fstab->begin(), fstab->end(), [&block_device](const FstabEntry& e) { - if (e.mount_point != "/data") { - return false; - } - if (e.blk_device == block_device) { - return true; - } - DeviceMapper& dm = DeviceMapper::Instance(); - std::string path; - if (!dm.GetDmDevicePathByName("userdata", &path)) { - return false; - } - return path == block_device; - }); - if (entry == fstab->end()) { + auto entry = GetMountedEntryForUserdata(fstab); + if (entry == nullptr) { LERROR << "Can't find /data in fstab"; return -1; } diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index d216458d8..c81a07941 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -40,6 +40,7 @@ using android::base::EndsWith; using android::base::ParseByteCount; using android::base::ParseInt; using android::base::ReadFileToString; +using android::base::Readlink; using android::base::Split; using android::base::StartsWith; @@ -809,6 +810,89 @@ std::vector GetEntriesForMountPoint(Fstab* fstab, const std::string return entries; } +static std::string ResolveBlockDevice(const std::string& block_device) { + if (!StartsWith(block_device, "/dev/block/")) { + LWARNING << block_device << " is not a block device"; + return block_device; + } + std::string name = block_device.substr(5); + if (!StartsWith(name, "block/dm-")) { + // Not a dm-device, but might be a symlink. Optimistically try to readlink. + std::string result; + if (Readlink(block_device, &result)) { + return result; + } else if (errno == EINVAL) { + // After all, it wasn't a symlink. + return block_device; + } else { + LERROR << "Failed to readlink " << block_device; + return ""; + } + } + // It's a dm-device, let's find what's inside! + std::string sys_dir = "/sys/" + name; + while (true) { + std::string slaves_dir = sys_dir + "/slaves"; + std::unique_ptr dir(opendir(slaves_dir.c_str()), closedir); + if (!dir) { + LERROR << "Failed to open " << slaves_dir; + return ""; + } + std::string sub_device_name = ""; + for (auto entry = readdir(dir.get()); entry; entry = readdir(dir.get())) { + if (entry->d_type != DT_LNK) continue; + if (!sub_device_name.empty()) { + LERROR << "Too many slaves in " << slaves_dir; + return ""; + } + sub_device_name = entry->d_name; + } + if (sub_device_name.empty()) { + LERROR << "No slaves in " << slaves_dir; + return ""; + } + if (!StartsWith(sub_device_name, "dm-")) { + // Not a dm-device! We can stop now. + return "/dev/block/" + sub_device_name; + } + // Still a dm-device, keep digging. + sys_dir = "/sys/block/" + sub_device_name; + } +} + +FstabEntry* GetMountedEntryForUserdata(Fstab* fstab) { + Fstab mounts; + if (!ReadFstabFromFile("/proc/mounts", &mounts)) { + LERROR << "Failed to read /proc/mounts"; + return nullptr; + } + auto mounted_entry = GetEntryForMountPoint(&mounts, "/data"); + if (mounted_entry == nullptr) { + LWARNING << "/data is not mounted"; + return nullptr; + } + std::string resolved_block_device = ResolveBlockDevice(mounted_entry->blk_device); + if (resolved_block_device.empty()) { + return nullptr; + } + LINFO << "/data is mounted on " << resolved_block_device; + for (auto& entry : *fstab) { + if (entry.mount_point != "/data") { + continue; + } + std::string block_device; + if (!Readlink(entry.blk_device, &block_device)) { + LWARNING << "Failed to readlink " << entry.blk_device; + block_device = entry.blk_device; + } + if (block_device == resolved_block_device) { + return &entry; + } + } + LERROR << "Didn't find entry that was used to mount /data"; + return nullptr; +} + std::set GetBootDevices() { // First check the kernel commandline, then try the device tree otherwise std::string dt_file_name = get_android_dt_dir() + "/boot_devices"; diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index c6a16e375..80deaef65 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -102,6 +102,7 @@ bool SkipMountingPartitions(Fstab* fstab); FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path); // The Fstab can contain multiple entries for the same mount point with different configurations. std::vector GetEntriesForMountPoint(Fstab* fstab, const std::string& path); +FstabEntry* GetMountedEntryForUserdata(Fstab* fstab); // This method builds DSU fstab entries and transfer the fstab. // diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 1cbaf45b9..c5adea6c5 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -969,3 +969,14 @@ TEST(fs_mgr, DefaultFstabContainsUserdata) { ASSERT_NE(nullptr, GetEntryForMountPoint(&fstab, "/data")) << "Default fstab doesn't contain /data entry"; } + +TEST(fs_mgr, UserdataMountedFromDefaultFstab) { + if (getuid() != 0) { + GTEST_SKIP() << "Must be run as root."; + return; + } + Fstab fstab; + ASSERT_TRUE(ReadDefaultFstab(&fstab)) << "Failed to read default fstab"; + ASSERT_NE(nullptr, GetMountedEntryForUserdata(&fstab)) + << "/data wasn't mounted from default fstab"; +}