Loading fs_mgr/fs_mgr_overlayfs.cpp +277 −25 Original line number Diff line number Diff line Loading @@ -41,14 +41,18 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <ext4_utils/ext4_utils.h> #include <fs_mgr_dm_linear.h> #include <fs_mgr_overlayfs.h> #include <fstab/fstab.h> #include <libdm/dm.h> #include <liblp/builder.h> #include <liblp/liblp.h> #include "fs_mgr_priv.h" using namespace std::literals; using namespace android::dm; using namespace android::fs_mgr; #if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs Loading @@ -74,8 +78,10 @@ bool fs_mgr_overlayfs_teardown(const char*, bool* change) { namespace { // acceptable overlayfs backing storage const auto kOverlayMountPoint = "/cache"s; // list of acceptable overlayfs backing storage const auto kScratchMountPoint = "/mnt/scratch"s; const auto kCacheMountPoint = "/cache"s; const std::vector<const std::string> kOverlayMountPoints = {kScratchMountPoint, kCacheMountPoint}; // Return true if everything is mounted, but before adb is started. Right // after 'trigger load_persist_props_action' is done. Loading Loading @@ -136,15 +142,18 @@ const auto kOverlayTopDir = "/overlay"s; std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) { if (!fs_mgr_is_dir(mount_point)) return ""; auto dir = kOverlayMountPoint + kOverlayTopDir + "/" + android::base::Basename(mount_point) + "/"; const auto base = android::base::Basename(mount_point) + "/"; for (const auto& overlay_mount_point : kOverlayMountPoints) { auto dir = overlay_mount_point + kOverlayTopDir + "/" + base; auto upper = dir + kUpperName; if (!fs_mgr_is_dir(upper)) return ""; if (!fs_mgr_is_dir(upper)) continue; auto work = dir + kWorkName; if (!fs_mgr_is_dir(work)) return ""; if (!fs_mgr_dir_is_writable(work)) return ""; if (!fs_mgr_is_dir(work)) continue; if (!fs_mgr_dir_is_writable(work)) continue; return dir; } return ""; } const auto kLowerdirOption = "lowerdir="s; const auto kUpperdirOption = "upperdir="s; Loading Loading @@ -187,6 +196,14 @@ bool fs_mgr_access(const std::string& path) { return ret; } bool fs_mgr_rw_access(const std::string& path) { if (path.empty()) return false; auto save_errno = errno; auto ret = access(path.c_str(), R_OK | W_OK) == 0; errno = save_errno; return ret; } // return true if system supports overlayfs bool fs_mgr_wants_overlayfs() { // Properties will return empty on init first_stage_mount, so speculative Loading @@ -200,7 +217,7 @@ bool fs_mgr_wants_overlayfs() { return fs_mgr_access("/sys/module/overlay/parameters/override_creds"); } bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) { bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) { std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab); if (!fstab) return false; Loading @@ -209,10 +226,11 @@ bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) { const auto fsrec = &fstab->recs[i]; const auto fs_type = fsrec->fs_type; if (!fs_type) continue; if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue; if (overlay_only && ("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue; auto fsrec_mount_point = fsrec->mount_point; if (!fsrec_mount_point) continue; if (mount_point != fsrec_mount_point) continue; if (!overlay_only) return true; const auto fs_options = fsrec->fs_options; if (!fs_options) continue; const auto options = android::base::Split(fs_options, ","); Loading Loading @@ -373,6 +391,67 @@ bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& m return ret; } uint32_t fs_mgr_overlayfs_slot_number() { return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); } std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { return "/dev/block/by-name/" + fs_mgr_get_super_partition_name(slot_number); } bool fs_mgr_overlayfs_has_logical(const fstab* fstab) { if (!fstab) return false; for (auto i = 0; i < fstab->num_entries; i++) { const auto fsrec = &fstab->recs[i]; if (fs_mgr_is_logical(fsrec)) return true; } return false; } // reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise std::string scratch_device_cache; bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) { // umount and delete kScratchMountPoint storage if we have logical partitions if (overlay != kScratchMountPoint) return true; scratch_device_cache.erase(); auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); if (!fs_mgr_rw_access(super_device)) return true; auto save_errno = errno; if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) { // Lazy umount will allow us to move on and possibly later // establish a new fresh mount without requiring a reboot should // the developer wish to restart. Old references should melt // away or have no data. Main goal is to shut the door on the // current overrides with an expectation of a subsequent reboot, // thus any errors here are ignored. umount2(kScratchMountPoint.c_str(), MNT_DETACH); } auto builder = MetadataBuilder::New(super_device, slot_number); if (!builder) { errno = save_errno; return true; } const auto partition_name = android::base::Basename(kScratchMountPoint); if (builder->FindPartition(partition_name) == nullptr) { errno = save_errno; return true; } builder->RemovePartition(partition_name); auto metadata = builder->Export(); if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { if (change) *change = true; if (!DestroyLogicalPartition(partition_name, 0s)) return false; } else { PERROR << "delete partition " << overlay; return false; } errno = save_errno; return true; } bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point, bool* change) { const auto top = overlay + kOverlayTopDir; Loading Loading @@ -406,13 +485,16 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string save_errno = errno; if (!rmdir(top.c_str())) { if (change) *change = true; cleanup_all = true; } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) { ret = false; PERROR << "rmdir " << top; } else { errno = save_errno; cleanup_all = true; } } if (cleanup_all) ret &= fs_mgr_overlayfs_teardown_scratch(overlay, change); return ret; } Loading Loading @@ -504,6 +586,138 @@ std::vector<std::string> fs_mgr_candidate_list(const fstab* fstab, return mounts; } // Mount kScratchMountPoint bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type) { if (setfscreatecon(kOverlayfsFileContext)) { PERROR << "setfscreatecon " << kOverlayfsFileContext; } if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) { PERROR << "create " << kScratchMountPoint; } std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> local_fstab( static_cast<fstab*>(calloc(1, sizeof(fstab))), fs_mgr_free_fstab); auto fsrec = static_cast<fstab_rec*>(calloc(1, sizeof(fstab_rec))); local_fstab->num_entries = 1; local_fstab->recs = fsrec; fsrec->blk_device = strdup(device_path.c_str()); fsrec->mount_point = strdup(kScratchMountPoint.c_str()); fsrec->fs_type = strdup(mnt_type.c_str()); fsrec->flags = MS_RELATIME; fsrec->fs_options = strdup(""); auto mounted = fs_mgr_do_mount_one(fsrec) == 0; auto save_errno = errno; setfscreatecon(nullptr); if (!mounted) rmdir(kScratchMountPoint.c_str()); errno = save_errno; return mounted; } const std::string kMkF2fs("/system/bin/make_f2fs"); const std::string kMkExt4("/system/bin/mke2fs"); std::string fs_mgr_overlayfs_scratch_mount_type() { if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs"; if (!access(kMkExt4.c_str(), X_OK)) return "ext4"; return "auto"; } std::string fs_mgr_overlayfs_scratch_device() { if (!scratch_device_cache.empty()) return scratch_device_cache; auto& dm = DeviceMapper::Instance(); const auto partition_name = android::base::Basename(kScratchMountPoint); std::string path; if (!dm.GetDmDevicePathByName(partition_name, &path)) return ""; return scratch_device_cache = path; } // Create and mount kScratchMountPoint storage if we have logical partitions bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; auto mnt_type = fs_mgr_overlayfs_scratch_mount_type(); auto scratch_device = fs_mgr_overlayfs_scratch_device(); auto partition_exists = fs_mgr_rw_access(scratch_device); if (!partition_exists) { auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); if (!fs_mgr_rw_access(super_device)) return false; if (!fs_mgr_overlayfs_has_logical(fstab)) return false; auto builder = MetadataBuilder::New(super_device, slot_number); if (!builder) { PERROR << "open " << super_device << " metadata"; return false; } const auto partition_name = android::base::Basename(kScratchMountPoint); partition_exists = builder->FindPartition(partition_name) != nullptr; if (!partition_exists) { auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE); if (!partition) { PERROR << "create " << partition_name; return false; } auto partition_size = builder->AllocatableSpace() - builder->UsedSpace(); // 512MB or half the remaining available space, whichever is greater. partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2); if (!builder->ResizePartition(partition, partition_size)) { PERROR << "resize " << partition_name; return false; } auto metadata = builder->Export(); if (!metadata) { LERROR << "generate new metadata " << partition_name; return false; } if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { LERROR << "update " << partition_name; return false; } if (change) *change = true; } if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s, &scratch_device)) return false; } if (partition_exists) { if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) { if (change) *change = true; return true; } // partition existed, but was not initialized; errno = 0; } auto ret = system((mnt_type == "f2fs") ? ((kMkF2fs + " -d1 " + scratch_device).c_str()) : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M "s + kScratchMountPoint + " -O has_journal " + scratch_device) .c_str())); if (ret) { LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " error=" << ret; return false; } if (change) *change = true; return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type); } bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device) { if (scratch_device.empty()) return false; if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return false; if (fs_mgr_rw_access(scratch_device)) return true; auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); if (!fs_mgr_rw_access(super_device)) return false; auto builder = MetadataBuilder::New(super_device, slot_number); if (!builder) return false; return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr; } } // namespace bool fs_mgr_overlayfs_mount_all(const fstab* fstab) { Loading @@ -513,14 +727,37 @@ bool fs_mgr_overlayfs_mount_all(const fstab* fstab) { if (!fstab) return ret; auto scratch_can_be_mounted = true; for (const auto& mount_point : fs_mgr_candidate_list(fstab)) { if (fs_mgr_overlayfs_already_mounted(mount_point)) continue; if (scratch_can_be_mounted) { scratch_can_be_mounted = false; auto scratch_device = fs_mgr_overlayfs_scratch_device(); if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) && fs_mgr_wait_for_file(scratch_device, 10s) && fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type()) && !fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) { umount2(kScratchMountPoint.c_str(), MNT_DETACH); rmdir(kScratchMountPoint.c_str()); } } if (fs_mgr_overlayfs_mount(mount_point)) ret = true; } return ret; } std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) { std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab) { if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) { return {}; } for (const auto& mount_point : fs_mgr_candidate_list(fstab)) { if (fs_mgr_overlayfs_already_mounted(mount_point)) continue; auto device = fs_mgr_overlayfs_scratch_device(); if (!fs_mgr_overlayfs_scratch_can_be_mounted(device)) break; return {device}; } return {}; } Loading @@ -529,10 +766,6 @@ std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) { bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) { if (change) *change = false; auto ret = false; if (backing && (kOverlayMountPoint != backing)) { errno = EINVAL; return ret; } if (!fs_mgr_wants_overlayfs()) return ret; if (!fs_mgr_boot_completed()) { errno = EBUSY; Loading @@ -542,16 +775,32 @@ bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(), fs_mgr_free_fstab); if (fstab && !fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret; if (!fstab) return ret; auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(fstab.get(), mount_point)); if (fstab && mounts.empty()) return ret; if (mounts.empty()) return ret; std::string dir; for (const auto& overlay_mount_point : kOverlayMountPoints) { if (backing && backing[0] && (overlay_mount_point != backing)) continue; if (overlay_mount_point == kScratchMountPoint) { if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) || !fs_mgr_overlayfs_has_logical(fstab.get())) { continue; } if (!fs_mgr_overlayfs_setup_scratch(fstab.get(), change)) continue; } else { if (!fs_mgr_get_entry_for_mount_point(fstab.get(), overlay_mount_point)) continue; } dir = overlay_mount_point; break; } if (dir.empty()) { errno = ESRCH; return ret; } std::string overlay; ret |= fs_mgr_overlayfs_setup_dir(kOverlayMountPoint, &overlay, change); if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) { ret = true; } ret |= fs_mgr_overlayfs_setup_dir(dir, &overlay, change); for (const auto& fsrec_mount_point : mounts) { ret |= fs_mgr_overlayfs_setup_one(overlay, fsrec_mount_point, change); } Loading @@ -566,7 +815,10 @@ bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) { fs_mgr_read_fstab_default(), fs_mgr_free_fstab) .get(), mount_point); auto ret = fs_mgr_overlayfs_teardown_one(kOverlayMountPoint, mount_point ?: "", change); auto ret = true; for (const auto& overlay_mount_point : kOverlayMountPoints) { ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change); } if (!fs_mgr_wants_overlayfs()) { // After obligatory teardown to make sure everything is clean, but if // we didn't want overlayfs in the the first place, we do not want to Loading fs_mgr/fs_mgr_priv.h +2 −2 Original line number Diff line number Diff line Loading @@ -128,10 +128,10 @@ bool fs_mgr_wait_for_file(const std::string& filename, FileWaitMode wait_mode = FileWaitMode::Exists); int fs_mgr_set_blk_ro(const char* blockdev); bool fs_mgr_update_for_slotselect(struct fstab *fstab); bool fs_mgr_update_for_slotselect(fstab* fstab); bool fs_mgr_is_device_unlocked(); const std::string& get_android_dt_dir(); bool is_dt_compatible(); int load_verity_state(struct fstab_rec* fstab, int* mode); int load_verity_state(fstab_rec* fstab, int* mode); #endif /* __CORE_FS_MGR_PRIV_H */ fs_mgr/include/fs_mgr.h +11 −12 Original line number Diff line number Diff line Loading @@ -51,8 +51,8 @@ enum mount_mode { }; // Callback function for verity status typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* mount_point, int mode, int status); typedef void fs_mgr_verity_state_callback(fstab_rec* fstab, const char* mount_point, int mode, int status); #define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7 #define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6 Loading @@ -63,32 +63,31 @@ typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* m #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0 #define FS_MGR_MNTALL_FAIL (-1) int fs_mgr_mount_all(struct fstab *fstab, int mount_mode); int fs_mgr_mount_all(fstab* fstab, int mount_mode); #define FS_MGR_DOMNT_FAILED (-1) #define FS_MGR_DOMNT_BUSY (-2) #define FS_MGR_DOMNT_SUCCESS 0 int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, char *tmp_mount_point); int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point, bool need_cp); int fs_mgr_do_mount_one(struct fstab_rec *rec); int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point); int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point, bool need_cp); int fs_mgr_do_mount_one(fstab_rec* rec); int fs_mgr_do_tmpfs_mount(const char *n_name); struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab); void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size); fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab); void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size); bool fs_mgr_load_verity_state(int* mode); bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback); int fs_mgr_swapon_all(struct fstab *fstab); bool fs_mgr_update_logical_partition(struct fstab_rec* rec); int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer); int fs_mgr_do_format(fstab_rec* fstab, bool reserve_footer); #define FS_MGR_SETUP_VERITY_SKIPPED (-3) #define FS_MGR_SETUP_VERITY_DISABLED (-2) #define FS_MGR_SETUP_VERITY_FAIL (-1) #define FS_MGR_SETUP_VERITY_SUCCESS 0 int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev); int fs_mgr_setup_verity(fstab_rec* fstab, bool wait_for_verity_dev); // Return the name of the super partition if it exists. If a slot number is // specified, the super partition for the corresponding metadata slot will be Loading Loading
fs_mgr/fs_mgr_overlayfs.cpp +277 −25 Original line number Diff line number Diff line Loading @@ -41,14 +41,18 @@ #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <ext4_utils/ext4_utils.h> #include <fs_mgr_dm_linear.h> #include <fs_mgr_overlayfs.h> #include <fstab/fstab.h> #include <libdm/dm.h> #include <liblp/builder.h> #include <liblp/liblp.h> #include "fs_mgr_priv.h" using namespace std::literals; using namespace android::dm; using namespace android::fs_mgr; #if ALLOW_ADBD_DISABLE_VERITY == 0 // If we are a user build, provide stubs Loading @@ -74,8 +78,10 @@ bool fs_mgr_overlayfs_teardown(const char*, bool* change) { namespace { // acceptable overlayfs backing storage const auto kOverlayMountPoint = "/cache"s; // list of acceptable overlayfs backing storage const auto kScratchMountPoint = "/mnt/scratch"s; const auto kCacheMountPoint = "/cache"s; const std::vector<const std::string> kOverlayMountPoints = {kScratchMountPoint, kCacheMountPoint}; // Return true if everything is mounted, but before adb is started. Right // after 'trigger load_persist_props_action' is done. Loading Loading @@ -136,15 +142,18 @@ const auto kOverlayTopDir = "/overlay"s; std::string fs_mgr_get_overlayfs_candidate(const std::string& mount_point) { if (!fs_mgr_is_dir(mount_point)) return ""; auto dir = kOverlayMountPoint + kOverlayTopDir + "/" + android::base::Basename(mount_point) + "/"; const auto base = android::base::Basename(mount_point) + "/"; for (const auto& overlay_mount_point : kOverlayMountPoints) { auto dir = overlay_mount_point + kOverlayTopDir + "/" + base; auto upper = dir + kUpperName; if (!fs_mgr_is_dir(upper)) return ""; if (!fs_mgr_is_dir(upper)) continue; auto work = dir + kWorkName; if (!fs_mgr_is_dir(work)) return ""; if (!fs_mgr_dir_is_writable(work)) return ""; if (!fs_mgr_is_dir(work)) continue; if (!fs_mgr_dir_is_writable(work)) continue; return dir; } return ""; } const auto kLowerdirOption = "lowerdir="s; const auto kUpperdirOption = "upperdir="s; Loading Loading @@ -187,6 +196,14 @@ bool fs_mgr_access(const std::string& path) { return ret; } bool fs_mgr_rw_access(const std::string& path) { if (path.empty()) return false; auto save_errno = errno; auto ret = access(path.c_str(), R_OK | W_OK) == 0; errno = save_errno; return ret; } // return true if system supports overlayfs bool fs_mgr_wants_overlayfs() { // Properties will return empty on init first_stage_mount, so speculative Loading @@ -200,7 +217,7 @@ bool fs_mgr_wants_overlayfs() { return fs_mgr_access("/sys/module/overlay/parameters/override_creds"); } bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) { bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) { std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab("/proc/mounts"), fs_mgr_free_fstab); if (!fstab) return false; Loading @@ -209,10 +226,11 @@ bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point) { const auto fsrec = &fstab->recs[i]; const auto fs_type = fsrec->fs_type; if (!fs_type) continue; if (("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue; if (overlay_only && ("overlay"s != fs_type) && ("overlayfs"s != fs_type)) continue; auto fsrec_mount_point = fsrec->mount_point; if (!fsrec_mount_point) continue; if (mount_point != fsrec_mount_point) continue; if (!overlay_only) return true; const auto fs_options = fsrec->fs_options; if (!fs_options) continue; const auto options = android::base::Split(fs_options, ","); Loading Loading @@ -373,6 +391,67 @@ bool fs_mgr_overlayfs_setup_one(const std::string& overlay, const std::string& m return ret; } uint32_t fs_mgr_overlayfs_slot_number() { return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); } std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { return "/dev/block/by-name/" + fs_mgr_get_super_partition_name(slot_number); } bool fs_mgr_overlayfs_has_logical(const fstab* fstab) { if (!fstab) return false; for (auto i = 0; i < fstab->num_entries; i++) { const auto fsrec = &fstab->recs[i]; if (fs_mgr_is_logical(fsrec)) return true; } return false; } // reduce 'DM_DEV_STATUS failed for scratch: No such device or address' noise std::string scratch_device_cache; bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) { // umount and delete kScratchMountPoint storage if we have logical partitions if (overlay != kScratchMountPoint) return true; scratch_device_cache.erase(); auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); if (!fs_mgr_rw_access(super_device)) return true; auto save_errno = errno; if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) { // Lazy umount will allow us to move on and possibly later // establish a new fresh mount without requiring a reboot should // the developer wish to restart. Old references should melt // away or have no data. Main goal is to shut the door on the // current overrides with an expectation of a subsequent reboot, // thus any errors here are ignored. umount2(kScratchMountPoint.c_str(), MNT_DETACH); } auto builder = MetadataBuilder::New(super_device, slot_number); if (!builder) { errno = save_errno; return true; } const auto partition_name = android::base::Basename(kScratchMountPoint); if (builder->FindPartition(partition_name) == nullptr) { errno = save_errno; return true; } builder->RemovePartition(partition_name); auto metadata = builder->Export(); if (metadata && UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { if (change) *change = true; if (!DestroyLogicalPartition(partition_name, 0s)) return false; } else { PERROR << "delete partition " << overlay; return false; } errno = save_errno; return true; } bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string& mount_point, bool* change) { const auto top = overlay + kOverlayTopDir; Loading Loading @@ -406,13 +485,16 @@ bool fs_mgr_overlayfs_teardown_one(const std::string& overlay, const std::string save_errno = errno; if (!rmdir(top.c_str())) { if (change) *change = true; cleanup_all = true; } else if ((errno != ENOENT) && (errno != ENOTEMPTY)) { ret = false; PERROR << "rmdir " << top; } else { errno = save_errno; cleanup_all = true; } } if (cleanup_all) ret &= fs_mgr_overlayfs_teardown_scratch(overlay, change); return ret; } Loading Loading @@ -504,6 +586,138 @@ std::vector<std::string> fs_mgr_candidate_list(const fstab* fstab, return mounts; } // Mount kScratchMountPoint bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::string mnt_type) { if (setfscreatecon(kOverlayfsFileContext)) { PERROR << "setfscreatecon " << kOverlayfsFileContext; } if (mkdir(kScratchMountPoint.c_str(), 0755) && (errno != EEXIST)) { PERROR << "create " << kScratchMountPoint; } std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> local_fstab( static_cast<fstab*>(calloc(1, sizeof(fstab))), fs_mgr_free_fstab); auto fsrec = static_cast<fstab_rec*>(calloc(1, sizeof(fstab_rec))); local_fstab->num_entries = 1; local_fstab->recs = fsrec; fsrec->blk_device = strdup(device_path.c_str()); fsrec->mount_point = strdup(kScratchMountPoint.c_str()); fsrec->fs_type = strdup(mnt_type.c_str()); fsrec->flags = MS_RELATIME; fsrec->fs_options = strdup(""); auto mounted = fs_mgr_do_mount_one(fsrec) == 0; auto save_errno = errno; setfscreatecon(nullptr); if (!mounted) rmdir(kScratchMountPoint.c_str()); errno = save_errno; return mounted; } const std::string kMkF2fs("/system/bin/make_f2fs"); const std::string kMkExt4("/system/bin/mke2fs"); std::string fs_mgr_overlayfs_scratch_mount_type() { if (!access(kMkF2fs.c_str(), X_OK)) return "f2fs"; if (!access(kMkExt4.c_str(), X_OK)) return "ext4"; return "auto"; } std::string fs_mgr_overlayfs_scratch_device() { if (!scratch_device_cache.empty()) return scratch_device_cache; auto& dm = DeviceMapper::Instance(); const auto partition_name = android::base::Basename(kScratchMountPoint); std::string path; if (!dm.GetDmDevicePathByName(partition_name, &path)) return ""; return scratch_device_cache = path; } // Create and mount kScratchMountPoint storage if we have logical partitions bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; auto mnt_type = fs_mgr_overlayfs_scratch_mount_type(); auto scratch_device = fs_mgr_overlayfs_scratch_device(); auto partition_exists = fs_mgr_rw_access(scratch_device); if (!partition_exists) { auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); if (!fs_mgr_rw_access(super_device)) return false; if (!fs_mgr_overlayfs_has_logical(fstab)) return false; auto builder = MetadataBuilder::New(super_device, slot_number); if (!builder) { PERROR << "open " << super_device << " metadata"; return false; } const auto partition_name = android::base::Basename(kScratchMountPoint); partition_exists = builder->FindPartition(partition_name) != nullptr; if (!partition_exists) { auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE); if (!partition) { PERROR << "create " << partition_name; return false; } auto partition_size = builder->AllocatableSpace() - builder->UsedSpace(); // 512MB or half the remaining available space, whichever is greater. partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2); if (!builder->ResizePartition(partition, partition_size)) { PERROR << "resize " << partition_name; return false; } auto metadata = builder->Export(); if (!metadata) { LERROR << "generate new metadata " << partition_name; return false; } if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { LERROR << "update " << partition_name; return false; } if (change) *change = true; } if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s, &scratch_device)) return false; } if (partition_exists) { if (fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type)) { if (change) *change = true; return true; } // partition existed, but was not initialized; errno = 0; } auto ret = system((mnt_type == "f2fs") ? ((kMkF2fs + " -d1 " + scratch_device).c_str()) : ((kMkExt4 + " -b 4096 -t ext4 -m 0 -M "s + kScratchMountPoint + " -O has_journal " + scratch_device) .c_str())); if (ret) { LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " error=" << ret; return false; } if (change) *change = true; return fs_mgr_overlayfs_mount_scratch(scratch_device, mnt_type); } bool fs_mgr_overlayfs_scratch_can_be_mounted(const std::string& scratch_device) { if (scratch_device.empty()) return false; if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return false; if (fs_mgr_rw_access(scratch_device)) return true; auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); if (!fs_mgr_rw_access(super_device)) return false; auto builder = MetadataBuilder::New(super_device, slot_number); if (!builder) return false; return builder->FindPartition(android::base::Basename(kScratchMountPoint)) != nullptr; } } // namespace bool fs_mgr_overlayfs_mount_all(const fstab* fstab) { Loading @@ -513,14 +727,37 @@ bool fs_mgr_overlayfs_mount_all(const fstab* fstab) { if (!fstab) return ret; auto scratch_can_be_mounted = true; for (const auto& mount_point : fs_mgr_candidate_list(fstab)) { if (fs_mgr_overlayfs_already_mounted(mount_point)) continue; if (scratch_can_be_mounted) { scratch_can_be_mounted = false; auto scratch_device = fs_mgr_overlayfs_scratch_device(); if (fs_mgr_overlayfs_scratch_can_be_mounted(scratch_device) && fs_mgr_wait_for_file(scratch_device, 10s) && fs_mgr_overlayfs_mount_scratch(scratch_device, fs_mgr_overlayfs_scratch_mount_type()) && !fs_mgr_access(kScratchMountPoint + kOverlayTopDir)) { umount2(kScratchMountPoint.c_str(), MNT_DETACH); rmdir(kScratchMountPoint.c_str()); } } if (fs_mgr_overlayfs_mount(mount_point)) ret = true; } return ret; } std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) { std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab* fstab) { if (fs_mgr_get_entry_for_mount_point(const_cast<struct fstab*>(fstab), kScratchMountPoint)) { return {}; } for (const auto& mount_point : fs_mgr_candidate_list(fstab)) { if (fs_mgr_overlayfs_already_mounted(mount_point)) continue; auto device = fs_mgr_overlayfs_scratch_device(); if (!fs_mgr_overlayfs_scratch_can_be_mounted(device)) break; return {device}; } return {}; } Loading @@ -529,10 +766,6 @@ std::vector<std::string> fs_mgr_overlayfs_required_devices(const fstab*) { bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) { if (change) *change = false; auto ret = false; if (backing && (kOverlayMountPoint != backing)) { errno = EINVAL; return ret; } if (!fs_mgr_wants_overlayfs()) return ret; if (!fs_mgr_boot_completed()) { errno = EBUSY; Loading @@ -542,16 +775,32 @@ bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* std::unique_ptr<fstab, decltype(&fs_mgr_free_fstab)> fstab(fs_mgr_read_fstab_default(), fs_mgr_free_fstab); if (fstab && !fs_mgr_get_entry_for_mount_point(fstab.get(), kOverlayMountPoint)) return ret; if (!fstab) return ret; auto mounts = fs_mgr_candidate_list(fstab.get(), fs_mgr_mount_point(fstab.get(), mount_point)); if (fstab && mounts.empty()) return ret; if (mounts.empty()) return ret; std::string dir; for (const auto& overlay_mount_point : kOverlayMountPoints) { if (backing && backing[0] && (overlay_mount_point != backing)) continue; if (overlay_mount_point == kScratchMountPoint) { if (!fs_mgr_rw_access(fs_mgr_overlayfs_super_device(fs_mgr_overlayfs_slot_number())) || !fs_mgr_overlayfs_has_logical(fstab.get())) { continue; } if (!fs_mgr_overlayfs_setup_scratch(fstab.get(), change)) continue; } else { if (!fs_mgr_get_entry_for_mount_point(fstab.get(), overlay_mount_point)) continue; } dir = overlay_mount_point; break; } if (dir.empty()) { errno = ESRCH; return ret; } std::string overlay; ret |= fs_mgr_overlayfs_setup_dir(kOverlayMountPoint, &overlay, change); if (!fstab && mount_point && fs_mgr_overlayfs_setup_one(overlay, mount_point, change)) { ret = true; } ret |= fs_mgr_overlayfs_setup_dir(dir, &overlay, change); for (const auto& fsrec_mount_point : mounts) { ret |= fs_mgr_overlayfs_setup_one(overlay, fsrec_mount_point, change); } Loading @@ -566,7 +815,10 @@ bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) { fs_mgr_read_fstab_default(), fs_mgr_free_fstab) .get(), mount_point); auto ret = fs_mgr_overlayfs_teardown_one(kOverlayMountPoint, mount_point ?: "", change); auto ret = true; for (const auto& overlay_mount_point : kOverlayMountPoints) { ret &= fs_mgr_overlayfs_teardown_one(overlay_mount_point, mount_point ?: "", change); } if (!fs_mgr_wants_overlayfs()) { // After obligatory teardown to make sure everything is clean, but if // we didn't want overlayfs in the the first place, we do not want to Loading
fs_mgr/fs_mgr_priv.h +2 −2 Original line number Diff line number Diff line Loading @@ -128,10 +128,10 @@ bool fs_mgr_wait_for_file(const std::string& filename, FileWaitMode wait_mode = FileWaitMode::Exists); int fs_mgr_set_blk_ro(const char* blockdev); bool fs_mgr_update_for_slotselect(struct fstab *fstab); bool fs_mgr_update_for_slotselect(fstab* fstab); bool fs_mgr_is_device_unlocked(); const std::string& get_android_dt_dir(); bool is_dt_compatible(); int load_verity_state(struct fstab_rec* fstab, int* mode); int load_verity_state(fstab_rec* fstab, int* mode); #endif /* __CORE_FS_MGR_PRIV_H */
fs_mgr/include/fs_mgr.h +11 −12 Original line number Diff line number Diff line Loading @@ -51,8 +51,8 @@ enum mount_mode { }; // Callback function for verity status typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* mount_point, int mode, int status); typedef void fs_mgr_verity_state_callback(fstab_rec* fstab, const char* mount_point, int mode, int status); #define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7 #define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6 Loading @@ -63,32 +63,31 @@ typedef void fs_mgr_verity_state_callback(struct fstab_rec* fstab, const char* m #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTED 1 #define FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE 0 #define FS_MGR_MNTALL_FAIL (-1) int fs_mgr_mount_all(struct fstab *fstab, int mount_mode); int fs_mgr_mount_all(fstab* fstab, int mount_mode); #define FS_MGR_DOMNT_FAILED (-1) #define FS_MGR_DOMNT_BUSY (-2) #define FS_MGR_DOMNT_SUCCESS 0 int fs_mgr_do_mount(struct fstab *fstab, const char *n_name, char *n_blk_device, char *tmp_mount_point); int fs_mgr_do_mount(struct fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point, bool need_cp); int fs_mgr_do_mount_one(struct fstab_rec *rec); int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point); int fs_mgr_do_mount(fstab* fstab, const char* n_name, char* n_blk_device, char* tmp_mount_point, bool need_cp); int fs_mgr_do_mount_one(fstab_rec* rec); int fs_mgr_do_tmpfs_mount(const char *n_name); struct fstab_rec const* fs_mgr_get_crypt_entry(struct fstab const* fstab); void fs_mgr_get_crypt_info(struct fstab* fstab, char* key_loc, char* real_blk_device, size_t size); fstab_rec const* fs_mgr_get_crypt_entry(fstab const* fstab); void fs_mgr_get_crypt_info(fstab* fstab, char* key_loc, char* real_blk_device, size_t size); bool fs_mgr_load_verity_state(int* mode); bool fs_mgr_update_verity_state(std::function<fs_mgr_verity_state_callback> callback); int fs_mgr_swapon_all(struct fstab *fstab); bool fs_mgr_update_logical_partition(struct fstab_rec* rec); int fs_mgr_do_format(struct fstab_rec *fstab, bool reserve_footer); int fs_mgr_do_format(fstab_rec* fstab, bool reserve_footer); #define FS_MGR_SETUP_VERITY_SKIPPED (-3) #define FS_MGR_SETUP_VERITY_DISABLED (-2) #define FS_MGR_SETUP_VERITY_FAIL (-1) #define FS_MGR_SETUP_VERITY_SUCCESS 0 int fs_mgr_setup_verity(struct fstab_rec *fstab, bool wait_for_verity_dev); int fs_mgr_setup_verity(fstab_rec* fstab, bool wait_for_verity_dev); // Return the name of the super partition if it exists. If a slot number is // specified, the super partition for the corresponding metadata slot will be Loading