Merge "libsnapshot: Changes to AddCopy() API"
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
index e7a2f02..19f3649 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h
@@ -52,8 +52,9 @@
virtual ~ICowWriter() {}
// Encode an operation that copies the contents of |old_block| to the
- // location of |new_block|.
- bool AddCopy(uint64_t new_block, uint64_t old_block);
+ // location of |new_block|. 'num_blocks' is the number of contiguous
+ // COPY operations from |old_block| to |new_block|.
+ bool AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1);
// Encode a sequence of raw blocks. |size| must be a multiple of the block size.
bool AddRawBlocks(uint64_t new_block_start, const void* data, size_t size);
@@ -84,7 +85,7 @@
const CowOptions& options() { return options_; }
protected:
- virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) = 0;
+ virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) = 0;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) = 0;
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
uint32_t old_block, uint16_t offset) = 0;
@@ -122,7 +123,7 @@
uint32_t GetCowVersion() { return header_.major_version; }
protected:
- virtual bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+ virtual bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
virtual bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
virtual bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size,
uint32_t old_block, uint16_t offset) override;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
index b0be5a5..29828bc 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/mock_snapshot_writer.h
@@ -34,7 +34,7 @@
// Returns true if AddCopy() operations are supported.
MOCK_METHOD(bool, SupportsCopyOperation, (), (const override));
- MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t), (override));
+ MOCK_METHOD(bool, EmitCopy, (uint64_t, uint64_t, uint64_t), (override));
MOCK_METHOD(bool, EmitRawBlocks, (uint64_t, const void*, size_t), (override));
MOCK_METHOD(bool, EmitXorBlocks, (uint32_t, const void*, size_t, uint32_t, uint16_t),
(override));
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
index 545f117..0e3b1db 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot_writer.h
@@ -74,7 +74,7 @@
bool VerifyMergeOps() const noexcept;
protected:
- bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+ bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
bool EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) override;
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
uint16_t offset) override;
@@ -113,7 +113,7 @@
bool EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) override;
bool EmitXorBlocks(uint32_t new_block_start, const void* data, size_t size, uint32_t old_block,
uint16_t offset) override;
- bool EmitCopy(uint64_t new_block, uint64_t old_block) override;
+ bool EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks = 1) override;
bool EmitLabel(uint64_t label) override;
bool EmitSequenceData(size_t num_ops, const uint32_t* data) override;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp
index ba4044f..2c1187f 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_api_test.cpp
@@ -62,6 +62,48 @@
std::string stream_;
};
+TEST_F(CowTest, CopyContiguous) {
+ CowOptions options;
+ options.cluster_ops = 0;
+ CowWriter writer(options);
+
+ ASSERT_TRUE(writer.Initialize(cow_->fd));
+
+ ASSERT_TRUE(writer.AddCopy(10, 1000, 100));
+ ASSERT_TRUE(writer.Finalize());
+ ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
+
+ CowReader reader;
+ CowHeader header;
+ CowFooter footer;
+ ASSERT_TRUE(reader.Parse(cow_->fd));
+ ASSERT_TRUE(reader.GetHeader(&header));
+ ASSERT_TRUE(reader.GetFooter(&footer));
+ ASSERT_EQ(header.magic, kCowMagicNumber);
+ ASSERT_EQ(header.major_version, kCowVersionMajor);
+ ASSERT_EQ(header.minor_version, kCowVersionMinor);
+ ASSERT_EQ(header.block_size, options.block_size);
+ ASSERT_EQ(footer.op.num_ops, 100);
+
+ auto iter = reader.GetOpIter();
+ ASSERT_NE(iter, nullptr);
+ ASSERT_FALSE(iter->Done());
+
+ size_t i = 0;
+ while (!iter->Done()) {
+ auto op = &iter->Get();
+ ASSERT_EQ(op->type, kCowCopyOp);
+ ASSERT_EQ(op->compression, kCowCompressNone);
+ ASSERT_EQ(op->data_length, 0);
+ ASSERT_EQ(op->new_block, 10 + i);
+ ASSERT_EQ(op->source, 1000 + i);
+ iter->Next();
+ i += 1;
+ }
+
+ ASSERT_EQ(i, 100);
+}
+
TEST_F(CowTest, ReadWrite) {
CowOptions options;
options.cluster_ops = 0;
diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
index e4f019e..015bff0 100644
--- a/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
+++ b/fs_mgr/libsnapshot/libsnapshot_cow/cow_writer.cpp
@@ -38,11 +38,16 @@
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;
+bool ICowWriter::AddCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
+ CHECK(num_blocks != 0);
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ if (!ValidateNewBlock(new_block + i)) {
+ return false;
+ }
}
- return EmitCopy(new_block, old_block);
+
+ return EmitCopy(new_block, old_block, num_blocks);
}
bool ICowWriter::AddRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
@@ -286,13 +291,20 @@
return EmitClusterIfNeeded();
}
-bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block, uint64_t num_blocks) {
CHECK(!merge_in_progress_);
- CowOperation op = {};
- op.type = kCowCopyOp;
- op.new_block = new_block;
- op.source = old_block;
- return WriteOperation(op);
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ CowOperation op = {};
+ op.type = kCowCopyOp;
+ op.new_block = new_block + i;
+ op.source = old_block + i;
+ if (!WriteOperation(op)) {
+ return false;
+ }
+ }
+
+ return true;
}
bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) {
diff --git a/fs_mgr/libsnapshot/snapshot_writer.cpp b/fs_mgr/libsnapshot/snapshot_writer.cpp
index 48b7d80..6aad3d1 100644
--- a/fs_mgr/libsnapshot/snapshot_writer.cpp
+++ b/fs_mgr/libsnapshot/snapshot_writer.cpp
@@ -111,8 +111,9 @@
return reader;
}
-bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
- return cow_->AddCopy(new_block, old_block);
+bool CompressedSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
+ uint64_t num_blocks) {
+ return cow_->AddCopy(new_block, old_block, num_blocks);
}
bool CompressedSnapshotWriter::EmitRawBlocks(uint64_t new_block_start, const void* data,
@@ -191,19 +192,29 @@
return true;
}
-bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block) {
+bool OnlineKernelSnapshotWriter::EmitCopy(uint64_t new_block, uint64_t old_block,
+ uint64_t num_blocks) {
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)) {
- PLOG(ERROR) << "EmitCopy read";
- return false;
+ CHECK(num_blocks != 0);
+
+ for (size_t i = 0; i < num_blocks; i++) {
+ std::string buffer(options_.block_size, 0);
+ uint64_t offset = (old_block + i) * options_.block_size;
+ if (!android::base::ReadFullyAtOffset(source_fd, buffer.data(), buffer.size(), offset)) {
+ PLOG(ERROR) << "EmitCopy read";
+ return false;
+ }
+ if (!EmitRawBlocks(new_block + i, buffer.data(), buffer.size())) {
+ PLOG(ERROR) << "EmitRawBlocks failed";
+ return false;
+ }
}
- return EmitRawBlocks(new_block, buffer.data(), buffer.size());
+
+ return true;
}
bool OnlineKernelSnapshotWriter::EmitLabel(uint64_t) {