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

Commit d3ecda57 authored by David Anderson's avatar David Anderson
Browse files

libsnapshot: Clarify the meaning of "compression.enabled".

The compression.enabled property only refers to legacy snapuserd.
However, everywhere it's used, we almost always mean "using the new COW
format with snapuserd, whether compression is enabled or not".

This patch clarifies things by renaming "compression_enabled" fields to
"using_snapuserd".

This also simplifies the feature detection code quite a bit, by removing
some redundant checks and clarifying which cases are legacy vs userspace
snapshots.

Bug: 208944665
Test: vts_libsnapshot_test
      apply OTA, snapshotctl dump
Change-Id: Ie617ed3f92eefb8dff0a5cf13e5a2caa47b9e8e0
parent b0fe01da
Loading
Loading
Loading
Loading
+3 −3
Original line number Diff line number Diff line
@@ -97,8 +97,8 @@ message SnapshotStatus {
    // This is non-zero when |state| == MERGING or MERGE_COMPLETED.
    uint64 metadata_sectors = 8;

    // True if compression is enabled, false otherwise.
    bool compression_enabled = 9;
    // True if using snapuserd, false otherwise.
    bool using_snapuserd = 9;

    // The old partition size (if none existed, this will be zero).
    uint64 old_partition_size = 10;
@@ -184,7 +184,7 @@ message SnapshotUpdateStatus {
    uint64 metadata_sectors = 4;

    // Whether compression/dm-user was used for any snapshots.
    bool compression_enabled = 5;
    bool using_snapuserd = 5;

    // Merge phase (if state == MERGING).
    MergePhase merge_phase = 6;
+1 −1
Original line number Diff line number Diff line
@@ -143,7 +143,7 @@ void WriteExtent(DmSnapCowSizeCalculator* sc, const chromeos_update_engine::Exte
}

std::optional<uint64_t> PartitionCowCreator::GetCowSize() {
    if (compression_enabled) {
    if (using_snapuserd) {
        if (update == nullptr || !update->has_estimate_cow_size()) {
            LOG(ERROR) << "Update manifest does not include a COW size";
            return std::nullopt;
+2 −2
Original line number Diff line number Diff line
@@ -56,8 +56,8 @@ struct PartitionCowCreator {
    // Extra extents that are going to be invalidated during the update
    // process.
    std::vector<ChromeOSExtent> extra_extents = {};
    // True if compression is enabled.
    bool compression_enabled = false;
    // True if snapuserd COWs are enabled.
    bool using_snapuserd = false;
    std::string compression_algorithm;

    struct Return {
+2 −2
Original line number Diff line number Diff line
@@ -249,7 +249,7 @@ TEST_F(PartitionCowCreatorTest, CompressionEnabled) {
                                .target_partition = system_b,
                                .current_metadata = builder_a.get(),
                                .current_suffix = "_a",
                                .compression_enabled = true,
                                .using_snapuserd = true,
                                .update = &update};

    auto ret = creator.Run();
@@ -275,7 +275,7 @@ TEST_F(PartitionCowCreatorTest, CompressionWithNoManifest) {
                                .target_partition = system_b,
                                .current_metadata = builder_a.get(),
                                .current_suffix = "_a",
                                .compression_enabled = true,
                                .using_snapuserd = true,
                                .update = nullptr};

    auto ret = creator.Run();
+80 −86
Original line number Diff line number Diff line
@@ -398,7 +398,7 @@ bool SnapshotManager::CreateSnapshot(LockedFile* lock, PartitionCowCreator* cow_
    status->set_state(SnapshotState::CREATED);
    status->set_sectors_allocated(0);
    status->set_metadata_sectors(0);
    status->set_compression_enabled(cow_creator->compression_enabled);
    status->set_using_snapuserd(cow_creator->using_snapuserd);
    status->set_compression_algorithm(cow_creator->compression_algorithm);

    if (!WriteSnapshotStatus(lock, *status)) {
@@ -788,7 +788,7 @@ bool SnapshotManager::InitiateMerge() {
        }
    }

    bool compression_enabled = false;
    bool using_snapuserd = false;

    std::vector<std::string> first_merge_group;

@@ -809,7 +809,7 @@ bool SnapshotManager::InitiateMerge() {
            return false;
        }

        compression_enabled |= snapshot_status.compression_enabled();
        using_snapuserd |= snapshot_status.using_snapuserd();
        if (DecideMergePhase(snapshot_status) == MergePhase::FIRST_PHASE) {
            first_merge_group.emplace_back(snapshot);
        }
@@ -817,7 +817,7 @@ bool SnapshotManager::InitiateMerge() {

    SnapshotUpdateStatus initial_status = ReadSnapshotUpdateStatus(lock.get());
    initial_status.set_state(UpdateState::Merging);
    initial_status.set_compression_enabled(compression_enabled);
    initial_status.set_using_snapuserd(using_snapuserd);

    if (!UpdateUsesUserSnapshots(lock.get())) {
        initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
@@ -1364,7 +1364,7 @@ MergeFailureCode SnapshotManager::CheckMergeConsistency(LockedFile* lock, const
}

MergeFailureCode CheckMergeConsistency(const std::string& name, const SnapshotStatus& status) {
    if (!status.compression_enabled()) {
    if (!status.using_snapuserd()) {
        // Do not try to verify old-style COWs yet.
        return MergeFailureCode::Ok;
    }
@@ -1625,7 +1625,7 @@ bool SnapshotManager::CollapseSnapshotDevice(LockedFile* lock, const std::string
        // as unmap will fail since dm-user itself was a snapshot device prior
        // to switching of tables. Unmap will fail as the device will be mounted
        // by system partitions
        if (status.compression_enabled()) {
        if (status.using_snapuserd()) {
            auto dm_user_name = GetDmUserCowName(name, GetSnapshotDriver(lock));
            UnmapDmUserDevice(dm_user_name);
        }
@@ -2115,8 +2115,10 @@ bool SnapshotManager::UpdateUsesCompression() {
}

bool SnapshotManager::UpdateUsesCompression(LockedFile* lock) {
    // This returns true even if compression is "none", since update_engine is
    // really just trying to see if snapuserd is in use.
    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock);
    return update_status.compression_enabled();
    return update_status.using_snapuserd();
}

bool SnapshotManager::UpdateUsesIouring(LockedFile* lock) {
@@ -2436,13 +2438,13 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
    remaining_time = GetRemainingTime(params.timeout_ms, begin);
    if (remaining_time.count() < 0) return false;

    if (context == SnapshotContext::Update && live_snapshot_status->compression_enabled()) {
    if (context == SnapshotContext::Update && live_snapshot_status->using_snapuserd()) {
        // Stop here, we can't run dm-user yet, the COW isn't built.
        created_devices.Release();
        return true;
    }

    if (live_snapshot_status->compression_enabled()) {
    if (live_snapshot_status->using_snapuserd()) {
        // Get the source device (eg the view of the partition from before it was resized).
        std::string source_device_path;
        if (live_snapshot_status->old_partition_size() > 0) {
@@ -2944,7 +2946,7 @@ bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state,
    // build fingerprint.
    if (!(state == UpdateState::Initiated || state == UpdateState::None)) {
        SnapshotUpdateStatus old_status = ReadSnapshotUpdateStatus(lock);
        status.set_compression_enabled(old_status.compression_enabled());
        status.set_using_snapuserd(old_status.using_snapuserd());
        status.set_source_build_fingerprint(old_status.source_build_fingerprint());
        status.set_merge_phase(old_status.merge_phase());
        status.set_userspace_snapshots(old_status.userspace_snapshots());
@@ -3198,18 +3200,42 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
    LOG(INFO) << " dap_metadata.cow_version(): " << dap_metadata.cow_version()
              << " writer.GetCowVersion(): " << writer.GetCowVersion();

    bool use_compression = IsCompressionEnabled() && dap_metadata.vabc_enabled() &&
                           !device_->IsRecovery() && cow_format_support;
    // Deduce supported features.
    bool userspace_snapshots = CanUseUserspaceSnapshots();
    bool legacy_compression = GetLegacyCompressionEnabledProperty();

    std::string vabc_disable_reason;
    if (!dap_metadata.vabc_enabled()) {
        vabc_disable_reason = "not enabled metadata";
    } else if (device_->IsRecovery()) {
        vabc_disable_reason = "recovery";
    } else if (!cow_format_support) {
        vabc_disable_reason = "cow format not supported";
    }

    if (!vabc_disable_reason.empty()) {
        if (userspace_snapshots) {
            LOG(INFO) << "Userspace snapshots disabled: " << vabc_disable_reason;
        }
        if (legacy_compression) {
            LOG(INFO) << "Compression disabled: " << vabc_disable_reason;
        }
        userspace_snapshots = false;
        legacy_compression = false;
    }

    const bool using_snapuserd = userspace_snapshots || legacy_compression;
    if (!using_snapuserd) {
        LOG(INFO) << "Using legacy Virtual A/B (dm-snapshot)";
    }

    std::string compression_algorithm;
    if (use_compression) {
    if (using_snapuserd) {
        compression_algorithm = dap_metadata.vabc_compression_param();
        if (compression_algorithm.empty()) {
            // Older OTAs don't set an explicit compression type, so default to gz.
            compression_algorithm = "gz";
        }
    } else {
        compression_algorithm = "none";
    }

    PartitionCowCreator cow_creator{
@@ -3220,7 +3246,7 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
            .current_suffix = current_suffix,
            .update = nullptr,
            .extra_extents = {},
            .compression_enabled = use_compression,
            .using_snapuserd = using_snapuserd,
            .compression_algorithm = compression_algorithm,
    };

@@ -3245,11 +3271,11 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife
        return Return::Error();
    }

    // If compression is enabled, we need to retain a copy of the old metadata
    // If snapuserd is enabled, we need to retain a copy of the old metadata
    // so we can access original blocks in case they are moved around. We do
    // not want to rely on the old super metadata slot because we don't
    // guarantee its validity after the slot switch is successful.
    if (cow_creator.compression_enabled) {
    if (using_snapuserd) {
        auto metadata = current_metadata->Export();
        if (!metadata) {
            LOG(ERROR) << "Could not export current metadata";
@@ -3265,70 +3291,36 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife

    SnapshotUpdateStatus status = ReadSnapshotUpdateStatus(lock.get());
    status.set_state(update_state);
    status.set_compression_enabled(cow_creator.compression_enabled);
    if (cow_creator.compression_enabled) {
        if (!device()->IsTestDevice()) {
            bool userSnapshotsEnabled = IsUserspaceSnapshotsEnabled();
            const std::string UNKNOWN = "unknown";
            const std::string vendor_release = android::base::GetProperty(
                    "ro.vendor.build.version.release_or_codename", UNKNOWN);

            // No user-space snapshots if vendor partition is on Android 12
            if (vendor_release.find("12") != std::string::npos) {
                LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
                          << vendor_release;
                userSnapshotsEnabled = false;
            }

            // Userspace snapshots is enabled only if compression is enabled
            status.set_userspace_snapshots(userSnapshotsEnabled);
            if (userSnapshotsEnabled) {
                is_snapshot_userspace_ = true;
                status.set_io_uring_enabled(IsIouringEnabled());
                LOG(INFO) << "Userspace snapshots enabled";
    status.set_using_snapuserd(using_snapuserd);

    if (userspace_snapshots) {
        status.set_userspace_snapshots(true);
        LOG(INFO) << "Virtual A/B using userspace snapshots";

        if (GetIouringEnabledProperty()) {
            status.set_io_uring_enabled(true);
            LOG(INFO) << "io_uring for snapshots enabled";
        }
    } else if (legacy_compression) {
        LOG(INFO) << "Virtual A/B using legacy snapuserd";
    } else {
                is_snapshot_userspace_ = false;
                LOG(INFO) << "Userspace snapshots disabled";
        LOG(INFO) << "Virtual A/B using dm-snapshot";
    }

    is_snapshot_userspace_.emplace(userspace_snapshots);

    if (!device()->IsTestDevice() && using_snapuserd) {
        // Terminate stale daemon if any
            std::unique_ptr<SnapuserdClient> snapuserd_client =
                    SnapuserdClient::Connect(kSnapuserdSocket, 5s);
        std::unique_ptr<SnapuserdClient> snapuserd_client = std::move(snapuserd_client_);
        if (!snapuserd_client) {
            snapuserd_client = SnapuserdClient::Connect(kSnapuserdSocket, 5s);
        }
        if (snapuserd_client) {
            snapuserd_client->DetachSnapuserd();
            snapuserd_client->CloseConnection();
                snapuserd_client = nullptr;
            }

            // Clear the cached client if any
            if (snapuserd_client_) {
                snapuserd_client_->CloseConnection();
                snapuserd_client_ = nullptr;
            }
        } else {
            bool userSnapshotsEnabled = true;
            const std::string UNKNOWN = "unknown";
            const std::string vendor_release = android::base::GetProperty(
                    "ro.vendor.build.version.release_or_codename", UNKNOWN);

            // No user-space snapshots if vendor partition is on Android 12
            if (vendor_release.find("12") != std::string::npos) {
                LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
                          << vendor_release;
                userSnapshotsEnabled = false;
            }

            userSnapshotsEnabled = (userSnapshotsEnabled && !IsDmSnapshotTestingEnabled());
            status.set_userspace_snapshots(userSnapshotsEnabled);
            if (!userSnapshotsEnabled) {
                is_snapshot_userspace_ = false;
                LOG(INFO) << "User-space snapshots disabled for testing";
            } else {
                is_snapshot_userspace_ = true;
                LOG(INFO) << "User-space snapshots enabled for testing";
            }
        }
    }

    if (!WriteSnapshotUpdateStatus(lock.get(), status)) {
        LOG(ERROR) << "Unable to write new update state";
        return Return::Error();
@@ -3521,7 +3513,7 @@ Return SnapshotManager::InitializeUpdateSnapshots(
            return Return::Error();
        }

        if (it->second.compression_enabled()) {
        if (it->second.using_snapuserd()) {
            unique_fd fd(open(cow_path.c_str(), O_RDWR | O_CLOEXEC));
            if (fd < 0) {
                PLOG(ERROR) << "open " << cow_path << " failed for snapshot "
@@ -3567,8 +3559,8 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para
    if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
        return false;
    }
    if (status.compression_enabled()) {
        LOG(ERROR) << "Cannot use MapUpdateSnapshot with compressed snapshots";
    if (status.using_snapuserd()) {
        LOG(ERROR) << "Cannot use MapUpdateSnapshot with snapuserd";
        return false;
    }

@@ -3625,7 +3617,7 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
        return nullptr;
    }

    if (status.compression_enabled()) {
    if (status.using_snapuserd()) {
        return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(),
                                            status, paths);
    }
@@ -3755,7 +3747,10 @@ bool SnapshotManager::Dump(std::ostream& os) {
    auto update_status = ReadSnapshotUpdateStatus(file.get());

    ss << "Update state: " << ReadUpdateState(file.get()) << std::endl;
    ss << "Compression: " << update_status.compression_enabled() << std::endl;
    ss << "Using snapuserd: " << update_status.using_snapuserd() << std::endl;
    ss << "Using userspace snapshots: " << update_status.userspace_snapshots() << std::endl;
    ss << "Using io_uring: " << update_status.io_uring_enabled() << std::endl;
    ss << "Using XOR compression: " << GetXorCompressionEnabledProperty() << std::endl;
    ss << "Current slot: " << device_->GetSlotSuffix() << std::endl;
    ss << "Boot indicator: booting from " << GetCurrentSlot() << " slot" << std::endl;
    ss << "Rollback indicator: "
@@ -3976,7 +3971,7 @@ bool SnapshotManager::EnsureNoOverflowSnapshot(LockedFile* lock) {
        if (!ReadSnapshotStatus(lock, snapshot, &status)) {
            return false;
        }
        if (status.compression_enabled()) {
        if (status.using_snapuserd()) {
            continue;
        }

@@ -4140,7 +4135,7 @@ bool SnapshotManager::IsSnapuserdRequired() {
    if (!lock) return false;

    auto status = ReadSnapshotUpdateStatus(lock.get());
    return status.state() != UpdateState::None && status.compression_enabled();
    return status.state() != UpdateState::None && status.using_snapuserd();
}

bool SnapshotManager::DetachSnapuserdForSelinux(std::vector<std::string>* snapuserd_argv) {
@@ -4166,7 +4161,7 @@ const LpMetadata* SnapshotManager::ReadOldPartitionMetadata(LockedFile* lock) {
}

MergePhase SnapshotManager::DecideMergePhase(const SnapshotStatus& status) {
    if (status.compression_enabled() && status.device_size() < status.old_partition_size()) {
    if (status.using_snapuserd() && status.device_size() < status.old_partition_size()) {
        return MergePhase::FIRST_PHASE;
    }
    return MergePhase::SECOND_PHASE;
@@ -4208,8 +4203,7 @@ void SnapshotManager::SetMergeStatsFeatures(ISnapshotMergeStats* stats) {
    SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock.get());
    stats->report()->set_iouring_used(update_status.io_uring_enabled());
    stats->report()->set_userspace_snapshots_used(update_status.userspace_snapshots());
    stats->report()->set_xor_compression_used(
            android::base::GetBoolProperty("ro.virtual_ab.compression.xor.enabled", false));
    stats->report()->set_xor_compression_used(GetXorCompressionEnabledProperty());
}

bool SnapshotManager::DeleteDeviceIfExists(const std::string& name,
Loading