Loading fs_mgr/libsnapshot/cow_reader.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,26 @@ bool CowReader::ParseOps() { } else { LOG(INFO) << "No Footer, recovered data"; } if (header_.num_merge_ops > 0) { uint64_t merge_ops = header_.num_merge_ops; uint64_t metadata_ops = 0; current_op_num = 0; CHECK(ops_buffer->size() >= merge_ops); while (merge_ops) { auto& current_op = ops_buffer->data()[current_op_num]; if (current_op.type == kCowLabelOp || current_op.type == kCowFooterOp) { metadata_ops += 1; } else { merge_ops -= 1; } current_op_num += 1; } ops_buffer->erase(ops_buffer.get()->begin(), ops_buffer.get()->begin() + header_.num_merge_ops + metadata_ops); } ops_ = ops_buffer; return true; } Loading fs_mgr/libsnapshot/cow_writer.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ void CowWriter::SetupHeaders() { header_.header_size = sizeof(CowHeader); header_.footer_size = sizeof(CowFooter); header_.block_size = options_.block_size; header_.num_merge_ops = 0; footer_ = {}; footer_.op.data_length = 64; footer_.op.type = kCowFooterOp; Loading Loading @@ -125,6 +126,12 @@ bool CowWriter::SetFd(android::base::borrowed_fd fd) { return true; } void CowWriter::InitializeMerge(borrowed_fd fd, CowHeader* header) { fd_ = fd; memcpy(&header_, header, sizeof(CowHeader)); merge_in_progress_ = true; } bool CowWriter::Initialize(unique_fd&& fd) { owned_fd_ = std::move(fd); return Initialize(borrowed_fd{owned_fd_}); Loading Loading @@ -223,6 +230,7 @@ bool CowWriter::OpenForAppend(uint64_t label) { } bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) { CHECK(!merge_in_progress_); CowOperation op = {}; op.type = kCowCopyOp; op.new_block = new_block; Loading @@ -233,6 +241,7 @@ bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) { bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) { const uint8_t* iter = reinterpret_cast<const uint8_t*>(data); uint64_t pos; CHECK(!merge_in_progress_); for (size_t i = 0; i < size / header_.block_size; i++) { CowOperation op = {}; op.type = kCowReplaceOp; Loading Loading @@ -271,6 +280,7 @@ bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t } bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { CHECK(!merge_in_progress_); for (uint64_t i = 0; i < num_blocks; i++) { CowOperation op = {}; op.type = kCowZeroOp; Loading @@ -282,6 +292,7 @@ bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { } bool CowWriter::EmitLabel(uint64_t label) { CHECK(!merge_in_progress_); CowOperation op = {}; op.type = kCowLabelOp; op.source = label; Loading Loading @@ -416,5 +427,23 @@ bool CowWriter::Sync() { return true; } bool CowWriter::CommitMerge(int merged_ops) { CHECK(merge_in_progress_); header_.num_merge_ops += merged_ops; if (lseek(fd_.get(), 0, SEEK_SET) < 0) { PLOG(ERROR) << "lseek failed"; return false; } if (!android::base::WriteFully(fd_, reinterpret_cast<const uint8_t*>(&header_), sizeof(header_))) { PLOG(ERROR) << "WriteFully failed"; return false; } return Sync(); } } // namespace snapshot } // namespace android fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +3 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ struct CowHeader { // The size of block operations, in bytes. uint32_t block_size; // Tracks merge operations completed uint64_t num_merge_ops; } __attribute__((packed)); // This structure is the same size of a normal Operation, but is repurposed for the footer. Loading fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +2 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,8 @@ class CowReader : public ICowReader { bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read); void UpdateMergeProgress(uint64_t merge_ops) { header_.num_merge_ops += merge_ops; } private: bool ParseOps(); Loading fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +4 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,9 @@ class CowWriter : public ICowWriter { bool InitializeAppend(android::base::unique_fd&&, uint64_t label); bool InitializeAppend(android::base::borrowed_fd fd, uint64_t label); void InitializeMerge(android::base::borrowed_fd fd, CowHeader* header); bool CommitMerge(int merged_ops); bool Finalize() override; uint64_t GetCowSize() override; Loading Loading @@ -129,6 +132,7 @@ class CowWriter : public ICowWriter { int compression_ = 0; uint64_t next_op_pos_ = 0; bool is_dev_null_ = false; bool merge_in_progress_ = false; // :TODO: this is not efficient, but stringstream ubsan aborts because some // bytes overflow a signed char. Loading Loading
fs_mgr/libsnapshot/cow_reader.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -193,6 +193,26 @@ bool CowReader::ParseOps() { } else { LOG(INFO) << "No Footer, recovered data"; } if (header_.num_merge_ops > 0) { uint64_t merge_ops = header_.num_merge_ops; uint64_t metadata_ops = 0; current_op_num = 0; CHECK(ops_buffer->size() >= merge_ops); while (merge_ops) { auto& current_op = ops_buffer->data()[current_op_num]; if (current_op.type == kCowLabelOp || current_op.type == kCowFooterOp) { metadata_ops += 1; } else { merge_ops -= 1; } current_op_num += 1; } ops_buffer->erase(ops_buffer.get()->begin(), ops_buffer.get()->begin() + header_.num_merge_ops + metadata_ops); } ops_ = ops_buffer; return true; } Loading
fs_mgr/libsnapshot/cow_writer.cpp +29 −0 Original line number Diff line number Diff line Loading @@ -91,6 +91,7 @@ void CowWriter::SetupHeaders() { header_.header_size = sizeof(CowHeader); header_.footer_size = sizeof(CowFooter); header_.block_size = options_.block_size; header_.num_merge_ops = 0; footer_ = {}; footer_.op.data_length = 64; footer_.op.type = kCowFooterOp; Loading Loading @@ -125,6 +126,12 @@ bool CowWriter::SetFd(android::base::borrowed_fd fd) { return true; } void CowWriter::InitializeMerge(borrowed_fd fd, CowHeader* header) { fd_ = fd; memcpy(&header_, header, sizeof(CowHeader)); merge_in_progress_ = true; } bool CowWriter::Initialize(unique_fd&& fd) { owned_fd_ = std::move(fd); return Initialize(borrowed_fd{owned_fd_}); Loading Loading @@ -223,6 +230,7 @@ bool CowWriter::OpenForAppend(uint64_t label) { } bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) { CHECK(!merge_in_progress_); CowOperation op = {}; op.type = kCowCopyOp; op.new_block = new_block; Loading @@ -233,6 +241,7 @@ bool CowWriter::EmitCopy(uint64_t new_block, uint64_t old_block) { bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t size) { const uint8_t* iter = reinterpret_cast<const uint8_t*>(data); uint64_t pos; CHECK(!merge_in_progress_); for (size_t i = 0; i < size / header_.block_size; i++) { CowOperation op = {}; op.type = kCowReplaceOp; Loading Loading @@ -271,6 +280,7 @@ bool CowWriter::EmitRawBlocks(uint64_t new_block_start, const void* data, size_t } bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { CHECK(!merge_in_progress_); for (uint64_t i = 0; i < num_blocks; i++) { CowOperation op = {}; op.type = kCowZeroOp; Loading @@ -282,6 +292,7 @@ bool CowWriter::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) { } bool CowWriter::EmitLabel(uint64_t label) { CHECK(!merge_in_progress_); CowOperation op = {}; op.type = kCowLabelOp; op.source = label; Loading Loading @@ -416,5 +427,23 @@ bool CowWriter::Sync() { return true; } bool CowWriter::CommitMerge(int merged_ops) { CHECK(merge_in_progress_); header_.num_merge_ops += merged_ops; if (lseek(fd_.get(), 0, SEEK_SET) < 0) { PLOG(ERROR) << "lseek failed"; return false; } if (!android::base::WriteFully(fd_, reinterpret_cast<const uint8_t*>(&header_), sizeof(header_))) { PLOG(ERROR) << "WriteFully failed"; return false; } return Sync(); } } // namespace snapshot } // namespace android
fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +3 −0 Original line number Diff line number Diff line Loading @@ -59,6 +59,9 @@ struct CowHeader { // The size of block operations, in bytes. uint32_t block_size; // Tracks merge operations completed uint64_t num_merge_ops; } __attribute__((packed)); // This structure is the same size of a normal Operation, but is repurposed for the footer. Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +2 −0 Original line number Diff line number Diff line Loading @@ -135,6 +135,8 @@ class CowReader : public ICowReader { bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read); void UpdateMergeProgress(uint64_t merge_ops) { header_.num_merge_ops += merge_ops; } private: bool ParseOps(); Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_writer.h +4 −0 Original line number Diff line number Diff line Loading @@ -97,6 +97,9 @@ class CowWriter : public ICowWriter { bool InitializeAppend(android::base::unique_fd&&, uint64_t label); bool InitializeAppend(android::base::borrowed_fd fd, uint64_t label); void InitializeMerge(android::base::borrowed_fd fd, CowHeader* header); bool CommitMerge(int merged_ops); bool Finalize() override; uint64_t GetCowSize() override; Loading Loading @@ -129,6 +132,7 @@ class CowWriter : public ICowWriter { int compression_ = 0; uint64_t next_op_pos_ = 0; bool is_dev_null_ = false; bool merge_in_progress_ = false; // :TODO: this is not efficient, but stringstream ubsan aborts because some // bytes overflow a signed char. Loading