Loading fs_mgr/README.overlayfs.md +6 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,12 @@ Caveats multiple reasons. NB: This is not a problem for fastbootd or recovery as overrides are disabled for those special boot scenarios. - For implementation simplicity on retrofit dynamic partition devices, take the whole alternate super (eg: if "*a*" slot, then the whole of "*system_b*"). Since landing a filesystem on the alternate super physical device without differentiating if it is setup to support logical or physical, the alternate slot metadata and previous content will be lost. - If dynamic partitions runs out of space, resizing a logical partition larger may fail because of the scratch partition. If this happens, either fastboot flashall or adb enable-verity can Loading fs_mgr/fs_mgr_overlayfs.cpp +65 −34 Original line number Diff line number Diff line Loading @@ -386,8 +386,10 @@ uint32_t fs_mgr_overlayfs_slot_number() { return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); } const auto kPhysicalDevice = "/dev/block/by-name/"s; std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { return "/dev/block/by-name/" + fs_mgr_get_super_partition_name(slot_number); return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number); } bool fs_mgr_overlayfs_has_logical(const fstab* fstab) { Loading Loading @@ -645,19 +647,50 @@ std::string fs_mgr_overlayfs_scratch_mount_type() { std::string fs_mgr_overlayfs_scratch_device() { if (!scratch_device_cache.empty()) return scratch_device_cache; // Is this a multiple super device (retrofit)? auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); auto path = fs_mgr_overlayfs_super_device(slot_number == 0); if (super_device == path) { // Create from within single super device; 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_create = !fs_mgr_rw_access(scratch_device); bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) { // Force mkfs by design for overlay support of adb remount, simplify and // thus do not rely on fsck to correct problems that could creep in. auto command = ""s; if (mnt_type == "f2fs") { command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint); } else if (mnt_type == "ext4") { command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; } else { errno = ESRCH; LERROR << mnt_type << " has no mkfs cookbook"; return false; } command += " " + scratch_device; auto ret = system(command.c_str()); if (ret) { LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " return=" << ret; return false; } return true; } bool fs_mgr_overlayfs_create_scratch(const fstab* fstab, std::string* scratch_device, bool* partition_exists, bool* change) { *scratch_device = fs_mgr_overlayfs_scratch_device(); *partition_exists = fs_mgr_rw_access(*scratch_device); auto partition_create = !*partition_exists; // Do we need to create a logical "scratch" partition? if (!partition_create && android::base::StartsWith(*scratch_device, kPhysicalDevice)) { 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; Loading @@ -669,9 +702,9 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { } const auto partition_name = android::base::Basename(kScratchMountPoint); auto partition = builder->FindPartition(partition_name); auto partition_exists = partition != nullptr; *partition_exists = partition != nullptr; auto changed = false; if (!partition_exists) { if (!*partition_exists) { partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE); if (!partition) { LERROR << "create " << partition_name; Loading Loading @@ -707,7 +740,7 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { } if (!partition_create) DestroyLogicalPartition(partition_name, 10s); changed = true; partition_exists = false; *partition_exists = false; } } } Loading @@ -724,39 +757,36 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { if (changed || partition_create) { if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s, &scratch_device)) scratch_device)) return false; if (change) *change = true; } return true; } // 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; std::string scratch_device; bool partition_exists; if (!fs_mgr_overlayfs_create_scratch(fstab, &scratch_device, &partition_exists, change)) { return false; } // If the partition exists, assume first that it can be mounted. auto mnt_type = fs_mgr_overlayfs_scratch_mount_type(); 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; // partition existed, but was not initialized; fall through to make it. errno = 0; } // Force mkfs by design for overlay support of adb remount, simplify and // thus do not rely on fsck to correct problems that could creep in. auto command = ""s; if (mnt_type == "f2fs") { command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint); } else if (mnt_type == "ext4") { command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; } else { errno = ESRCH; LERROR << mnt_type << " has no mkfs cookbook"; return false; } command += " " + scratch_device; auto ret = system(command.c_str()); if (ret) { LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " return=" << ret; return false; } if (!fs_mgr_overlayfs_make_scratch(scratch_device, mnt_type)) return false; if (change) *change = true; Loading @@ -766,6 +796,7 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { 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 (android::base::StartsWith(scratch_device, kPhysicalDevice)) return true; 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); Loading fs_mgr/tests/adb-remount-test.sh +31 −11 Original line number Diff line number Diff line Loading @@ -378,6 +378,11 @@ fi M=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'` [ -n "${M}" ] && echo "${BLUE}[ INFO ]${NORMAL} scratch filesystem ${M}" uses_dynamic_scratch=true if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then uses_dynamic_scratch=false scratch_partition="${M##*/dev/block/by-name/}" fi scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null | while read device kblocks used available use mounted on; do if [ "/mnt/scratch" = "\${mounted}" ]; then Loading Loading @@ -453,16 +458,30 @@ echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears fastboot flash vendor || ( fastboot reboot && false) || die "fastboot flash vendor" fastboot_getvar partition-type:${scratch_partition} raw || ( fastboot reboot && false) || die "fastboot can not see ${scratch_partition} parameters" if ${uses_dynamic_scratch}; then # check ${scratch_partition} via fastboot fastboot_getvar partition-type:${scratch_partition} raw && fastboot_getvar has-slot:${scratch_partition} no && fastboot_getvar is-logical:${scratch_partition} yes || ( fastboot reboot && false) || die "fastboot can not see ${scratch_partition} parameters" else fastboot_getvar is-logical:${scratch_partition} no || ( fastboot reboot && false) || die "fastboot can not see ${scratch_partition} parameters" fi if ! ${uses_dynamic_scratch}; then fastboot reboot-bootloader || die "Reboot into fastboot" fi if ${uses_dynamic_scratch}; then echo "${BLUE}[ INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2 fastboot erase ${scratch_partition} && ( fastboot reboot || true) && die "fastboot can erase ${scratch_partition}" fi echo "${BLUE}[ INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2 fastboot format ${scratch_partition} && ( fastboot reboot || true) && Loading Loading @@ -507,12 +526,13 @@ check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2 adb reboot-fastboot && adb reboot-fastboot || die "Reboot into fastbootd" dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null && fastboot_wait 2m || ( rm /tmp/adb-remount-test.img && false) || die "reboot into fastboot" fastboot flash ${scratch_partition} /tmp/adb-remount-test.img fastboot flash --force ${scratch_partition} /tmp/adb-remount-test.img err=${?} rm /tmp/adb-remount-test.img fastboot reboot || Loading Loading
fs_mgr/README.overlayfs.md +6 −0 Original line number Diff line number Diff line Loading @@ -95,6 +95,12 @@ Caveats multiple reasons. NB: This is not a problem for fastbootd or recovery as overrides are disabled for those special boot scenarios. - For implementation simplicity on retrofit dynamic partition devices, take the whole alternate super (eg: if "*a*" slot, then the whole of "*system_b*"). Since landing a filesystem on the alternate super physical device without differentiating if it is setup to support logical or physical, the alternate slot metadata and previous content will be lost. - If dynamic partitions runs out of space, resizing a logical partition larger may fail because of the scratch partition. If this happens, either fastboot flashall or adb enable-verity can Loading
fs_mgr/fs_mgr_overlayfs.cpp +65 −34 Original line number Diff line number Diff line Loading @@ -386,8 +386,10 @@ uint32_t fs_mgr_overlayfs_slot_number() { return SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix()); } const auto kPhysicalDevice = "/dev/block/by-name/"s; std::string fs_mgr_overlayfs_super_device(uint32_t slot_number) { return "/dev/block/by-name/" + fs_mgr_get_super_partition_name(slot_number); return kPhysicalDevice + fs_mgr_get_super_partition_name(slot_number); } bool fs_mgr_overlayfs_has_logical(const fstab* fstab) { Loading Loading @@ -645,19 +647,50 @@ std::string fs_mgr_overlayfs_scratch_mount_type() { std::string fs_mgr_overlayfs_scratch_device() { if (!scratch_device_cache.empty()) return scratch_device_cache; // Is this a multiple super device (retrofit)? auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); auto path = fs_mgr_overlayfs_super_device(slot_number == 0); if (super_device == path) { // Create from within single super device; 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_create = !fs_mgr_rw_access(scratch_device); bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std::string& mnt_type) { // Force mkfs by design for overlay support of adb remount, simplify and // thus do not rely on fsck to correct problems that could creep in. auto command = ""s; if (mnt_type == "f2fs") { command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint); } else if (mnt_type == "ext4") { command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; } else { errno = ESRCH; LERROR << mnt_type << " has no mkfs cookbook"; return false; } command += " " + scratch_device; auto ret = system(command.c_str()); if (ret) { LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " return=" << ret; return false; } return true; } bool fs_mgr_overlayfs_create_scratch(const fstab* fstab, std::string* scratch_device, bool* partition_exists, bool* change) { *scratch_device = fs_mgr_overlayfs_scratch_device(); *partition_exists = fs_mgr_rw_access(*scratch_device); auto partition_create = !*partition_exists; // Do we need to create a logical "scratch" partition? if (!partition_create && android::base::StartsWith(*scratch_device, kPhysicalDevice)) { 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; Loading @@ -669,9 +702,9 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { } const auto partition_name = android::base::Basename(kScratchMountPoint); auto partition = builder->FindPartition(partition_name); auto partition_exists = partition != nullptr; *partition_exists = partition != nullptr; auto changed = false; if (!partition_exists) { if (!*partition_exists) { partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE); if (!partition) { LERROR << "create " << partition_name; Loading Loading @@ -707,7 +740,7 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { } if (!partition_create) DestroyLogicalPartition(partition_name, 10s); changed = true; partition_exists = false; *partition_exists = false; } } } Loading @@ -724,39 +757,36 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { if (changed || partition_create) { if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s, &scratch_device)) scratch_device)) return false; if (change) *change = true; } return true; } // 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; std::string scratch_device; bool partition_exists; if (!fs_mgr_overlayfs_create_scratch(fstab, &scratch_device, &partition_exists, change)) { return false; } // If the partition exists, assume first that it can be mounted. auto mnt_type = fs_mgr_overlayfs_scratch_mount_type(); 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; // partition existed, but was not initialized; fall through to make it. errno = 0; } // Force mkfs by design for overlay support of adb remount, simplify and // thus do not rely on fsck to correct problems that could creep in. auto command = ""s; if (mnt_type == "f2fs") { command = kMkF2fs + " -w 4096 -f -d1 -l" + android::base::Basename(kScratchMountPoint); } else if (mnt_type == "ext4") { command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; } else { errno = ESRCH; LERROR << mnt_type << " has no mkfs cookbook"; return false; } command += " " + scratch_device; auto ret = system(command.c_str()); if (ret) { LERROR << "make " << mnt_type << " filesystem on " << scratch_device << " return=" << ret; return false; } if (!fs_mgr_overlayfs_make_scratch(scratch_device, mnt_type)) return false; if (change) *change = true; Loading @@ -766,6 +796,7 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { 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 (android::base::StartsWith(scratch_device, kPhysicalDevice)) return true; 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); Loading
fs_mgr/tests/adb-remount-test.sh +31 −11 Original line number Diff line number Diff line Loading @@ -378,6 +378,11 @@ fi M=`adb_sh cat /proc/mounts | sed -n 's@\([^ ]*\) /mnt/scratch \([^ ]*\) .*@\2 on \1@p'` [ -n "${M}" ] && echo "${BLUE}[ INFO ]${NORMAL} scratch filesystem ${M}" uses_dynamic_scratch=true if [ "${M}" != "${M##*/dev/block/by-name/}" ]; then uses_dynamic_scratch=false scratch_partition="${M##*/dev/block/by-name/}" fi scratch_size=`adb_sh df -k /mnt/scratch </dev/null 2>/dev/null | while read device kblocks used available use mounted on; do if [ "/mnt/scratch" = "\${mounted}" ]; then Loading Loading @@ -453,16 +458,30 @@ echo "${GREEN}[ RUN ]${NORMAL} flash vendor, confirm its content disappears fastboot flash vendor || ( fastboot reboot && false) || die "fastboot flash vendor" fastboot_getvar partition-type:${scratch_partition} raw || ( fastboot reboot && false) || die "fastboot can not see ${scratch_partition} parameters" if ${uses_dynamic_scratch}; then # check ${scratch_partition} via fastboot fastboot_getvar partition-type:${scratch_partition} raw && fastboot_getvar has-slot:${scratch_partition} no && fastboot_getvar is-logical:${scratch_partition} yes || ( fastboot reboot && false) || die "fastboot can not see ${scratch_partition} parameters" else fastboot_getvar is-logical:${scratch_partition} no || ( fastboot reboot && false) || die "fastboot can not see ${scratch_partition} parameters" fi if ! ${uses_dynamic_scratch}; then fastboot reboot-bootloader || die "Reboot into fastboot" fi if ${uses_dynamic_scratch}; then echo "${BLUE}[ INFO ]${NORMAL} expect fastboot erase ${scratch_partition} to fail" >&2 fastboot erase ${scratch_partition} && ( fastboot reboot || true) && die "fastboot can erase ${scratch_partition}" fi echo "${BLUE}[ INFO ]${NORMAL} expect fastboot format ${scratch_partition} to fail" >&2 fastboot format ${scratch_partition} && ( fastboot reboot || true) && Loading Loading @@ -507,12 +526,13 @@ check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm echo "${GREEN}[ RUN ]${NORMAL} test fastboot flash to ${scratch_partition}" >&2 adb reboot-fastboot && adb reboot-fastboot || die "Reboot into fastbootd" dd if=/dev/zero of=/tmp/adb-remount-test.img bs=4096 count=16 2>/dev/null && fastboot_wait 2m || ( rm /tmp/adb-remount-test.img && false) || die "reboot into fastboot" fastboot flash ${scratch_partition} /tmp/adb-remount-test.img fastboot flash --force ${scratch_partition} /tmp/adb-remount-test.img err=${?} rm /tmp/adb-remount-test.img fastboot reboot || Loading