Skip to content

Commit

Permalink
libsnapshot: Partially implement OpenSnapshotWriter.
Browse files Browse the repository at this point in the history
Implement OpenSnapshotWriter for non-compressed Virtual A/B. This is
done by adding an OnlineKernelSnapshotWriter class, which forwards all
writes to a dm-snapshot block device.

This also introduces a new ISnapshotWriter class which extends
ICowWriter, and adds features specific to libsnapshot (versus ICowWriter
which is intended only for the new COW format). The OpenSnapshotReader
call has been moved here since the writer retains all the information
needed to create the reader.

To test the new call, vts_libsnapshot_test has been modified to use
OpenSnapshotWriter.

As part of this change, all consumers of libsnapshot must now link to
libsnapshot_cow.

Bug: 168554689
Test: vts_libsnapshot_test
Change-Id: Ieedfadc557833c1e0540922aabc6e95c80266a64
  • Loading branch information
dvandercorp committed Sep 28, 2020
1 parent 6560d23 commit 75b982a
Show file tree
Hide file tree
Showing 16 changed files with 385 additions and 82 deletions.
1 change: 1 addition & 0 deletions fastboot/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ cc_binary {
static_libs: [
"libgtest_prod",
"libhealthhalutils",
"libsnapshot_cow",
"libsnapshot_nobinder",
"update_metadata-protos",
],
Expand Down
4 changes: 4 additions & 0 deletions fs_mgr/libsnapshot/Android.bp
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ filegroup {
"snapshot_stats.cpp",
"snapshot_stub.cpp",
"snapshot_metadata_updater.cpp",
"snapshot_writer.cpp",
"partition_cow_creator.cpp",
"return.cpp",
"utility.cpp",
Expand Down Expand Up @@ -215,6 +216,7 @@ cc_defaults {
"libgmock",
"liblp",
"libsnapshot",
"libsnapshot_cow",
"libsnapshot_test_helpers",
"libsparse",
],
Expand Down Expand Up @@ -249,6 +251,7 @@ cc_binary {
static_libs: [
"libfstab",
"libsnapshot",
"libsnapshot_cow",
"update_metadata-protos",
],
shared_libs: [
Expand Down Expand Up @@ -312,6 +315,7 @@ cc_defaults {
"libgmock", // from libsnapshot_test_helpers
"liblog",
"liblp",
"libsnapshot_cow",
"libsnapshot_test_helpers",
"libprotobuf-mutator",
],
Expand Down
9 changes: 6 additions & 3 deletions fs_mgr/libsnapshot/cow_writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ namespace snapshot {

static_assert(sizeof(off_t) == sizeof(uint64_t));

using android::base::borrowed_fd;
using android::base::unique_fd;

bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block) {
if (!ValidateNewBlock(new_block)) {
return false;
Expand Down Expand Up @@ -98,12 +101,12 @@ bool CowWriter::ParseOptions() {
return true;
}

bool CowWriter::Initialize(android::base::unique_fd&& fd, OpenMode mode) {
bool CowWriter::Initialize(unique_fd&& fd, OpenMode mode) {
owned_fd_ = std::move(fd);
return Initialize(android::base::borrowed_fd{owned_fd_}, mode);
return Initialize(borrowed_fd{owned_fd_}, mode);
}

bool CowWriter::Initialize(android::base::borrowed_fd fd, OpenMode mode) {
bool CowWriter::Initialize(borrowed_fd fd, OpenMode mode) {
fd_ = fd;

if (!ParseOptions()) {
Expand Down
3 changes: 3 additions & 0 deletions fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ class ICowWriter {
// Return number of bytes the cow image occupies on disk.
virtual uint64_t GetCowSize() = 0;

// Returns true if AddCopy() operations are supported.
virtual bool SupportsCopyOperation() const { return true; }

const CowOptions& options() { return options_; }

protected:
Expand Down
4 changes: 1 addition & 3 deletions fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,7 @@ class MockSnapshotManager : public ISnapshotManager {
(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path),
(override));
MOCK_METHOD(std::unique_ptr<ICowWriter>, OpenSnapshotWriter,
(const android::fs_mgr::CreateLogicalPartitionParams& params), (override));
MOCK_METHOD(std::unique_ptr<FileDescriptor>, OpenSnapshotReader,
MOCK_METHOD(std::unique_ptr<ISnapshotWriter>, OpenSnapshotWriter,
(const android::fs_mgr::CreateLogicalPartitionParams& params), (override));
MOCK_METHOD(bool, UnmapUpdateSnapshot, (const std::string& target_partition_name), (override));
MOCK_METHOD(bool, NeedSnapshotsInFirstStageMount, (), (override));
Expand Down
59 changes: 38 additions & 21 deletions fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,15 @@
#include <update_engine/update_metadata.pb.h>

#include <libsnapshot/auto_device.h>
#include <libsnapshot/cow_writer.h>
#include <libsnapshot/return.h>
#include <libsnapshot/snapshot_writer.h>

#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
friend class test_set_name##_##individual_test##_Test
#define DEFINED_FRIEND_TEST
#endif

namespace chromeos_update_engine {
class FileDescriptor;
} // namespace chromeos_update_engine

namespace android {

namespace fiemap {
Expand Down Expand Up @@ -110,8 +106,6 @@ class ISnapshotManager {
};
virtual ~ISnapshotManager() = default;

using FileDescriptor = chromeos_update_engine::FileDescriptor;

// Begin an update. This must be called before creating any snapshots. It
// will fail if GetUpdateState() != None.
virtual bool BeginUpdate() = 0;
Expand Down Expand Up @@ -187,19 +181,14 @@ class ISnapshotManager {
virtual bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path) = 0;

// Create an ICowWriter to build a snapshot against a target partition. The partition name must
// be suffixed.
virtual std::unique_ptr<ICowWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;

// Open a snapshot for reading. A file-like interface is provided through the FileDescriptor.
// In this mode, writes are not supported. The partition name must be suffixed.
virtual std::unique_ptr<FileDescriptor> OpenSnapshotReader(
// Create an ISnapshotWriter to build a snapshot against a target partition. The partition name
// must be suffixed.
virtual std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) = 0;

// Unmap a snapshot device or CowWriter that was previously opened with MapUpdateSnapshot,
// OpenSnapshotWriter, or OpenSnapshotReader. All outstanding open descriptors, writers,
// or readers must be deleted before this is called.
// OpenSnapshotWriter. All outstanding open descriptors, writers, or
// readers must be deleted before this is called.
virtual bool UnmapUpdateSnapshot(const std::string& target_partition_name) = 0;

// If this returns true, first-stage mount must call
Expand Down Expand Up @@ -310,9 +299,7 @@ class SnapshotManager final : public ISnapshotManager {
Return CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const CreateLogicalPartitionParams& params,
std::string* snapshot_path) override;
std::unique_ptr<ICowWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) override;
std::unique_ptr<FileDescriptor> OpenSnapshotReader(
std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;
Expand Down Expand Up @@ -532,9 +519,39 @@ class SnapshotManager final : public ISnapshotManager {
std::string GetSnapshotDeviceName(const std::string& snapshot_name,
const SnapshotStatus& status);

// Reason for calling MapPartitionWithSnapshot.
enum class SnapshotContext {
// For writing or verification (during update_engine).
Update,

// For mounting a full readable device.
Mount,
};

struct SnapshotPaths {
// 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;

// dm-snapshot instance. Not present in Update mode for VABC.
std::string snapshot_device;
};

// Helpers for OpenSnapshotWriter.
std::unique_ptr<ISnapshotWriter> OpenCompressedSnapshotWriter(LockedFile* lock,
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,
const SnapshotPaths& paths);

// Map the base device, COW devices, and snapshot device.
bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,
std::string* path);
SnapshotContext context, SnapshotPaths* paths);

// Map the COW devices, including the partition in super and the images.
// |params|:
Expand Down
4 changes: 1 addition & 3 deletions fs_mgr/libsnapshot/include/libsnapshot/snapshot_stub.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ class SnapshotManagerStub : public ISnapshotManager {
const chromeos_update_engine::DeltaArchiveManifest& manifest) override;
bool MapUpdateSnapshot(const android::fs_mgr::CreateLogicalPartitionParams& params,
std::string* snapshot_path) override;
std::unique_ptr<ICowWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) override;
std::unique_ptr<FileDescriptor> OpenSnapshotReader(
std::unique_ptr<ISnapshotWriter> OpenSnapshotWriter(
const android::fs_mgr::CreateLogicalPartitionParams& params) override;
bool UnmapUpdateSnapshot(const std::string& target_partition_name) override;
bool NeedSnapshotsInFirstStageMount() override;
Expand Down
68 changes: 68 additions & 0 deletions fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <android-base/unique_fd.h>

#include <libsnapshot/cow_writer.h>

namespace chromeos_update_engine {
class FileDescriptor;
} // namespace chromeos_update_engine

namespace android {
namespace snapshot {

class ISnapshotWriter : public ICowWriter {
public:
using FileDescriptor = chromeos_update_engine::FileDescriptor;

explicit ISnapshotWriter(const CowOptions& options);

// 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);

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

protected:
android::base::unique_fd source_fd_;
};

// Write directly to a dm-snapshot device.
class OnlineKernelSnapshotWriter : public ISnapshotWriter {
public:
OnlineKernelSnapshotWriter(const CowOptions& options);

// Set the device used for all writes.
void SetSnapshotDevice(android::base::unique_fd&& snapshot_fd, uint64_t cow_size);

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

protected:
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;
bool EmitCopy(uint64_t new_block, uint64_t old_block) override;

private:
android::base::unique_fd snapshot_fd_;
uint64_t cow_size_ = 0;
};

} // namespace snapshot
} // namespace android
1 change: 1 addition & 0 deletions fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,7 @@ void DeleteBackingImage(android::fiemap::IImageManager* manager, const std::stri
// Expect space of |path| is multiple of 4K.
bool WriteRandomData(const std::string& path, std::optional<size_t> expect_size = std::nullopt,
std::string* hash = nullptr);
bool WriteRandomData(ICowWriter* writer, std::string* hash = nullptr);

std::optional<std::string> GetHash(const std::string& path);

Expand Down
Loading

0 comments on commit 75b982a

Please sign in to comment.