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

Commit dfaede06 authored by David Anderson's avatar David Anderson Committed by Gerrit Code Review
Browse files

Merge changes from topic "init-snapuserd"

* changes:
  libsnapshot: Implement MapAllSnapshots and UnmapAllSnapshots.
  Start snapuserd if needed as soon as possible during second-stage init.
  libsnapshot: Add support for first-to-second-stage transitions of snapuserd.
parents 22e036bd 2eb7b922
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -31,15 +31,17 @@ cc_defaults {
        "libbrotli",
        "libbrotli",
        "libdm",
        "libdm",
        "libfstab",
        "libfstab",
        "libsnapshot_cow",
        "update_metadata-protos",
        "update_metadata-protos",
    ],
    ],
    whole_static_libs: [
    whole_static_libs: [
        "libbrotli",
        "libcutils",
        "libcutils",
        "libext2_uuid",
        "libext2_uuid",
        "libext4_utils",
        "libext4_utils",
        "libfstab",
        "libfstab",
        "libsnapshot_cow",
        "libsnapshot_snapuserd",
        "libsnapshot_snapuserd",
        "libz",
    ],
    ],
    header_libs: [
    header_libs: [
        "libchrome",
        "libchrome",
@@ -432,6 +434,7 @@ cc_binary {
    init_rc: [
    init_rc: [
        "snapuserd.rc",
        "snapuserd.rc",
    ],
    ],
    static_executable: true,
}
}


cc_binary {
cc_binary {
+24 −3
Original line number Original line Diff line number Diff line
@@ -15,6 +15,7 @@
#pragma once
#pragma once


#include <stdint.h>
#include <stdint.h>
#include <unistd.h>


#include <chrono>
#include <chrono>
#include <map>
#include <map>
@@ -77,6 +78,7 @@ class SnapshotMergeStats;
class SnapshotStatus;
class SnapshotStatus;


static constexpr const std::string_view kCowGroupName = "cow";
static constexpr const std::string_view kCowGroupName = "cow";
static constexpr char kVirtualAbCompressionProp[] = "ro.virtual_ab.compression.enabled";


bool OptimizeSourceCopyOperation(const chromeos_update_engine::InstallOperation& operation,
bool OptimizeSourceCopyOperation(const chromeos_update_engine::InstallOperation& operation,
                                 chromeos_update_engine::InstallOperation* optimized);
                                 chromeos_update_engine::InstallOperation* optimized);
@@ -104,6 +106,7 @@ class ISnapshotManager {
                android::hardware::boot::V1_1::MergeStatus status) = 0;
                android::hardware::boot::V1_1::MergeStatus status) = 0;
        virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
        virtual bool SetSlotAsUnbootable(unsigned int slot) = 0;
        virtual bool IsRecovery() const = 0;
        virtual bool IsRecovery() const = 0;
        virtual bool IsTestDevice() const { return false; }
    };
    };
    virtual ~ISnapshotManager() = default;
    virtual ~ISnapshotManager() = default;


