Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d48e75a1 authored by Akilesh Kailash's avatar Akilesh Kailash
Browse files

libsnapshot: Pause snapshot merge during shutdown



If the device is mounted off snapshots, initiate the snapshot-merge
pause.

Additionally, try to umount the partitions which are mounted off snapshots.

Bug: 386142969
Test: Reboot device when snapshot merge is in progress and verify merge
threads are paused
Change-Id: Ide9e33157432e3a8d4e6ba7d4d414270505b8941
Signed-off-by: default avatarAkilesh Kailash <akailash@google.com>
parent 27a825f1
Loading
Loading
Loading
Loading
+10 −3
Original line number Diff line number Diff line
@@ -418,9 +418,16 @@ class SnapshotManager final : public ISnapshotManager {
    // first-stage to decide whether to launch snapuserd.
    bool IsSnapuserdRequired();

    // This is primarily used to device reboot. If OTA update is in progress,
    // init will avoid killing processes
    bool IsUserspaceSnapshotUpdateInProgress();
    // This is primarily invoked during device reboot after an OTA update.
    //
    // a: Check if the partitions are mounted off snapshots.
    //
    // b: Store all dynamic partitions which are mounted off snapshots. This
    // is used to unmount the partition.
    bool IsUserspaceSnapshotUpdateInProgress(std::vector<std::string>& dynamic_partitions);

    // Pause the snapshot merge.
    bool PauseSnapshotMerge();

    enum class SnapshotDriver {
        DM_SNAPSHOT,
+18 −4
Original line number Diff line number Diff line
@@ -4687,7 +4687,17 @@ std::string SnapshotManager::ReadSourceBuildFingerprint() {
    return status.source_build_fingerprint();
}

bool SnapshotManager::IsUserspaceSnapshotUpdateInProgress() {
bool SnapshotManager::PauseSnapshotMerge() {
    auto snapuserd_client = SnapuserdClient::TryConnect(kSnapuserdSocket, 5s);
    if (snapuserd_client) {
        // Pause the snapshot-merge
        return snapuserd_client->PauseMerge();
    }
    return false;
}

bool SnapshotManager::IsUserspaceSnapshotUpdateInProgress(
        std::vector<std::string>& dynamic_partitions) {
    // We cannot grab /metadata/ota lock here as this
    // is in reboot path. See b/308900853
    //
@@ -4701,18 +4711,22 @@ bool SnapshotManager::IsUserspaceSnapshotUpdateInProgress() {
        LOG(ERROR) << "No dm-enabled block device is found.";
        return false;
    }

    bool is_ota_in_progress = false;
    for (auto& partition : dm_block_devices) {
        std::string partition_name = partition.first + current_suffix;
        DeviceMapper::TargetInfo snap_target;
        if (!GetSingleTarget(partition_name, TableQuery::Status, &snap_target)) {
            return false;
            continue;
        }
        auto type = DeviceMapper::GetTargetType(snap_target.spec);
        // Partition is mounted off snapshots
        if (type == "user") {
            return true;
            dynamic_partitions.emplace_back("/" + partition.first);
            is_ota_in_progress = true;
        }
    }
    return false;
    return is_ota_in_progress;
}

bool SnapshotManager::BootFromSnapshotsWithoutSlotSwitch() {
+4 −2
Original line number Diff line number Diff line
@@ -3112,8 +3112,10 @@ int main(int argc, char** argv) {
    // thereby interfering with the update and snapshot-merge progress.
    // Hence, wait until the update is complete.
    auto sm = android::snapshot::SnapshotManager::New();
    while (sm->IsUserspaceSnapshotUpdateInProgress()) {
        LOG(INFO) << "Snapshot update is in progress. Waiting...";
    std::vector<std::string> snapshot_partitions;
    while (sm->IsUserspaceSnapshotUpdateInProgress(snapshot_partitions)) {
        LOG(INFO) << "Waiting for: " << snapshot_partitions.size()
                  << " partitions to finish snapshot-merge";
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }

+22 −2
Original line number Diff line number Diff line
@@ -394,6 +394,21 @@ void RebootMonitorThread(unsigned int cmd, const std::string& reboot_target,
    }
}

static void UmountDynamicPartitions(const std::vector<std::string>& dynamic_partitions) {
    for (auto device : dynamic_partitions) {
        // Cannot unmount /system
        if (device == "/system") {
            continue;
        }
        int r = umount2(device.c_str(), MNT_FORCE);
        if (r == 0) {
            LOG(INFO) << "Umounted success: " << device;
        } else {
            PLOG(WARNING) << "Cannot umount: " << device;
        }
    }
}

/* Try umounting all emulated file systems R/W block device cfile systems.
 * This will just try umount and give it up if it fails.
 * For fs like ext4, this is ok as file system will be marked as unclean shutdown
@@ -408,14 +423,18 @@ static UmountStat TryUmountAndFsck(unsigned int cmd, bool run_fsck,
    Timer t;
    std::vector<MountEntry> block_devices;
    std::vector<MountEntry> emulated_devices;
    std::vector<std::string> dynamic_partitions;

    if (run_fsck && !FindPartitionsToUmount(&block_devices, &emulated_devices, false)) {
        return UMOUNT_STAT_ERROR;
    }
    auto sm = snapshot::SnapshotManager::New();
    bool ota_update_in_progress = false;
    if (sm->IsUserspaceSnapshotUpdateInProgress()) {
        LOG(INFO) << "OTA update in progress";
    if (sm->IsUserspaceSnapshotUpdateInProgress(dynamic_partitions)) {
        LOG(INFO) << "OTA update in progress. Pause snapshot merge";
        if (!sm->PauseSnapshotMerge()) {
            LOG(ERROR) << "Snapshot-merge pause failed";
        }
        ota_update_in_progress = true;
    }
    UmountStat stat = UmountPartitions(timeout - t.duration());
@@ -435,6 +454,7 @@ static UmountStat TryUmountAndFsck(unsigned int cmd, bool run_fsck,
        // still not doing fsck when all processes are killed.
        //
        if (ota_update_in_progress) {
            UmountDynamicPartitions(dynamic_partitions);
            return stat;
        }
        KillAllProcesses();