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

Commit 3feb3237 authored by David Anderson's avatar David Anderson
Browse files

libsnapshot: Add a source_partition parameter to OpenSnapshotWriter.

Reading from the base device is incorrect, because if the partition
shrinks, we may still have copy operations from the removed area in the
original partition. Ask the caller to explicitly name the source device
for AddCopy() operations.

Bug: 168554689
Test: vts_libsnapshot_test
Test: full OTA with update_device.py
Test: incremental OTA with update_device.py
Change-Id: If388e37c2a2f9288a43d2849312c921bf59d4918
parent 767f3f72
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -39,7 +39,9 @@ class MockSnapshotManager : public ISnapshotManager {
                 std::string* snapshot_path),
                (override));
    MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
                (const android::fs_mgr::CreateLogicalPartitionParams& params), (override));
                (const android::fs_mgr::CreateLogicalPartitionParams& params,
                 const std::optional<std::string>&),
                (override));
    MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
    MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
    MOCK_METHOD(bool, CreateLogicalAndSnapshotPartitions,
+15 −11
Original line number Diff line number Diff line
@@ -182,9 +182,12 @@ class ISnapshotManager {
                                   std::string* snapshot_path) = 0;

    // Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
    // must be suffixed.
    // must be suffixed. If a source partition exists, it must be specified as well. The source
    // partition will only be used if raw bytes are needed. The source partition should be an
    // absolute path to the device, not a partition name.
    virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
            const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;
            const android::fs_mgr::CreateLogicalPartitionParams& params,
            const std::optional<std::string>& source_device) = 0;

    // Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
    // OpenSnapshotWriter. All outstanding open descriptors, writers, or
@@ -300,7 +303,8 @@ class SnapshotManager final : public ISnapshotManager {
    bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
                           std::string* snapshot_path) override;
    std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
            const android::fs_mgr::CreateLogicalPartitionParams& params) override;
            const android::fs_mgr::CreateLogicalPartitionParams& params,
            const std::optional<std::string>& source_device) override;
    bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
    bool NeedSnapshotsInFirstStageMount() override;
    bool CreateLogicalAndSnapshotPartitions(
@@ -540,13 +544,13 @@ class SnapshotManager final : public ISnapshotManager {
    };

    // Helpers for OpenSnapshotWriter.
    std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
                                                                  const std::string& partition_name,
                                                                  const SnapshotStatus& status,
    std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(
            LockedFile* lock, const std::optional<std::string>& source_device,
            const std::string& partition_name, const SnapshotStatus& status,
            const SnapshotPaths& paths);
    std::unique_ptr<ISnapshotWriter> OpenKernelSnapshotWriter(LockedFile* lock,
                                                              const std::string& partition_name,
                                                              const SnapshotStatus& status,
    std::unique_ptr<ISnapshotWriter> OpenKernelSnapshotWriter(
            LockedFile* lock, const std::optional<std::string>& source_device,
            const std::string& partition_name, const SnapshotStatus& status,
            const SnapshotPaths& paths);

    // Map the base device, COW devices, and snapshot device.
+2 −1
Original line number Diff line number Diff line
@@ -37,7 +37,8 @@ class SnapshotManagerStub : public ISnapshotManager {
    bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
                           std::string* snapshot_path) override;
    std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
            const android::fs_mgr::CreateLogicalPartitionParams& params) override;
            const android::fs_mgr::CreateLogicalPartitionParams& params,
            const std::optional<std::string>& source_device) override;
    bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
    bool NeedSnapshotsInFirstStageMount() override;
    bool CreateLogicalAndSnapshotPartitions(
+7 −2
Original line number Diff line number Diff line
@@ -33,13 +33,18 @@ class ISnapshotWriter : public ICowWriter {

    // Set the source device. This is used for AddCopy() operations, if the
    // underlying writer needs the original bytes (for example if backed by
    // dm-snapshot or if writing directly to an unsnapshotted region).
    void SetSourceDevice(android::base::unique_fd&& source_fd);
    // dm-snapshot or if writing directly to an unsnapshotted region). The
    // device is only opened on the first operation that requires it.
    void SetSourceDevice(const std::string& source_device);

    virtual std::unique_ptr<FileDescriptor> OpenReader() = 0;

  protected:
    android::base::borrowed_fd GetSourceFd();

  private:
    android::base::unique_fd source_fd_;
    std::optional<std::string> source_device_;
};

// Send writes to a COW or a raw device directly, based on a threshold.
+19 −13
Original line number Diff line number Diff line
@@ -2471,9 +2471,11 @@ bool SnapshotManager::MapUpdateSnapshot(const CreateLogicalPartitionParams& para
}

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

    LOG(ERROR) << "Snapshots cannot be written in first-stage init or recovery";
    return nullptr;
@@ -2508,16 +2510,19 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenSnapshotWriter(
    }

    if (IsCompressionEnabled()) {
        return OpenCompressedSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
        return OpenCompressedSnapshotWriter(lock.get(), source_device, params.GetPartitionName(),
                                            status, paths);
    }
    return OpenKernelSnapshotWriter(lock.get(), params.GetPartitionName(), status, paths);
    return OpenKernelSnapshotWriter(lock.get(), source_device, params.GetPartitionName(), status,
                                    paths);
#endif
}

#if !defined(LIBSNAPSHOT_NO_COW_WRITE)
std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
        LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
        const SnapshotStatus& status, const SnapshotPaths& paths) {
        LockedFile* lock, const std::optional<std::string>& source_device,
        [[maybe_unused]] const std::string& partition_name, const SnapshotStatus& status,
        const SnapshotPaths& paths) {
    CHECK(lock);

    CowOptions cow_options;
@@ -2529,13 +2534,9 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
    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;
    if (source_device) {
        writer->SetSourceDevice(*source_device);
    }
    writer->SetSourceDevice(std::move(base_fd));

    std::string cow_path;
    if (!GetMappedImageDevicePath(paths.cow_device_name, &cow_path)) {
@@ -2557,8 +2558,9 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenCompressedSnapshotWriter(
}

std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
        LockedFile* lock, [[maybe_unused]] const std::string& partition_name,
        const SnapshotStatus& status, const SnapshotPaths& paths) {
        LockedFile* lock, const std::optional<std::string>& source_device,
        [[maybe_unused]] const std::string& partition_name, const SnapshotStatus& status,
        const SnapshotPaths& paths) {
    CHECK(lock);

    CowOptions cow_options;
@@ -2573,6 +2575,10 @@ std::unique_ptr<ISnapshotWriter> SnapshotManager::OpenKernelSnapshotWriter(
        return nullptr;
    }

    if (source_device) {
        writer->SetSourceDevice(*source_device);
    }

    uint64_t cow_size = status.cow_partition_size() + status.cow_file_size();
    writer->SetSnapshotDevice(std::move(fd), cow_size);

Loading