@@ -303,6 +306,14 @@ class SnapshotManager final : public ISnapshotManager {
    // Helper function for second stage init to restorecon on the rollback indicator.
    // Helper function for second stage init to restorecon on the rollback indicator.
    static std::string GetGlobalRollbackIndicatorPath();
    static std::string GetGlobalRollbackIndicatorPath();


    // Initiate the transition from first-stage to second-stage snapuserd. This
    // process involves re-creating the dm-user table entries for each device,
    // so that they connect to the new daemon. Once all new tables have been
    // activated, we ask the first-stage daemon to cleanly exit.
    //
    // The caller must pass a function which starts snapuserd.
    bool PerformSecondStageTransition();

    // ISnapshotManager overrides.
    // ISnapshotManager overrides.
    bool BeginUpdate() override;
    bool BeginUpdate() override;
    bool CancelUpdate() override;
    bool CancelUpdate() override;
@@ -345,6 +356,7 @@ class SnapshotManager final : public ISnapshotManager {
    FRIEND_TEST(SnapshotTest, Merge);
    FRIEND_TEST(SnapshotTest, Merge);
    FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
    FRIEND_TEST(SnapshotTest, NoMergeBeforeReboot);
    FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
    FRIEND_TEST(SnapshotTest, UpdateBootControlHal);
    FRIEND_TEST(SnapshotUpdateTest, DaemonTransition);
    FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
    FRIEND_TEST(SnapshotUpdateTest, DataWipeAfterRollback);
    FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
    FRIEND_TEST(SnapshotUpdateTest, DataWipeRollbackInRecovery);
    FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
    FRIEND_TEST(SnapshotUpdateTest, FullUpdateFlow);
@@ -372,11 +384,13 @@ class SnapshotManager final : public ISnapshotManager {
    // Ensure we're connected to snapuserd.
    // Ensure we're connected to snapuserd.
    bool EnsureSnapuserdConnected();
    bool EnsureSnapuserdConnected();


    // Helper for first-stage init.
    // Helpers for first-stage init.
    bool ForceLocalImageManager();
    bool ForceLocalImageManager();
    const std::unique_ptr<IDeviceInfo>& device() const { return device_; }


    // Helper function for tests.
    // Helper functions for tests.
    IImageManager* image_manager() const { return images_.get(); }
    IImageManager* image_manager() const { return images_.get(); }
    void set_use_first_stage_snapuserd(bool value) { use_first_stage_snapuserd_ = value; }


    // Since libsnapshot is included into multiple processes, we flock() our
    // Since libsnapshot is included into multiple processes, we flock() our
    // files for simple synchronization. LockedFile is a helper to assist with
    // files for simple synchronization. LockedFile is a helper to assist with
@@ -545,6 +559,9 @@ class SnapshotManager final : public ISnapshotManager {
    std::string GetSnapshotDeviceName(const std::string& snapshot_name,
    std::string GetSnapshotDeviceName(const std::string& snapshot_name,
                                      const SnapshotStatus& status);
                                      const SnapshotStatus& status);


    bool MapAllPartitions(LockedFile* lock, const std::string& super_device, uint32_t slot,
                          const std::chrono::milliseconds& timeout_ms);

    // Reason for calling MapPartitionWithSnapshot.
    // Reason for calling MapPartitionWithSnapshot.
    enum class SnapshotContext {
    enum class SnapshotContext {
        // For writing or verification (during update_engine).
        // For writing or verification (during update_engine).
@@ -618,9 +635,12 @@ class SnapshotManager final : public ISnapshotManager {
            const LpMetadata* exported_target_metadata, const std::string& target_suffix,
            const LpMetadata* exported_target_metadata, const std::string& target_suffix,
            const std::map<std::string, SnapshotStatus>& all_snapshot_status);
            const std::map<std::string, SnapshotStatus>& all_snapshot_status);


    // Implementation of UnmapAllSnapshots(), with the lock provided.
    bool UnmapAllSnapshots(LockedFile* lock);

    // Unmap all partitions that were mapped by CreateLogicalAndSnapshotPartitions.
    // Unmap all partitions that were mapped by CreateLogicalAndSnapshotPartitions.
    // This should only be called in recovery.
    // This should only be called in recovery.
    bool UnmapAllPartitions();
    bool UnmapAllPartitionsInRecovery();


    // Check no snapshot overflows. Note that this returns false negatives if the snapshot
    // Check no snapshot overflows. Note that this returns false negatives if the snapshot
    // overflows, then is remapped and not written afterwards.
    // overflows, then is remapped and not written afterwards.
@@ -660,6 +680,7 @@ class SnapshotManager final : public ISnapshotManager {
    std::unique_ptr<IDeviceInfo> device_;
    std::unique_ptr<IDeviceInfo> device_;
    std::unique_ptr<IImageManager> images_;
    std::unique_ptr<IImageManager> images_;
    bool has_local_image_manager_ = false;
    bool has_local_image_manager_ = false;
    bool use_first_stage_snapuserd_ = false;
    bool in_factory_data_reset_ = false;
    bool in_factory_data_reset_ = false;
    std::unique_ptr<SnapuserdClient> snapuserd_client_;
    std::unique_ptr<SnapuserdClient> snapuserd_client_;
};
};
+8 −0
Original line number Original line Diff line number Diff line
@@ -14,6 +14,8 @@


#pragma once
#pragma once


#include <unistd.h>

#include <chrono>
#include <chrono>
#include <cstring>
#include <cstring>
#include <iostream>
#include <iostream>
@@ -31,9 +33,15 @@ static constexpr uint32_t PACKET_SIZE = 512;
static constexpr char kSnapuserdSocketFirstStage[] = "snapuserd_first_stage";
static constexpr char kSnapuserdSocketFirstStage[] = "snapuserd_first_stage";
static constexpr char kSnapuserdSocket[] = "snapuserd";
static constexpr char kSnapuserdSocket[] = "snapuserd";


static constexpr char kSnapuserdFirstStagePidVar[] = "FIRST_STAGE_SNAPUSERD_PID";

// Ensure that the second-stage daemon for snapuserd is running.
// Ensure that the second-stage daemon for snapuserd is running.
bool EnsureSnapuserdStarted();
bool EnsureSnapuserdStarted();


// Start the first-stage version of snapuserd, returning its pid. This is used
// by first-stage init, as well as vts_libsnapshot_test. On failure, -1 is returned.
pid_t StartFirstStageSnapuserd();

class SnapuserdClient {
class SnapuserdClient {
  private:
  private:
    android::base::unique_fd sockfd_;
    android::base::unique_fd sockfd_;
+1 −0
Original line number Original line Diff line number Diff line
@@ -95,6 +95,7 @@ class TestDeviceInfo : public SnapshotManager::IDeviceInfo {
        unbootable_slots_.insert(slot);
        unbootable_slots_.insert(slot);
        return true;
        return true;
    }
    }
    bool IsTestDevice() const override { return true; }


    bool IsSlotUnbootable(uint32_t slot) { return unbootable_slots_.count(slot) != 0; }
    bool IsSlotUnbootable(uint32_t slot) { return unbootable_slots_.count(slot) != 0; }


+231 −24
Original line number Original line Diff line number Diff line
@@ -31,8 +31,10 @@
#include <android-base/properties.h>
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
#include <android-base/unique_fd.h>
#include <cutils/sockets.h>
#include <ext4_utils/ext4_utils.h>
#include <ext4_utils/ext4_utils.h>
#include <fs_mgr.h>
#include <fs_mgr.h>
#include <fs_mgr/file_wait.h>
#include <fs_mgr_dm_linear.h>
#include <fs_mgr_dm_linear.h>
#include <fstab/fstab.h>
#include <fstab/fstab.h>
#include <libdm/dm.h>
#include <libdm/dm.h>
@@ -100,6 +102,12 @@ std::unique_ptr<SnapshotManager> SnapshotManager::NewForFirstStageMount(IDeviceI
    if (!sm || !sm->ForceLocalImageManager()) {
    if (!sm || !sm->ForceLocalImageManager()) {
        return nullptr;
        return nullptr;
    }
    }

    // The first-stage version of snapuserd is explicitly started by init. Do
    // not attempt to using it during tests (which run in normal AOSP).
    if (!sm->device()->IsTestDevice()) {
        sm->use_first_stage_snapuserd_ = true;
    }
    return sm;
    return sm;
}
}


@@ -400,8 +408,15 @@ bool SnapshotManager::MapDmUserCow(LockedFile* lock, const std::string& name,
        base_sectors = dev_size / kSectorSize;
        base_sectors = dev_size / kSectorSize;
    }
    }


    // Use an extra decoration for first-stage init, so we can transition
    // to a new table entry in second-stage.
    std::string misc_name = name;
    if (use_first_stage_snapuserd_) {
        misc_name += "-init";
    }

    DmTable table;
    DmTable table;
    table.Emplace<DmTargetUser>(0, base_sectors, name);
    table.Emplace<DmTargetUser>(0, base_sectors, misc_name);
    if (!dm.CreateDevice(name, table, path, timeout_ms)) {
    if (!dm.CreateDevice(name, table, path, timeout_ms)) {
        return false;
        return false;
    }
    }
@@ -410,7 +425,7 @@ bool SnapshotManager::MapDmUserCow(LockedFile* lock, const std::string& name,
        return false;
        return false;
    }
    }


    auto control_device = "/dev/dm-user/" + name;
    auto control_device = "/dev/dm-user/" + misc_name;
    return snapuserd_client_->InitializeSnapuserd(cow_file, base_device, control_device);
    return snapuserd_client_->InitializeSnapuserd(cow_file, base_device, control_device);
}
}


