Loading fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +28 −11 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <limits> #include <optional> #include <string_view> #include <type_traits> namespace android { namespace snapshot { Loading Loading @@ -194,11 +195,12 @@ struct CowOperationV2 { uint64_t source; } __attribute__((packed)); static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; static constexpr uint64_t kCowOpSourceInfoTypeBit = 60; static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4; static constexpr uint64_t kCowOpSourceInfoTypeMask = (1ULL << kCowOpSourceInfoTypeNumBits) - 1; // The on disk format of cow (currently == CowOperation) struct CowOperationV3 { // The operation code (see the constants and structures below). CowOperationType type; // If this operation reads from the data section of the COW, this contains // the length. uint16_t data_length; Loading @@ -206,6 +208,10 @@ struct CowOperationV3 { // The block of data in the new image that this operation modifies. uint32_t new_block; // source_info with have the following layout // |---4 bits ---| ---12 bits---| --- 48 bits ---| // |--- type --- | -- unused -- | --- source --- | // // The value of |source| depends on the operation code. // // CopyOp: a 32-bit block location in the source image. Loading @@ -217,9 +223,26 @@ struct CowOperationV3 { // For ops other than Label: // Bits 47-62 are reserved and must be zero. // A block is compressed if it’s data is < block_sz uint64_t source_info; uint64_t source_info_; constexpr uint64_t source() const { return source_info_ & kCowOpSourceInfoDataMask; } constexpr void set_source(uint64_t source) { source_info_ |= source & kCowOpSourceInfoDataMask; } constexpr CowOperationType type() const { // this is a mask to grab the first 4 bits of a 64 bit integer const auto type = (source_info_ >> kCowOpSourceInfoTypeBit) & kCowOpSourceInfoTypeMask; return static_cast<CowOperationType>(type); } constexpr void set_type(CowOperationType type) { source_info_ |= (static_cast<uint64_t>(type) & kCowOpSourceInfoTypeMask) << kCowOpSourceInfoTypeBit; } } __attribute__((packed)); // Ensure that getters/setters added to CowOperationV3 does not increases size // of CowOperationV3 struct(no virtual method tables added). static_assert(std::is_trivially_copyable_v<CowOperationV3>); static_assert(std::is_standard_layout_v<CowOperationV3>); static_assert(sizeof(CowOperationV2) == sizeof(CowFooterOperation)); enum CowCompressionAlgorithm : uint8_t { Loading @@ -238,12 +261,6 @@ static constexpr uint8_t kCowReadAheadNotStarted = 0; static constexpr uint8_t kCowReadAheadInProgress = 1; static constexpr uint8_t kCowReadAheadDone = 2; static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; static inline uint64_t GetCowOpSourceInfoData(const CowOperation& op) { return op.source_info & kCowOpSourceInfoDataMask; } static constexpr off_t GetSequenceOffset(const CowHeaderV3& header) { return header.prefix.header_size + header.buffer_size; } Loading Loading @@ -284,7 +301,7 @@ static constexpr uint64_t BUFFER_REGION_DEFAULT_SIZE = (1ULL << 21); std::ostream& operator<<(std::ostream& os, CowOperationV2 const& arg); std::ostream& operator<<(std::ostream& os, CowOperation const& arg); std::ostream& operator<<(std::ostream& os, CowOperationV3 const& arg); std::ostream& operator<<(std::ostream& os, ResumePoint const& arg); Loading fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp +11 −12 Original line number Diff line number Diff line Loading @@ -80,22 +80,21 @@ std::ostream& operator<<(std::ostream& os, CowOperationV2 const& op) { return os; } std::ostream& operator<<(std::ostream& os, CowOperation const& op) { std::ostream& operator<<(std::ostream& os, CowOperationV3 const& op) { os << "CowOperation("; EmitCowTypeString(os, op.type); if (op.type == kCowReplaceOp || op.type == kCowXorOp || op.type == kCowSequenceOp) { EmitCowTypeString(os, op.type()); if (op.type() == kCowReplaceOp || op.type() == kCowXorOp || op.type() == kCowSequenceOp) { os << ", data_length:" << op.data_length; } if (op.type != kCowClusterOp && op.type != kCowSequenceOp && op.type != kCowLabelOp) { if (op.type() != kCowClusterOp && op.type() != kCowSequenceOp && op.type() != kCowLabelOp) { os << ", new_block:" << op.new_block; } if (op.type == kCowXorOp || op.type == kCowReplaceOp || op.type == kCowCopyOp) { os << ", source:" << (op.source_info & kCowOpSourceInfoDataMask); } else if (op.type == kCowClusterOp) { os << ", cluster_data:" << (op.source_info & kCowOpSourceInfoDataMask); } else { os << ", label:0x" << android::base::StringPrintf("%" PRIx64, op.source_info); if (op.type() == kCowXorOp || op.type() == kCowReplaceOp || op.type() == kCowCopyOp) { os << ", source:" << op.source(); } else if (op.type() == kCowClusterOp) { os << ", cluster_data:" << op.source(); } // V3 op stores resume points in header, so CowOp can never be Label. os << ")"; return os; } Loading Loading @@ -126,7 +125,7 @@ int64_t GetNextDataOffset(const CowOperationV2& op, uint32_t cluster_ops) { } bool IsMetadataOp(const CowOperation& op) { switch (op.type) { switch (op.type()) { case kCowLabelOp: case kCowClusterOp: case kCowFooterOp: Loading @@ -138,7 +137,7 @@ bool IsMetadataOp(const CowOperation& op) { } bool IsOrderedOp(const CowOperation& op) { switch (op.type) { switch (op.type()) { case kCowCopyOp: case kCowXorOp: return true; Loading fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -345,7 +345,7 @@ bool CowReader::GetSequenceDataV2(std::vector<uint32_t>* merge_op_blocks, for (size_t i = 0; i < ops_->size(); i++) { auto& current_op = ops_->data()[i]; if (current_op.type == kCowSequenceOp) { if (current_op.type() == kCowSequenceOp) { size_t seq_len = current_op.data_length / sizeof(uint32_t); merge_op_blocks->resize(merge_op_blocks->size() + seq_len); Loading Loading @@ -637,11 +637,11 @@ std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) { } bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read) { switch (op->type) { switch (op->type()) { case kCowSequenceOp: case kCowReplaceOp: case kCowXorOp: return GetRawBytes(GetCowOpSourceInfoData(*op), buffer, len, read); return GetRawBytes(op->source(), buffer, len, read); default: LOG(ERROR) << "Cannot get raw bytes of non-data op: " << *op; return false; Loading Loading @@ -730,10 +730,10 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ } uint64_t offset; if (op->type == kCowXorOp) { if (op->type() == kCowXorOp) { offset = xor_data_loc_->at(op->new_block); } else { offset = GetCowOpSourceInfoData(*op); offset = op->source(); } if (!decompressor || ((op->data_length == header_.block_size) && (header_.prefix.major_version == 3))) { Loading @@ -747,12 +747,12 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ } bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) { switch (op->type) { switch (op->type()) { case kCowCopyOp: *source_offset = GetCowOpSourceInfoData(*op) * header_.block_size; *source_offset = op->source() * header_.block_size; return true; case kCowXorOp: *source_offset = GetCowOpSourceInfoData(*op); *source_offset = op->source(); return true; default: return false; Loading fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -199,7 +199,7 @@ static bool Inspect(const std::string& path) { if (!FLAGS_silent && FLAGS_show_ops) std::cout << *op << "\n"; if ((FLAGS_decompress || extract_to >= 0) && op->type == kCowReplaceOp) { if ((FLAGS_decompress || extract_to >= 0) && op->type() == kCowReplaceOp) { if (reader.ReadData(op, buffer.data(), buffer.size()) < 0) { std::cerr << "Failed to decompress for :" << *op << "\n"; success = false; Loading @@ -213,12 +213,12 @@ static bool Inspect(const std::string& path) { return false; } } } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type != kCowZeroOp) { } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type() != kCowZeroOp) { PLOG(ERROR) << "Cannot extract op yet: " << *op; return false; } if (op->type == kCowSequenceOp && FLAGS_show_merge_sequence) { if (op->type() == kCowSequenceOp && FLAGS_show_merge_sequence) { size_t read; std::vector<uint32_t> merge_op_blocks; size_t seq_len = op->data_length / sizeof(uint32_t); Loading @@ -236,13 +236,13 @@ static bool Inspect(const std::string& path) { } } if (op->type == kCowCopyOp) { if (op->type() == kCowCopyOp) { copy_ops++; } else if (op->type == kCowReplaceOp) { } else if (op->type() == kCowReplaceOp) { replace_ops++; } else if (op->type == kCowZeroOp) { } else if (op->type() == kCowZeroOp) { zero_ops++; } else if (op->type == kCowXorOp) { } else if (op->type() == kCowXorOp) { xor_ops++; } Loading fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -205,7 +205,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) { const auto& v2_op = v2_ops_->at(i); auto& new_op = out->ops->at(i); new_op.type = v2_op.type; new_op.set_type(v2_op.type); new_op.data_length = v2_op.data_length; if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) { Loading @@ -215,7 +215,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) { new_op.new_block = v2_op.new_block; uint64_t source_info = v2_op.source; if (new_op.type != kCowLabelOp) { if (new_op.type() != kCowLabelOp) { source_info &= kCowOpSourceInfoDataMask; if (source_info != v2_op.source) { LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op; Loading @@ -232,7 +232,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) { return false; } } new_op.source_info = source_info; new_op.set_source(source_info); } out->header = header_; Loading Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +28 −11 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ #include <limits> #include <optional> #include <string_view> #include <type_traits> namespace android { namespace snapshot { Loading Loading @@ -194,11 +195,12 @@ struct CowOperationV2 { uint64_t source; } __attribute__((packed)); static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; static constexpr uint64_t kCowOpSourceInfoTypeBit = 60; static constexpr uint64_t kCowOpSourceInfoTypeNumBits = 4; static constexpr uint64_t kCowOpSourceInfoTypeMask = (1ULL << kCowOpSourceInfoTypeNumBits) - 1; // The on disk format of cow (currently == CowOperation) struct CowOperationV3 { // The operation code (see the constants and structures below). CowOperationType type; // If this operation reads from the data section of the COW, this contains // the length. uint16_t data_length; Loading @@ -206,6 +208,10 @@ struct CowOperationV3 { // The block of data in the new image that this operation modifies. uint32_t new_block; // source_info with have the following layout // |---4 bits ---| ---12 bits---| --- 48 bits ---| // |--- type --- | -- unused -- | --- source --- | // // The value of |source| depends on the operation code. // // CopyOp: a 32-bit block location in the source image. Loading @@ -217,9 +223,26 @@ struct CowOperationV3 { // For ops other than Label: // Bits 47-62 are reserved and must be zero. // A block is compressed if it’s data is < block_sz uint64_t source_info; uint64_t source_info_; constexpr uint64_t source() const { return source_info_ & kCowOpSourceInfoDataMask; } constexpr void set_source(uint64_t source) { source_info_ |= source & kCowOpSourceInfoDataMask; } constexpr CowOperationType type() const { // this is a mask to grab the first 4 bits of a 64 bit integer const auto type = (source_info_ >> kCowOpSourceInfoTypeBit) & kCowOpSourceInfoTypeMask; return static_cast<CowOperationType>(type); } constexpr void set_type(CowOperationType type) { source_info_ |= (static_cast<uint64_t>(type) & kCowOpSourceInfoTypeMask) << kCowOpSourceInfoTypeBit; } } __attribute__((packed)); // Ensure that getters/setters added to CowOperationV3 does not increases size // of CowOperationV3 struct(no virtual method tables added). static_assert(std::is_trivially_copyable_v<CowOperationV3>); static_assert(std::is_standard_layout_v<CowOperationV3>); static_assert(sizeof(CowOperationV2) == sizeof(CowFooterOperation)); enum CowCompressionAlgorithm : uint8_t { Loading @@ -238,12 +261,6 @@ static constexpr uint8_t kCowReadAheadNotStarted = 0; static constexpr uint8_t kCowReadAheadInProgress = 1; static constexpr uint8_t kCowReadAheadDone = 2; static constexpr uint64_t kCowOpSourceInfoDataMask = (1ULL << 48) - 1; static inline uint64_t GetCowOpSourceInfoData(const CowOperation& op) { return op.source_info & kCowOpSourceInfoDataMask; } static constexpr off_t GetSequenceOffset(const CowHeaderV3& header) { return header.prefix.header_size + header.buffer_size; } Loading Loading @@ -284,7 +301,7 @@ static constexpr uint64_t BUFFER_REGION_DEFAULT_SIZE = (1ULL << 21); std::ostream& operator<<(std::ostream& os, CowOperationV2 const& arg); std::ostream& operator<<(std::ostream& os, CowOperation const& arg); std::ostream& operator<<(std::ostream& os, CowOperationV3 const& arg); std::ostream& operator<<(std::ostream& os, ResumePoint const& arg); Loading
fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp +11 −12 Original line number Diff line number Diff line Loading @@ -80,22 +80,21 @@ std::ostream& operator<<(std::ostream& os, CowOperationV2 const& op) { return os; } std::ostream& operator<<(std::ostream& os, CowOperation const& op) { std::ostream& operator<<(std::ostream& os, CowOperationV3 const& op) { os << "CowOperation("; EmitCowTypeString(os, op.type); if (op.type == kCowReplaceOp || op.type == kCowXorOp || op.type == kCowSequenceOp) { EmitCowTypeString(os, op.type()); if (op.type() == kCowReplaceOp || op.type() == kCowXorOp || op.type() == kCowSequenceOp) { os << ", data_length:" << op.data_length; } if (op.type != kCowClusterOp && op.type != kCowSequenceOp && op.type != kCowLabelOp) { if (op.type() != kCowClusterOp && op.type() != kCowSequenceOp && op.type() != kCowLabelOp) { os << ", new_block:" << op.new_block; } if (op.type == kCowXorOp || op.type == kCowReplaceOp || op.type == kCowCopyOp) { os << ", source:" << (op.source_info & kCowOpSourceInfoDataMask); } else if (op.type == kCowClusterOp) { os << ", cluster_data:" << (op.source_info & kCowOpSourceInfoDataMask); } else { os << ", label:0x" << android::base::StringPrintf("%" PRIx64, op.source_info); if (op.type() == kCowXorOp || op.type() == kCowReplaceOp || op.type() == kCowCopyOp) { os << ", source:" << op.source(); } else if (op.type() == kCowClusterOp) { os << ", cluster_data:" << op.source(); } // V3 op stores resume points in header, so CowOp can never be Label. os << ")"; return os; } Loading Loading @@ -126,7 +125,7 @@ int64_t GetNextDataOffset(const CowOperationV2& op, uint32_t cluster_ops) { } bool IsMetadataOp(const CowOperation& op) { switch (op.type) { switch (op.type()) { case kCowLabelOp: case kCowClusterOp: case kCowFooterOp: Loading @@ -138,7 +137,7 @@ bool IsMetadataOp(const CowOperation& op) { } bool IsOrderedOp(const CowOperation& op) { switch (op.type) { switch (op.type()) { case kCowCopyOp: case kCowXorOp: return true; Loading
fs_mgr/libsnapshot/libsnapshot_cow/cow_reader.cpp +8 −8 Original line number Diff line number Diff line Loading @@ -345,7 +345,7 @@ bool CowReader::GetSequenceDataV2(std::vector<uint32_t>* merge_op_blocks, for (size_t i = 0; i < ops_->size(); i++) { auto& current_op = ops_->data()[i]; if (current_op.type == kCowSequenceOp) { if (current_op.type() == kCowSequenceOp) { size_t seq_len = current_op.data_length / sizeof(uint32_t); merge_op_blocks->resize(merge_op_blocks->size() + seq_len); Loading Loading @@ -637,11 +637,11 @@ std::unique_ptr<ICowOpIter> CowReader::GetMergeOpIter(bool ignore_progress) { } bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read) { switch (op->type) { switch (op->type()) { case kCowSequenceOp: case kCowReplaceOp: case kCowXorOp: return GetRawBytes(GetCowOpSourceInfoData(*op), buffer, len, read); return GetRawBytes(op->source(), buffer, len, read); default: LOG(ERROR) << "Cannot get raw bytes of non-data op: " << *op; return false; Loading Loading @@ -730,10 +730,10 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ } uint64_t offset; if (op->type == kCowXorOp) { if (op->type() == kCowXorOp) { offset = xor_data_loc_->at(op->new_block); } else { offset = GetCowOpSourceInfoData(*op); offset = op->source(); } if (!decompressor || ((op->data_length == header_.block_size) && (header_.prefix.major_version == 3))) { Loading @@ -747,12 +747,12 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_ } bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) { switch (op->type) { switch (op->type()) { case kCowCopyOp: *source_offset = GetCowOpSourceInfoData(*op) * header_.block_size; *source_offset = op->source() * header_.block_size; return true; case kCowXorOp: *source_offset = GetCowOpSourceInfoData(*op); *source_offset = op->source(); return true; default: return false; Loading
fs_mgr/libsnapshot/libsnapshot_cow/inspect_cow.cpp +7 −7 Original line number Diff line number Diff line Loading @@ -199,7 +199,7 @@ static bool Inspect(const std::string& path) { if (!FLAGS_silent && FLAGS_show_ops) std::cout << *op << "\n"; if ((FLAGS_decompress || extract_to >= 0) && op->type == kCowReplaceOp) { if ((FLAGS_decompress || extract_to >= 0) && op->type() == kCowReplaceOp) { if (reader.ReadData(op, buffer.data(), buffer.size()) < 0) { std::cerr << "Failed to decompress for :" << *op << "\n"; success = false; Loading @@ -213,12 +213,12 @@ static bool Inspect(const std::string& path) { return false; } } } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type != kCowZeroOp) { } else if (extract_to >= 0 && !IsMetadataOp(*op) && op->type() != kCowZeroOp) { PLOG(ERROR) << "Cannot extract op yet: " << *op; return false; } if (op->type == kCowSequenceOp && FLAGS_show_merge_sequence) { if (op->type() == kCowSequenceOp && FLAGS_show_merge_sequence) { size_t read; std::vector<uint32_t> merge_op_blocks; size_t seq_len = op->data_length / sizeof(uint32_t); Loading @@ -236,13 +236,13 @@ static bool Inspect(const std::string& path) { } } if (op->type == kCowCopyOp) { if (op->type() == kCowCopyOp) { copy_ops++; } else if (op->type == kCowReplaceOp) { } else if (op->type() == kCowReplaceOp) { replace_ops++; } else if (op->type == kCowZeroOp) { } else if (op->type() == kCowZeroOp) { zero_ops++; } else if (op->type == kCowXorOp) { } else if (op->type() == kCowXorOp) { xor_ops++; } Loading
fs_mgr/libsnapshot/libsnapshot_cow/parser_v2.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -205,7 +205,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) { const auto& v2_op = v2_ops_->at(i); auto& new_op = out->ops->at(i); new_op.type = v2_op.type; new_op.set_type(v2_op.type); new_op.data_length = v2_op.data_length; if (v2_op.new_block > std::numeric_limits<uint32_t>::max()) { Loading @@ -215,7 +215,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) { new_op.new_block = v2_op.new_block; uint64_t source_info = v2_op.source; if (new_op.type != kCowLabelOp) { if (new_op.type() != kCowLabelOp) { source_info &= kCowOpSourceInfoDataMask; if (source_info != v2_op.source) { LOG(ERROR) << "Out-of-range source value in COW op: " << v2_op; Loading @@ -232,7 +232,7 @@ bool CowParserV2::Translate(TranslatedCowOps* out) { return false; } } new_op.source_info = source_info; new_op.set_source(source_info); } out->header = header_; Loading