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

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

Merge "libsnapshot: Implement OpenSnapshotWriter for compressed snapshots."

parents 2d697d33 767f3f72
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@ cc_defaults {
        "liblog",
    ],
    static_libs: [
        "libbrotli",
        "libdm",
        "libfstab",
        "libsnapshot_cow",
@@ -109,6 +110,9 @@ cc_library_static {
    defaults: ["libsnapshot_defaults"],
    srcs: [":libsnapshot_sources"],
    recovery_available: true,
    cflags: [
        "-DLIBSNAPSHOT_NO_COW_WRITE",
    ],
    static_libs: [
        "libfs_mgr",
    ],
@@ -122,6 +126,9 @@ cc_library_static {
    ],
    srcs: [":libsnapshot_sources"],
    recovery_available: true,
    cflags: [
        "-DLIBSNAPSHOT_NO_COW_WRITE",
    ],
    static_libs: [
        "libfs_mgr",
    ],
@@ -244,6 +251,7 @@ cc_defaults {
    static_libs: [
        "android.hardware.boot@1.0",
        "android.hardware.boot@1.1",
        "libbrotli",
        "libfs_mgr",
        "libgsi",
        "libgmock",
@@ -276,9 +284,11 @@ cc_binary {
        "snapshotctl.cpp",
    ],
    static_libs: [
        "libbrotli",
        "libfstab",
        "libsnapshot",
        "libsnapshot_cow",
        "libz",
        "update_metadata-protos",
    ],
    shared_libs: [
@@ -332,6 +342,7 @@ cc_defaults {
    ],
    static_libs: [
        "libbase",
        "libbrotli",
        "libcrypto_static",
        "libcutils",
        "libext2_uuid",
@@ -345,6 +356,7 @@ cc_defaults {
        "libsnapshot_cow",
        "libsnapshot_test_helpers",
        "libprotobuf-mutator",
        "libz",
    ],
    header_libs: [
        "libchrome",
+5 −2
Original line number Diff line number Diff line
@@ -532,8 +532,8 @@ class SnapshotManager final : public ISnapshotManager {
        // Target/base device (eg system_b), always present.
        std::string target_device;

        // COW path (eg system_cow). Not present if no COW is needed.
        std::string cow_device;
        // COW name (eg system_cow). Not present if no COW is needed.
        std::string cow_device_name;

        // dm-snapshot instance. Not present in Update mode for VABC.
        std::string snapshot_device;
@@ -626,6 +626,9 @@ class SnapshotManager final : public ISnapshotManager {
    bool GetMappedImageDeviceStringOrPath(const std::string& device_name,
                                          std::string* device_string_or_mapped_path);

    // Same as above, but for paths only (no major:minor device strings).
    bool GetMappedImageDevicePath(const std::string& device_name, std::string* device_path);

    std::string gsid_dir_;
    std::string metadata_dir_;
    std::unique_ptr<IDeviceInfo> device_;
+24 −1
Original line number Diff line number Diff line
@@ -42,6 +42,29 @@ class ISnapshotWriter : public ICowWriter {
    android::base::unique_fd source_fd_;
};

// Send writes to a COW or a raw device directly, based on a threshold.
class CompressedSnapshotWriter : public ISnapshotWriter {
  public:
    CompressedSnapshotWriter(const CowOptions& options);

    // Sets the COW device, if needed.
    bool SetCowDevice(android::base::unique_fd&& cow_device);

    bool Flush() override;
    uint64_t GetCowSize() override;
    std::unique_ptr<FileDescriptor> OpenReader() override;

  protected:
    bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
    bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
    bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;

  private:
    android::base::unique_fd cow_device_;

    std::unique_ptr<CowWriter> cow_;
};

// Write directly to a dm-snapshot device.
class OnlineKernelSnapshotWriter : public ISnapshotWriter {
  public:
@@ -52,7 +75,7 @@ class OnlineKernelSnapshotWriter : public ISnapshotWriter {

    bool Flush() override;
    uint64_t GetCowSize() override { return cow_size_; }
    virtual std::unique_ptr<FileDescriptor> OpenReader() override;
    std::unique_ptr<FileDescriptor> OpenReader() override;

  protected:
    bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
+67 −6
Original line number Diff line number Diff line
@@ -271,7 +271,7 @@ bool SnapshotManager::FinishedSnapshotWrites(bool wipe) {
        return false;
    }

    if (!EnsureNoOverflowSnapshot(lock.get())) {
    if (!IsCompressionEnabled() && !EnsureNoOverflowSnapshot(lock.get())) {
        LOG(ERROR) << "Cannot ensure there are no overflow snapshots.";
        return false;
    }
@@ -1716,7 +1716,7 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,
        return false;
    }
    if (paths) {
        paths->cow_device = cow_device;
        paths->cow_device_name = cow_name;
    }

    remaining_time = GetRemainingTime(params.timeout_ms, begin);
@@ -1724,6 +1724,7 @@ bool SnapshotManager::MapPartitionWithSnapshot(LockedFile* lock,

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

@@ -2471,6 +2472,12 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para

std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
        const android::fs_mgr::CreateLogicalPartitionParams& params) {
#if defined(LIBSNAPSHOT_NO_COW_WRITE)
    (void)params;

    LOG(ERROR) << "Snapshots cannot be written in first-stage init or recovery";
    return nullptr;
#else
    // First unmap any existing mapping.
    auto lock = LockShared();
    if (!lock) return nullptr;
@@ -2486,7 +2493,7 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
    }

    SnapshotStatus status;
    if (!paths.cow_device.empty()) {
    if (!paths.cow_device_name.empty()) {
        if (!ReadSnapshotStatus(lock.get(), params.GetPartitionName(), &status)) {
            return nullptr;
        }
@@ -2504,14 +2511,51 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
        return OpenCompressedSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
    }
    return OpenKernelSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
#endif
}

#if !defined(LIBSNAPSHOT_NO_COW_WRITE)
std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
        LockedFile*, const std::string&, const SnapshotStatus&, const SnapshotPaths&) {
    LOG(ERROR) << "OpenSnapshotWriter not yet implemented for compression";
        LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
        const SnapshotStatus& status, const SnapshotPaths& paths) {
    CHECK(lock);

    CowOptions cow_options;
    cow_options.compression = "gz";
    cow_options.max_blocks = {status.device_size() / cow_options.block_size};

    // Currently we don't support partial snapshots, since partition_cow_creator
    // never creates this scenario.
    CHECK(status.snapshot_size() == status.device_size());

    auto writer = std::make_unique<CompressedSnapshotWriter>(cow_options);

    unique_fd base_fd(open(paths.target_device.c_str(), O_RDWR | O_CLOEXEC));
    if (base_fd < 0) {
        PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << paths.target_device;
        return nullptr;
    }
    writer->SetSourceDevice(std::move(base_fd));

    std::string cow_path;
    if (!GetMappedImageDevicePath(paths.cow_device_name, &cow_path)) {
        LOG(ERROR) << "Could not determine path for " << paths.cow_device_name;
        return nullptr;
    }

    unique_fd cow_fd(open(cow_path.c_str(), O_RDWR | O_CLOEXEC));
    if (cow_fd < 0) {
        PLOG(ERROR) << "OpenCompressedSnapshotWriter: open " << cow_path;
        return nullptr;
    }
    if (!writer->SetCowDevice(std::move(cow_fd))) {
        LOG(ERROR) << "Could not create COW writer from " << cow_path;
        return nullptr;
    }

    return writer;
}

std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
        LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
        const SnapshotStatus& status, const SnapshotPaths& paths) {
@@ -2534,6 +2578,7 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(

    return writer;
}
#endif  // !defined(LIBSNAPSHOT_NO_COW_WRITE)

bool SnapshotManager::UnmapUpdateSnapshot(const std::string& target_partition_name) {
    auto lock = LockShared();
@@ -2872,6 +2917,22 @@ ISnapshotMergeStats* SnapshotManager::GetSnapshotMergeStatsInstance() {
    return SnapshotMergeStats::GetInstance(*this);
}

// This is only to be used in recovery or normal Android (not first-stage init).
// We don't guarantee dm paths are available in first-stage init, because ueventd
// isn't running yet.
bool SnapshotManager::GetMappedImageDevicePath(const std::string& device_name,
                                               std::string* device_path) {
    auto& dm = DeviceMapper::Instance();

    // Try getting the device string if it is a device mapper device.
    if (dm.GetState(device_name) != DmDeviceState::INVALID) {
        return dm.GetDmDevicePathByName(device_name, device_path);
    }

    // Otherwise, get path from IImageManager.
    return images_->GetMappedImageDevice(device_name, device_path);
}

bool SnapshotManager::GetMappedImageDeviceStringOrPath(const std::string& device_name,
                                                       std::string* device_string_or_mapped_path) {
    auto& dm = DeviceMapper::Instance();
+34 −0
Original line number Diff line number Diff line
@@ -33,6 +33,40 @@ void ISnapshotWriter::SetSourceDevice(android::base::unique_fd&& source_fd) {
    source_fd_ = std::move(source_fd);
}

CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options)
    : ISnapshotWriter(options) {}

bool CompressedSnapshotWriter::SetCowDevice(android::base::unique_fd&& cow_device) {
    cow_device_ = std::move(cow_device);
    cow_ = std::make_unique<CowWriter>(options_);

    return cow_->Initialize(cow_device_);
}
bool CompressedSnapshotWriter::Flush() {
    return cow_->Flush();
}

uint64_t CompressedSnapshotWriter::GetCowSize() {
    return cow_->GetCowSize();
}

std::unique_ptr<FileDescriptor> CompressedSnapshotWriter::OpenReader() {
    return nullptr;
}

bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
    return cow_->AddCopy(new_block, old_block);
}

bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
                                             size_t size) {
    return cow_->AddRawBlocks(new_block_start, data, size);
}

bool CompressedSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
    return cow_->AddZeroBlocks(new_block_start, num_blocks);
}

OnlineKernelSnapshotWriter::OnlineKernelSnapshotWriter(const CowOptions& options)
    : ISnapshotWriter(options) {}