@@ -1284,6 +1299,107 @@ bool SnapshotManager::HandleCancelledUpdate(LockedFile* lock,
    return RemoveAllUpdateState(lock, before_cancel);
    return RemoveAllUpdateState(lock, before_cancel);
}
}


bool SnapshotManager::PerformSecondStageTransition() {
    LOG(INFO) << "Performing second-stage transition for snapuserd.";

    // Don't use EnsuerSnapuserdConnected() because this is called from init,
    // and attempting to do so will deadlock.
    if (!snapuserd_client_) {
        snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, 10s);
        if (!snapuserd_client_) {
            LOG(ERROR) << "Unable to connect to snapuserd";
            return false;
        }
    }

    auto& dm = DeviceMapper::Instance();

    auto lock = LockExclusive();
    if (!lock) return false;

    std::vector<std::string> snapshots;
    if (!ListSnapshots(lock.get(), &snapshots)) {
        LOG(ERROR) << "Failed to list snapshots.";
        return false;
    }

    size_t num_cows = 0;
    size_t ok_cows = 0;
    for (const auto& snapshot : snapshots) {
        std::string cow_name = GetDmUserCowName(snapshot);
        if (dm.GetState(cow_name) == DmDeviceState::INVALID) {
            continue;
        }

        DeviceMapper::TargetInfo target;
        if (!GetSingleTarget(cow_name, TableQuery::Table, &target)) {
            continue;
        }

        auto target_type = DeviceMapper::GetTargetType(target.spec);
        if (target_type != "user") {
            LOG(ERROR) << "Unexpected target type for " << cow_name << ": " << target_type;
            continue;
        }

        num_cows++;

        DmTable table;
        table.Emplace<DmTargetUser>(0, target.spec.length, cow_name);
        if (!dm.LoadTableAndActivate(cow_name, table)) {
            LOG(ERROR) << "Unable to swap tables for " << cow_name;
            continue;
        }

        std::string backing_device;
        if (!dm.GetDmDevicePathByName(GetBaseDeviceName(snapshot), &backing_device)) {
            LOG(ERROR) << "Could not get device path for " << GetBaseDeviceName(snapshot);
            continue;
        }

        std::string cow_device;
        if (!dm.GetDmDevicePathByName(GetCowName(snapshot), &cow_device)) {
            LOG(ERROR) << "Could not get device path for " << GetCowName(snapshot);
            continue;
        }

        // Wait for ueventd to acknowledge and create the control device node.
        std::string control_device = "/dev/dm-user/" + cow_name;
        if (!android::fs_mgr::WaitForFile(control_device, 10s)) {
            LOG(ERROR) << "Could not find control device: " << control_device;
            continue;
        }

        if (!snapuserd_client_->InitializeSnapuserd(cow_device, backing_device, control_device)) {
            // This error is unrecoverable. We cannot proceed because reads to
            // the underlying device will fail.
            LOG(FATAL) << "Could not initialize snapuserd for " << cow_name;
            return false;
        }

        ok_cows++;
    }

    if (ok_cows != num_cows) {
        LOG(ERROR) << "Could not transition all snapuserd consumers.";
        return false;
    }

    int pid;
    const char* pid_str = getenv(kSnapuserdFirstStagePidVar);
    if (pid_str && android::base::ParseInt(pid_str, &pid)) {
        if (kill(pid, SIGTERM) < 0 && errno != ESRCH) {
            LOG(ERROR) << "kill snapuserd failed";
            return false;
        }
    } else {
        LOG(ERROR) << "Could not find or parse " << kSnapuserdFirstStagePidVar
                   << " for snapuserd pid";
        return false;
    }
    return true;
}

