Loading fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +1 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ class CowReader final : public ICowReader { size_t ignore_bytes = 0) override; CowHeader& GetHeader() override { return header_; } const CowHeaderV3& header_v3() const { return header_; } bool GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read); bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read); Loading fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +3 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,9 @@ struct CowOptions { // Batch write cluster ops bool batch_write = false; // Size of the cow operation buffer; used in v3 only. uint32_t op_count_max = 0; }; // Interface for writing to a snapuserd COW. All operations are ordered; merges Loading fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -89,5 +89,36 @@ TEST_F(CowTestV3, Header) { ASSERT_EQ(header.cluster_ops, 0); } TEST_F(CowTestV3, ZeroOp) { CowOptions options; options.op_count_max = 20; auto writer = CreateCowWriter(3, options, GetCowFd()); ASSERT_TRUE(writer->AddZeroBlocks(1, 2)); ASSERT_TRUE(writer->Finalize()); CowReader reader; ASSERT_TRUE(reader.Parse(cow_->fd)); ASSERT_EQ(reader.header_v3().op_count, 2); auto iter = reader.GetOpIter(); ASSERT_NE(iter, nullptr); ASSERT_FALSE(iter->AtEnd()); auto op = iter->Get(); ASSERT_EQ(op->type, kCowZeroOp); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 1); ASSERT_EQ(op->source_info, 0); iter->Next(); ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowZeroOp); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 2); ASSERT_EQ(op->source_info, 0); } } // namespace snapshot } // namespace android fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,8 @@ class CowWriterBase : public ICowWriter { bool InitFd(); bool ValidateNewBlock(uint64_t new_block); bool IsEstimating() const { return is_dev_null_; } CowOptions options_; android::base::unique_fd fd_; Loading fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp +38 −3 Original line number Diff line number Diff line Loading @@ -155,6 +155,7 @@ bool CowWriterV3::OpenForWrite() { return false; } } header_.op_count_max = options_.op_count_max; if (!Sync()) { LOG(ERROR) << "Header sync failed"; Loading Loading @@ -184,10 +185,18 @@ bool CowWriterV3::EmitXorBlocks(uint32_t new_block_start, const void* data, size } bool CowWriterV3::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; if (new_block_start && num_blocks) return false; for (uint64_t i = 0; i < num_blocks; i++) { CowOperationV3 op; op.type = kCowZeroOp; op.data_length = 0; op.new_block = new_block_start + i; op.source_info = 0; if (!WriteOperation(op)) { return false; } } return true; } bool CowWriterV3::EmitLabel(uint64_t label) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; Loading @@ -201,7 +210,33 @@ bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) { return false; } bool CowWriterV3::WriteOperation(const CowOperationV3& op) { if (IsEstimating()) { header_.op_count++; header_.op_count_max++; return true; } if (header_.op_count + 1 > header_.op_count_max) { LOG(ERROR) << "Maximum number of ops reached: " << header_.op_count_max; return false; } const off_t offset = GetOpOffset(header_.op_count); if (!android::base::WriteFullyAtOffset(fd_, &op, sizeof(op), offset)) { return false; } header_.op_count++; return true; } bool CowWriterV3::Finalize() { CHECK_GE(header_.prefix.header_size, sizeof(CowHeaderV3)); CHECK_LE(header_.prefix.header_size, sizeof(header_)); if (!android::base::WriteFullyAtOffset(fd_, &header_, header_.prefix.header_size, 0)) { return false; } return Sync(); } Loading Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +1 −0 Original line number Diff line number Diff line Loading @@ -145,6 +145,7 @@ class CowReader final : public ICowReader { size_t ignore_bytes = 0) override; CowHeader& GetHeader() override { return header_; } const CowHeaderV3& header_v3() const { return header_; } bool GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read); bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read); Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +3 −0 Original line number Diff line number Diff line Loading @@ -54,6 +54,9 @@ struct CowOptions { // Batch write cluster ops bool batch_write = false; // Size of the cow operation buffer; used in v3 only. uint32_t op_count_max = 0; }; // Interface for writing to a snapuserd COW. All operations are ordered; merges Loading
fs_mgr/libsnapshot/libsnapshot_cow/test_v3.cpp +31 −0 Original line number Diff line number Diff line Loading @@ -89,5 +89,36 @@ TEST_F(CowTestV3, Header) { ASSERT_EQ(header.cluster_ops, 0); } TEST_F(CowTestV3, ZeroOp) { CowOptions options; options.op_count_max = 20; auto writer = CreateCowWriter(3, options, GetCowFd()); ASSERT_TRUE(writer->AddZeroBlocks(1, 2)); ASSERT_TRUE(writer->Finalize()); CowReader reader; ASSERT_TRUE(reader.Parse(cow_->fd)); ASSERT_EQ(reader.header_v3().op_count, 2); auto iter = reader.GetOpIter(); ASSERT_NE(iter, nullptr); ASSERT_FALSE(iter->AtEnd()); auto op = iter->Get(); ASSERT_EQ(op->type, kCowZeroOp); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 1); ASSERT_EQ(op->source_info, 0); iter->Next(); ASSERT_FALSE(iter->AtEnd()); op = iter->Get(); ASSERT_EQ(op->type, kCowZeroOp); ASSERT_EQ(op->data_length, 0); ASSERT_EQ(op->new_block, 2); ASSERT_EQ(op->source_info, 0); } } // namespace snapshot } // namespace android
fs_mgr/libsnapshot/libsnapshot_cow/writer_base.h +2 −0 Original line number Diff line number Diff line Loading @@ -62,6 +62,8 @@ class CowWriterBase : public ICowWriter { bool InitFd(); bool ValidateNewBlock(uint64_t new_block); bool IsEstimating() const { return is_dev_null_; } CowOptions options_; android::base::unique_fd fd_; Loading
fs_mgr/libsnapshot/libsnapshot_cow/writer_v3.cpp +38 −3 Original line number Diff line number Diff line Loading @@ -155,6 +155,7 @@ bool CowWriterV3::OpenForWrite() { return false; } } header_.op_count_max = options_.op_count_max; if (!Sync()) { LOG(ERROR) << "Header sync failed"; Loading Loading @@ -184,10 +185,18 @@ bool CowWriterV3::EmitXorBlocks(uint32_t new_block_start, const void* data, size } bool CowWriterV3::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; if (new_block_start && num_blocks) return false; for (uint64_t i = 0; i < num_blocks; i++) { CowOperationV3 op; op.type = kCowZeroOp; op.data_length = 0; op.new_block = new_block_start + i; op.source_info = 0; if (!WriteOperation(op)) { return false; } } return true; } bool CowWriterV3::EmitLabel(uint64_t label) { LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called"; Loading @@ -201,7 +210,33 @@ bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) { return false; } bool CowWriterV3::WriteOperation(const CowOperationV3& op) { if (IsEstimating()) { header_.op_count++; header_.op_count_max++; return true; } if (header_.op_count + 1 > header_.op_count_max) { LOG(ERROR) << "Maximum number of ops reached: " << header_.op_count_max; return false; } const off_t offset = GetOpOffset(header_.op_count); if (!android::base::WriteFullyAtOffset(fd_, &op, sizeof(op), offset)) { return false; } header_.op_count++; return true; } bool CowWriterV3::Finalize() { CHECK_GE(header_.prefix.header_size, sizeof(CowHeaderV3)); CHECK_LE(header_.prefix.header_size, sizeof(header_)); if (!android::base::WriteFullyAtOffset(fd_, &header_, header_.prefix.header_size, 0)) { return false; } return Sync(); } Loading