fs_mgr: overlayfs: resize scratch should it be too small
If scratch gets made too small (eg: fastboot flash scratch small-file) it can not recover without a workaround. The workaround is not intuitive, (adb enable-verity then adb disable-verity to erase and re-establish the proper sized scratch. This needs to be automatic. If we detect it is too small to support a filesystem, resize it to an more appropriate size if it exists. Alter unit test to check for fastboot characteristics and assumptions associated with the scratch partition, and a test case to flash the partition. Test: adb-remount-test.sh Bug: 109821005 Change-Id: Icfceaa461c2bf13ca5a7dd4e34675dde8a4d251f
This commit is contained in:
parent
fa105049d8
commit
cb2f6b6776
|
@ -432,7 +432,7 @@ bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change)
|
|||
if (change) *change = true;
|
||||
if (!DestroyLogicalPartition(partition_name, 0s)) return false;
|
||||
} else {
|
||||
PERROR << "delete partition " << overlay;
|
||||
LERROR << "delete partition " << overlay;
|
||||
return false;
|
||||
}
|
||||
errno = save_errno;
|
||||
|
@ -647,49 +647,65 @@ 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);
|
||||
auto partition_create = !fs_mgr_rw_access(scratch_device);
|
||||
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) {
|
||||
LERROR << "open " << super_device << " metadata";
|
||||
return false;
|
||||
}
|
||||
const auto partition_name = android::base::Basename(kScratchMountPoint);
|
||||
auto partition = builder->FindPartition(partition_name);
|
||||
auto partition_exists = partition != nullptr;
|
||||
auto changed = false;
|
||||
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";
|
||||
partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE);
|
||||
if (!partition) {
|
||||
LERROR << "create " << partition_name;
|
||||
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;
|
||||
changed = true;
|
||||
}
|
||||
// Take half of free space, minimum 512MB or free space - 256KB margin.
|
||||
static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024);
|
||||
static constexpr auto kMarginSize = uint64_t(256 * 1024);
|
||||
if (partition->size() < kMinimumSize) {
|
||||
auto partition_size =
|
||||
builder->AllocatableSpace() - builder->UsedSpace() + partition->size();
|
||||
if ((partition_size > kMinimumSize) || !partition->size()) {
|
||||
partition_size = std::max(std::min(kMinimumSize, partition_size - kMarginSize),
|
||||
partition_size / 2);
|
||||
if (partition_size > partition->size()) {
|
||||
if (!builder->ResizePartition(partition, partition_size)) {
|
||||
LERROR << "resize " << partition_name;
|
||||
return false;
|
||||
}
|
||||
if (!partition_create) DestroyLogicalPartition(partition_name, 10s);
|
||||
changed = true;
|
||||
partition_exists = 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;
|
||||
}
|
||||
}
|
||||
// land the update back on to the partition
|
||||
if (changed) {
|
||||
auto metadata = builder->Export();
|
||||
if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) {
|
||||
LERROR << "add partition " << partition_name;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (change) *change = true;
|
||||
}
|
||||
|
||||
if (changed || partition_create) {
|
||||
if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s,
|
||||
&scratch_device))
|
||||
return false;
|
||||
|
||||
if (change) *change = true;
|
||||
}
|
||||
|
||||
if (partition_exists) {
|
||||
|
@ -709,6 +725,7 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) {
|
|||
} 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;
|
||||
}
|
||||
|
|
|
@ -63,6 +63,7 @@ adb_date() {
|
|||
|
||||
Returns: the logcat output" ]
|
||||
adb_logcat() {
|
||||
echo "${RED}[ INFO ]${NORMAL} logcat ${@}" >&2 &&
|
||||
adb logcat "${@}" </dev/null |
|
||||
grep -v 'logd : logdr: UID=' |
|
||||
sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //'
|
||||
|
@ -106,12 +107,13 @@ adb_cat() {
|
|||
|
||||
Returns: true if the reboot command succeeded" ]
|
||||
adb_reboot() {
|
||||
adb reboot remount-test
|
||||
adb reboot remount-test &&
|
||||
sleep 2
|
||||
}
|
||||
|
||||
[ "USAGE: adb_wait [timeout]
|
||||
|
||||
Returns: waits until the device has returned or the optional timeout" ]
|
||||
Returns: waits until the device has returned for adb or optional timeout" ]
|
||||
adb_wait() {
|
||||
if [ -n "${1}" ]; then
|
||||
timeout --preserve-status --signal=KILL ${1} adb wait-for-device
|
||||
|
@ -120,14 +122,49 @@ adb_wait() {
|
|||
fi
|
||||
}
|
||||
|
||||
[ "USAGE: fastboot_wait [timeout]
|
||||
|
||||
Returns: waits until the device has returned for fastboot or optional timeout" ]
|
||||
fastboot_wait() {
|
||||
# fastboot has no wait-for-device, but it does an automatic
|
||||
# wait and requires (even a nonsensical) command to do so.
|
||||
if [ -n "${1}" ]; then
|
||||
timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device
|
||||
else
|
||||
fastboot wait-for-device >/dev/null
|
||||
fi >/dev/null 2>/dev/null ||
|
||||
inFastboot
|
||||
}
|
||||
|
||||
[ "USAGE: adb_root
|
||||
|
||||
Returns: true if device in root state" ]
|
||||
adb_root() {
|
||||
adb root >/dev/null </dev/null 2>/dev/null &&
|
||||
sleep 1 &&
|
||||
adb_wait &&
|
||||
sleep 1
|
||||
adb root >/dev/null </dev/null 2>/dev/null
|
||||
sleep 2
|
||||
adb_wait 2m &&
|
||||
[ `adb_sh echo '${USER}'` = root ]
|
||||
}
|
||||
|
||||
[ "USAGE: fastboot_getvar var expected
|
||||
|
||||
Returns: true if var output matches expected" ]
|
||||
fastboot_getvar() {
|
||||
O=`fastboot getvar ${1} 2>&1`
|
||||
err=${?}
|
||||
O="${O#< waiting for * >?}"
|
||||
O="${O%%?Finished. Total time: *}"
|
||||
if [ 0 -ne ${err} ]; then
|
||||
echo ${O} >&2
|
||||
false
|
||||
return
|
||||
fi
|
||||
if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then
|
||||
echo "${2} != ${O}" >&2
|
||||
false
|
||||
return
|
||||
fi
|
||||
echo ${O} >&2
|
||||
}
|
||||
|
||||
[ "USAGE: die [-t <epoch>] [message] >/dev/stderr
|
||||
|
@ -233,8 +270,7 @@ adb_sh ls -d /sys/module/overlay </dev/null >/dev/null &&
|
|||
adb_su ls /sys/module/overlay/parameters/override_creds </dev/null >/dev/null &&
|
||||
echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 ||
|
||||
die "overlay module can not be used on ANDROID"
|
||||
adb_root &&
|
||||
adb_wait ||
|
||||
adb_root ||
|
||||
die "initial setup"
|
||||
reboot=false
|
||||
OVERLAYFS_BACKING="cache mnt/scratch"
|
||||
|
@ -250,8 +286,7 @@ if ${reboot}; then
|
|||
echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2
|
||||
adb_reboot &&
|
||||
adb_wait 2m &&
|
||||
adb_root &&
|
||||
adb_wait ||
|
||||
adb_root ||
|
||||
die "reboot after wipe"
|
||||
fi
|
||||
D=`adb_sh df -k </dev/null` &&
|
||||
|
@ -288,7 +323,6 @@ echo "${D}" | grep "^overlay .* /system\$" >/dev/null ||
|
|||
|
||||
T=`adb_date`
|
||||
adb_root &&
|
||||
adb_wait &&
|
||||
adb remount &&
|
||||
D=`adb_sh df -k </dev/null` ||
|
||||
die -t ${T} "can not collect filesystem data"
|
||||
|
@ -340,19 +374,28 @@ B="`adb_cat /vendor/hello`" &&
|
|||
die "re-read vendor hello after reboot w/o root"
|
||||
check_eq "cat: /vendor/hello: Permission denied" "${B}" vendor after reboot w/o root
|
||||
adb_root &&
|
||||
adb_wait &&
|
||||
B="`adb_cat /vendor/hello`" ||
|
||||
die "re-read vendor hello after reboot"
|
||||
check_eq "${A}" "${B}" vendor after reboot
|
||||
|
||||
adb reboot-fastboot &&
|
||||
fastboot flash vendor &&
|
||||
fastboot reboot ||
|
||||
fastboot_wait 2m &&
|
||||
fastboot flash vendor ||
|
||||
die "fastbootd flash vendor"
|
||||
# check scratch via fastboot
|
||||
fastboot_getvar partition-type:scratch raw &&
|
||||
fastboot_getvar has-slot:scratch no &&
|
||||
fastboot_getvar is-logical:scratch yes ||
|
||||
die "fastboot can not see scratch parameters"
|
||||
echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot erase scratch to fail" >&2
|
||||
fastboot erase scratch &&
|
||||
die "fastbootd can erase scratch"
|
||||
fastboot reboot ||
|
||||
die "can not reboot out of fastbootd"
|
||||
echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes"
|
||||
adb_wait 2m ||
|
||||
die "did not reboot after flash"
|
||||
adb_root &&
|
||||
adb_wait &&
|
||||
D=`adb_sh df -k </dev/null` &&
|
||||
H=`echo "${D}" | head -1` &&
|
||||
D=`echo "${D}" | grep "^overlay "` &&
|
||||
|
@ -365,8 +408,7 @@ echo "${D}" | grep "^overlay .* /vendor\$" >/dev/null &&
|
|||
B="`adb_cat /system/hello`" ||
|
||||
die "re-read system hello after flash vendor"
|
||||
check_eq "${A}" "${B}" system after flash vendor
|
||||
adb_root &&
|
||||
adb_wait ||
|
||||
adb_root ||
|
||||
die "adb root"
|
||||
B="`adb_cat /vendor/hello`" &&
|
||||
die "re-read vendor hello after flash vendor"
|
||||
|
@ -384,4 +426,27 @@ B="`adb_cat /vendor/hello`" &&
|
|||
die "re-read vendor hello after rm"
|
||||
check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm
|
||||
|
||||
adb reboot-fastboot &&
|
||||
dd if=/dev/zero of=adb-remount-test.img bs=4096 count=16 &&
|
||||
fastboot_wait 2m ||
|
||||
die "reboot into fastbootd"
|
||||
fastboot flash scratch adb-remount-test.img
|
||||
err=${?}
|
||||
rm adb-remount-test.img
|
||||
[ 0 -eq ${err} ] ||
|
||||
die "fastbootd flash scratch"
|
||||
fastboot reboot ||
|
||||
die "can not reboot out of fastbootd"
|
||||
adb_wait 2m &&
|
||||
adb_root ||
|
||||
die "did not reboot after flash"
|
||||
T=`adb_date`
|
||||
D=`adb disable-verity 2>&1`
|
||||
err=${?}
|
||||
echo "${D}"
|
||||
[ ${err} = 0 ] &&
|
||||
[ X"${D}" = X"${D##*setup failed}" ] &&
|
||||
[ X"${D}" != X"${D##*using overlayfs}" ] ||
|
||||
die -t ${T} "setup for overlayfs"
|
||||
|
||||
echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2
|
||||
|
|
Loading…
Reference in New Issue