std::unique_ptr<LpMetadata> SnapshotManager::ReadCurrentMetadata() {
std::unique_ptr<LpMetadata> SnapshotManager::ReadCurrentMetadata() {
    const auto& opener = device_->GetPartitionOpener();
    const auto& opener = device_->GetPartitionOpener();
    uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
    uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
@@ -1593,8 +1709,13 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(
    auto lock = LockExclusive();
    auto lock = LockExclusive();
    if (!lock) return false;
    if (!lock) return false;


    const auto& opener = device_->GetPartitionOpener();
    uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
    uint32_t slot = SlotNumberForSlotSuffix(device_->GetSlotSuffix());
    return MapAllPartitions(lock.get(), super_device, slot, timeout_ms);
}

bool SnapshotManager::MapAllPartitions(LockedFile* lock, const std::string& super_device,
                                       uint32_t slot, const std::chrono::milliseconds& timeout_ms) {
    const auto& opener = device_->GetPartitionOpener();
    auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot);
    auto metadata = android::fs_mgr::ReadMetadata(opener, super_device, slot);
    if (!metadata) {
    if (!metadata) {
        LOG(ERROR) << "Could not read dynamic partition metadata for device: " << super_device;
        LOG(ERROR) << "Could not read dynamic partition metadata for device: " << super_device;
@@ -1615,12 +1736,20 @@ bool SnapshotManager::CreateLogicalAndSnapshotPartitions(
                .partition_opener = &opener,
                .partition_opener = &opener,
                .timeout_ms = timeout_ms,
                .timeout_ms = timeout_ms,
        };
        };
        if (!MapPartitionWithSnapshot(lock.get(), std::move(params), SnapshotContext::Mount,
        if (!MapPartitionWithSnapshot(lock, std::move(params), SnapshotContext::Mount, nullptr)) {
                                      nullptr)) {
            return false;
            return false;
        }
        }
    }
    }


    if (use_first_stage_snapuserd_) {
        // Remove the first-stage socket as a precaution, there is no need to
        // access the daemon anymore and we'll be killing it once second-stage
        // is running.
        auto socket = ANDROID_SOCKET_DIR + "/"s + kSnapuserdSocketFirstStage;
        snapuserd_client_ = nullptr;
        unlink(socket.c_str());
    }

    LOG(INFO) << "Created logical partitions with snapshot.";
    LOG(INFO) << "Created logical partitions with snapshot.";
    return true;
    return true;
}
}
@@ -1925,10 +2054,18 @@ bool SnapshotManager::UnmapCowDevices(LockedFile* lock, const std::string& name)
            LOG(ERROR) << "Cannot unmap " << dm_user_name;
            LOG(ERROR) << "Cannot unmap " << dm_user_name;
            return false;
            return false;
        }
        }
        if (!snapuserd_client_->WaitForDeviceDelete("/dev/dm-user/" + dm_user_name)) {

        auto control_device = "/dev/dm-user/" + dm_user_name;
        if (!snapuserd_client_->WaitForDeviceDelete(control_device)) {
            LOG(ERROR) << "Failed to wait for " << dm_user_name << " control device to delete";
            LOG(ERROR) << "Failed to wait for " << dm_user_name << " control device to delete";
            return false;
            return false;
        }
        }

        // Ensure the control device is gone so we don't run into ABA problems.
        if (!android::fs_mgr::WaitForFileDeleted(control_device, 10s)) {
            LOG(ERROR) << "Timed out waiting for " << control_device << " to unlink";
            return false;
        }
    }
    }


    auto cow_name = GetCowName(name);
    auto cow_name = GetCowName(name);
