adb: better error messages on deduplicated filesystems.

If BOARD_EXT4_SHARE_DUP_BLOCKS is true, "adb remount" will error saying
the filesystem is read-only. Instead, it will now list affected
partitions and explain why they can't be remounted.

Bug: 64109868
Test: adb remount with deduplicated system image
Change-Id: Ida737a6be8e9fe9ea26300897d82b1a149e72f6d
This commit is contained in:
David Anderson 2018-04-26 14:32:48 -07:00
parent 53248e47f4
commit a962ec0c73

View file

@ -25,14 +25,18 @@
#include <stdlib.h>
#include <string.h>
#include <sys/mount.h>
#include <sys/vfs.h>
#include <unistd.h>
#include <string>
#include <vector>
#include <android-base/properties.h>
#include <ext4_utils/ext4_utils.h>
#include "adb.h"
#include "adb_io.h"
#include "adb_unique_fd.h"
#include "adb_utils.h"
#include "fs_mgr.h"
@ -82,7 +86,27 @@ bool make_block_device_writable(const std::string& dev) {
return result;
}
static bool remount_partition(int fd, const char* dir) {
static bool fs_has_shared_blocks(const char* dev) {
struct statfs fs;
if (statfs(dev, &fs) == -1 || fs.f_type == EXT4_SUPER_MAGIC) {
return false;
}
unique_fd fd(unix_open(dev, O_RDONLY));
if (fd < 0) {
return false;
}
struct ext4_super_block sb;
if (lseek64(fd, 1024, SEEK_SET) < 0 || unix_read(fd, &sb, sizeof(sb)) < 0) {
return false;
}
struct fs_info info;
if (ext4_parse_sb(&sb, &info) < 0) {
return false;
}
return (info.feat_ro_compat & EXT4_FEATURE_RO_COMPAT_SHARED_BLOCKS) != 0;
}
static bool remount_partition(int fd, const char* dir, std::vector<std::string>& dedup) {
if (!directory_exists(dir)) {
return true;
}
@ -108,6 +132,12 @@ static bool remount_partition(int fd, const char* dir) {
return false;
}
if (mount(dev.c_str(), dir, "none", MS_REMOUNT, nullptr) == -1) {
if (errno == EROFS && fs_has_shared_blocks(dev.c_str())) {
// We return true so remount_service() can detect that the only
// failure was deduplicated filesystems.
dedup.push_back(dev);
return true;
}
WriteFdFmt(fd, "remount of the %s superblock failed: %s\n", dir, strerror(errno));
return false;
}
@ -140,17 +170,29 @@ void remount_service(int fd, void* cookie) {
}
bool success = true;
std::vector<std::string> dedup;
if (android::base::GetBoolProperty("ro.build.system_root_image", false)) {
success &= remount_partition(fd, "/");
success &= remount_partition(fd, "/", dedup);
} else {
success &= remount_partition(fd, "/system");
success &= remount_partition(fd, "/system", dedup);
}
success &= remount_partition(fd, "/odm");
success &= remount_partition(fd, "/oem");
success &= remount_partition(fd, "/product");
success &= remount_partition(fd, "/vendor");
success &= remount_partition(fd, "/odm", dedup);
success &= remount_partition(fd, "/oem", dedup);
success &= remount_partition(fd, "/product", dedup);
success &= remount_partition(fd, "/vendor", dedup);
WriteFdExactly(fd, success ? "remount succeeded\n" : "remount failed\n");
if (!success) {
WriteFdExactly(fd, "remount failed\n");
} else if (dedup.empty()) {
WriteFdExactly(fd, "remount succeeded\n");
} else {
WriteFdExactly(fd,
"The following partitions are deduplicated and could "
"not be remounted:\n");
for (const std::string& name : dedup) {
WriteFdFmt(fd, " %s\n", name.c_str());
}
}
adb_close(fd);
}