Merge "libsnapshot: Add a source_partition parameter to OpenSnapshotWriter." am: 7d66a60012 am: ded0ee57a8

Original change: https://android-review.googlesource.com/c/platform/system/core/+/1441021

Change-Id: Ib00280286ec803beb6cffb3a60293ffb1d709f95
This commit is contained in:
David Anderson 2020-10-21 07:55:14 +00:00 committed by Automerger Merge Worker
commit a8e8d94e59
8 changed files with 73 additions and 33 deletions

View file

@ -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,

View file

@ -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,14 +544,14 @@ class SnapshotManager final : public ISnapshotManager {
};
// 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);
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::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.
bool MapPartitionWithSnapshot(LockedFile* lock, CreateLogicalPartitionParams params,

View file

@ -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(

View file

@ -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.

View file

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

View file

@ -131,7 +131,7 @@ ISnapshotMergeStats* SnapshotManagerStub::GetSnapshotMergeStatsInstance() {
}
std::unique_ptr<ISnapshotWriter> SnapshotManagerStub::OpenSnapshotWriter(
const CreateLogicalPartitionParams&) {
const CreateLogicalPartitionParams&, const std::optional<std::string>&) {
LOG(ERROR) << __FUNCTION__ << " should never be called.";
return nullptr;
}

View file

@ -903,7 +903,7 @@ class SnapshotUpdateTest : public SnapshotTest {
.partition_opener = opener_.get(),
};
auto result = sm->OpenSnapshotWriter(params);
auto result = sm->OpenSnapshotWriter(params, {});
if (!result) {
return AssertionFailure() << "Cannot open snapshot for writing: " << name;
}

View file

@ -24,13 +24,30 @@
namespace android {
namespace snapshot {
using android::base::borrowed_fd;
using android::base::unique_fd;
using chromeos_update_engine::FileDescriptor;
ISnapshotWriter::ISnapshotWriter(const CowOptions& options) : ICowWriter(options) {}
void ISnapshotWriter::SetSourceDevice(android::base::unique_fd&& source_fd) {
source_fd_ = std::move(source_fd);
void ISnapshotWriter::SetSourceDevice(const std::string& source_device) {
source_device_ = {source_device};
}
borrowed_fd ISnapshotWriter::GetSourceFd() {
if (!source_device_) {
LOG(ERROR) << "Attempted to read from source device but none was set";
return borrowed_fd{-1};
}
if (source_fd_ < 0) {
source_fd_.reset(open(source_device_->c_str(), O_RDONLY | O_CLOEXEC));
if (source_fd_ < 0) {
PLOG(ERROR) << "open " << *source_device_;
return borrowed_fd{-1};
}
}
return source_fd_;
}
CompressedSnapshotWriter::CompressedSnapshotWriter(const CowOptions& options)
@ -109,9 +126,14 @@ bool OnlineKernelSnapshotWriter::EmitZeroBlocks(uint64_t new_block_start, uint64
}
bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
auto source_fd = GetSourceFd();
if (source_fd < 0) {
return false;
}
std::string buffer(options_.block_size, 0);
uint64_t offset = old_block * options_.block_size;
if (!android::base::ReadFullyAtOffset(source_fd_, buffer.data(), buffer.size(), offset)) {
if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
PLOG(ERROR) << "EmitCopy read";
return false;
}