@@ -1945,15 +2082,50 @@ bool SnapshotManager::UnmapCowDevices(LockedFile* lock, const std::string& name)
    return true;
    return true;
}
}


bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds&) {
bool SnapshotManager::MapAllSnapshots(const std::chrono::milliseconds& timeout_ms) {
    LOG(ERROR) << "Not yet implemented.";
    auto lock = LockExclusive();
    if (!lock) return false;

    auto state = ReadUpdateState(lock.get());
    if (state == UpdateState::Unverified) {
        if (GetCurrentSlot() == Slot::Target) {
            LOG(ERROR) << "Cannot call MapAllSnapshots when booting from the target slot.";
            return false;
        }
    } else if (state != UpdateState::Initiated) {
        LOG(ERROR) << "Cannot call MapAllSnapshots from update state: " << state;
        return false;
        return false;
    }
    }


    if (!UnmapAllSnapshots(lock.get())) {
        return false;
    }

    uint32_t slot = SlotNumberForSlotSuffix(device_->GetOtherSlotSuffix());
    return MapAllPartitions(lock.get(), device_->GetSuperDevice(slot), slot, timeout_ms);
}

bool SnapshotManager::UnmapAllSnapshots() {
bool SnapshotManager::UnmapAllSnapshots() {
    LOG(ERROR) << "Not yet implemented.";
    auto lock = LockExclusive();
    if (!lock) return false;

    return UnmapAllSnapshots(lock.get());
}

bool SnapshotManager::UnmapAllSnapshots(LockedFile* lock) {
    std::vector<std::string> snapshots;
    if (!ListSnapshots(lock, &snapshots)) {
        return false;
    }

    for (const auto& snapshot : snapshots) {
        if (!UnmapPartitionWithSnapshot(lock, snapshot)) {
            LOG(ERROR) << "Failed to unmap snapshot: " << snapshot;
            return false;
            return false;
        }
        }
    }
    return true;
}


auto SnapshotManager::OpenFile(const std::string& file, int lock_flags)
auto SnapshotManager::OpenFile(const std::string& file, int lock_flags)
        -> std::unique_ptr<LockedFile> {
        -> std::unique_ptr<LockedFile> {
@@ -2212,16 +2384,36 @@ bool SnapshotManager::EnsureImageManager() {
}
}


bool SnapshotManager::EnsureSnapuserdConnected() {
bool SnapshotManager::EnsureSnapuserdConnected() {
    if (!snapuserd_client_) {
    if (snapuserd_client_) {
        return true;
    }

    std::string socket;
    if (use_first_stage_snapuserd_) {
        auto pid = StartFirstStageSnapuserd();
        if (pid < 0) {
            LOG(ERROR) << "Failed to start snapuserd";
            return false;
        }

        auto pid_str = std::to_string(static_cast<int>(pid));
        if (setenv(kSnapuserdFirstStagePidVar, pid_str.c_str(), 1) < 0) {
            PLOG(ERROR) << "setenv failed storing the snapuserd pid";
        }

        socket = kSnapuserdSocketFirstStage;
    } else {
        if (!EnsureSnapuserdStarted()) {
        if (!EnsureSnapuserdStarted()) {
            return false;
            return false;
        }
        }
        snapuserd_client_ = SnapuserdClient::Connect(kSnapuserdSocket, 10s);
        socket = kSnapuserdSocket;
    }

    snapuserd_client_ = SnapuserdClient::Connect(socket, 10s);
    if (!snapuserd_client_) {
    if (!snapuserd_client_) {
        LOG(ERROR) << "Unable to connect to snapuserd";
        LOG(ERROR) << "Unable to connect to snapuserd";
        return false;
        return false;
    }
    }
    }
    return true;
    return true;
}
}


@@ -2538,12 +2730,27 @@ Return SnapshotManager::InitializeUpdateSnapshots(
            return Return::Error();
            return Return::Error();
        }
        }


        auto ret = InitializeCow(cow_path);
        if (IsCompressionEnabled()) {
            unique_fd fd(open(cow_path.c_str(), O_RDWR | O_CLOEXEC));
            if (fd < 0) {
                PLOG(ERROR) << "open " << cow_path << " failed for snapshot "
                            << cow_params.partition_name;
                return Return::Error();
            }

            CowWriter writer(CowOptions{});
            if (!writer.Initialize(fd) || !writer.Finalize()) {
                LOG(ERROR) << "Could not initialize COW device for " << target_partition->name();
                return Return::Error();
            }
        } else {
            auto ret = InitializeKernelCow(cow_path);
            if (!ret.is_ok()) {
            if (!ret.is_ok()) {
                LOG(ERROR) << "Can't zero-fill COW device for " << target_partition->name() << ": "
                LOG(ERROR) << "Can't zero-fill COW device for " << target_partition->name() << ": "
                           << cow_path;
                           << cow_path;
                return AddRequiredSpace(ret, all_snapshot_status);
                return AddRequiredSpace(ret, all_snapshot_status);
            }
            }
        }
        // Let destructor of created_devices_for_cow to unmap the COW devices.
        // Let destructor of created_devices_for_cow to unmap the COW devices.
    };
    };
    return Return::Ok();
    return Return::Ok();
@@ -2700,7 +2907,7 @@ bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_na
    return UnmapPartitionWithSnapshot(lock.get(), target_partition_name);
    return UnmapPartitionWithSnapshot(lock.get(), target_partition_name);
}
}


bool SnapshotManager::UnmapAllPartitions() {
bool SnapshotManager::UnmapAllPartitionsInRecovery() {
    auto lock = LockExclusive();
    auto lock = LockExclusive();
    if (!lock) return false;
    if (!lock) return false;


@@ -2844,7 +3051,7 @@ bool SnapshotManager::HandleImminentDataWipe(const std::function<void()>& callba
    }
    }


    // Nothing should be depending on partitions now, so unmap them all.
    // Nothing should be depending on partitions now, so unmap them all.
    if (!UnmapAllPartitions()) {
    if (!UnmapAllPartitionsInRecovery()) {
        LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
        LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
    }
    }
    return true;
    return true;
@@ -2875,7 +3082,7 @@ bool SnapshotManager::FinishMergeInRecovery() {
    }
    }


    // Nothing should be depending on partitions now, so unmap them all.
    // Nothing should be depending on partitions now, so unmap them all.
    if (!UnmapAllPartitions()) {
    if (!UnmapAllPartitionsInRecovery()) {
        LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
        LOG(ERROR) << "Unable to unmap all partitions; fastboot may fail to flash.";
    }
    }
    return true;
    return true;
Loading