Loading fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +12 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,16 @@ struct CowHeader { } __attribute__((packed)); // Resume point structure used for resume buffer struct ResumePoint { // monotonically increasing value used by update_engine uint64_t label; // Index of last CowOperation guaranteed to be resumable uint32_t op_index; } __attribute__((packed)); static constexpr uint8_t kNumResumePoints = 4; struct CowHeaderV3 : public CowHeader { // Location of sequence buffer in COW. uint64_t sequence_buffer_offset; Loading Loading @@ -245,6 +255,8 @@ std::ostream& operator<<(std::ostream& os, CowOperationV2 const& arg); std::ostream& operator<<(std::ostream& os, CowOperation const& arg); std::ostream& operator<<(std::ostream& os, ResumePoint const& arg); int64_t GetNextOpOffset(const CowOperationV2& op, uint32_t cluster_size); int64_t GetNextDataOffset(const CowOperationV2& op, uint32_t cluster_size); Loading fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +1 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <stdint.h> #include <deque> #include <functional> #include <memory> #include <optional> Loading Loading @@ -192,6 +193,5 @@ class CowReader final : public ICowReader { // The extra fields will just be filled as 0. V3 header is strictly a superset of v1/v2 header and // contains all of the latter's field bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header); } // namespace snapshot } // namespace android fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,11 @@ std::ostream& operator<<(std::ostream& os, CowOperation const& op) { return os; } std::ostream& operator<<(std::ostream& os, ResumePoint const& resume_point) { os << "ResumePoint(" << resume_point.label << " , " << resume_point.op_index << ")"; return os; } int64_t GetNextOpOffset(const CowOperationV2& op, uint32_t cluster_ops) { if (op.type == kCowClusterOp) { return op.source; Loading fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.cpp +44 −6 Original line number Diff line number Diff line Loading @@ -15,8 +15,10 @@ #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/strings.h> #include <libsnapshot/cow_format.h> #include <libsnapshot/cow_reader.h> namespace android { namespace snapshot { Loading @@ -36,6 +38,7 @@ bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional LOG(ERROR) << "Footer size isn't 0, read " << header_.footer_size; return false; } if (header_.op_size != sizeof(CowOperationV3)) { LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected " << sizeof(CowOperationV3); Loading @@ -55,18 +58,54 @@ bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional return false; } return ParseOps(fd, label); std::optional<uint32_t> op_index = header_.op_count; if (label) { if (!ReadResumeBuffer(fd)) { PLOG(ERROR) << "Failed to read resume buffer"; return false; } op_index = FindResumeOp(label.value()); if (op_index == std::nullopt) { LOG(ERROR) << "failed to get op index from given label: " << label.value(); return false; } } return ParseOps(fd, op_index.value()); } bool CowParserV3::ReadResumeBuffer(borrowed_fd fd) { resume_points_ = std::make_shared<std::vector<ResumePoint>>(header_.resume_buffer_size); return android::base::ReadFullyAtOffset(fd, resume_points_->data(), header_.resume_buffer_size * sizeof(ResumePoint), header_.prefix.header_size + header_.buffer_size); } std::optional<uint32_t> CowParserV3::FindResumeOp(const uint32_t label) { for (auto& resume_point : *resume_points_) { if (resume_point.label == label) { return resume_point.op_index; } } LOG(ERROR) << "failed to find label: " << label << "from following labels"; LOG(ERROR) << android::base::Join(*resume_points_, " "); return std::nullopt; } off_t CowParserV3::GetDataOffset() const { return sizeof(CowHeaderV3) + header_.buffer_size + header_.op_count_max * sizeof(CowOperation); return sizeof(CowHeaderV3) + header_.buffer_size + header_.resume_buffer_size * sizeof(ResumePoint) + header_.op_count_max * sizeof(CowOperation); } bool CowParserV3::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) { bool CowParserV3::ParseOps(borrowed_fd fd, const uint32_t op_index) { ops_ = std::make_shared<std::vector<CowOperationV3>>(); ops_->resize(header_.op_count); ops_->resize(op_index); const off_t offset = header_.prefix.header_size + header_.buffer_size; const off_t offset = header_.prefix.header_size + header_.buffer_size + header_.resume_buffer_size * sizeof(ResumePoint); if (!android::base::ReadFullyAtOffset(fd, ops_->data(), ops_->size() * sizeof(CowOperationV3), offset)) { PLOG(ERROR) << "read ops failed"; Loading @@ -87,7 +126,6 @@ bool CowParserV3::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) { // :TODO: sequence buffer & resume buffer follow // Once we implement labels, we'll have to discard unused ops and adjust // the header as needed. CHECK(!label); ops_->shrink_to_fit(); Loading fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.h +5 −1 Original line number Diff line number Diff line Loading @@ -45,12 +45,16 @@ class CowParserV3 final : public CowParserBase { bool Parse(android::base::borrowed_fd fd, const CowHeaderV3& header, std::optional<uint64_t> label = {}) override; bool Translate(TranslatedCowOps* out) override; std::shared_ptr<std::vector<ResumePoint>> resume_points() const { return resume_points_; } private: bool ParseOps(android::base::borrowed_fd fd, std::optional<uint64_t> label); bool ParseOps(android::base::borrowed_fd fd, const uint32_t op_index); std::optional<uint32_t> FindResumeOp(const uint32_t label); off_t GetDataOffset() const; CowHeaderV3 header_ = {}; std::shared_ptr<std::vector<CowOperationV3>> ops_; bool ReadResumeBuffer(android::base::borrowed_fd fd); std::shared_ptr<std::vector<ResumePoint>> resume_points_; }; } // namespace snapshot Loading Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_format.h +12 −0 Original line number Diff line number Diff line Loading @@ -94,6 +94,16 @@ struct CowHeader { } __attribute__((packed)); // Resume point structure used for resume buffer struct ResumePoint { // monotonically increasing value used by update_engine uint64_t label; // Index of last CowOperation guaranteed to be resumable uint32_t op_index; } __attribute__((packed)); static constexpr uint8_t kNumResumePoints = 4; struct CowHeaderV3 : public CowHeader { // Location of sequence buffer in COW. uint64_t sequence_buffer_offset; Loading Loading @@ -245,6 +255,8 @@ std::ostream& operator<<(std::ostream& os, CowOperationV2 const& arg); std::ostream& operator<<(std::ostream& os, CowOperation const& arg); std::ostream& operator<<(std::ostream& os, ResumePoint const& arg); int64_t GetNextOpOffset(const CowOperationV2& op, uint32_t cluster_size); int64_t GetNextDataOffset(const CowOperationV2& op, uint32_t cluster_size); Loading
fs_mgr/libsnapshot/include/libsnapshot/cow_reader.h +1 −1 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ #include <stdint.h> #include <deque> #include <functional> #include <memory> #include <optional> Loading Loading @@ -192,6 +193,5 @@ class CowReader final : public ICowReader { // The extra fields will just be filled as 0. V3 header is strictly a superset of v1/v2 header and // contains all of the latter's field bool ReadCowHeader(android::base::borrowed_fd fd, CowHeaderV3* header); } // namespace snapshot } // namespace android
fs_mgr/libsnapshot/libsnapshot_cow/cow_format.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -100,6 +100,11 @@ std::ostream& operator<<(std::ostream& os, CowOperation const& op) { return os; } std::ostream& operator<<(std::ostream& os, ResumePoint const& resume_point) { os << "ResumePoint(" << resume_point.label << " , " << resume_point.op_index << ")"; return os; } int64_t GetNextOpOffset(const CowOperationV2& op, uint32_t cluster_ops) { if (op.type == kCowClusterOp) { return op.source; Loading
fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.cpp +44 −6 Original line number Diff line number Diff line Loading @@ -15,8 +15,10 @@ #include <android-base/file.h> #include <android-base/logging.h> #include <android-base/strings.h> #include <libsnapshot/cow_format.h> #include <libsnapshot/cow_reader.h> namespace android { namespace snapshot { Loading @@ -36,6 +38,7 @@ bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional LOG(ERROR) << "Footer size isn't 0, read " << header_.footer_size; return false; } if (header_.op_size != sizeof(CowOperationV3)) { LOG(ERROR) << "Operation size unknown, read " << header_.op_size << ", expected " << sizeof(CowOperationV3); Loading @@ -55,18 +58,54 @@ bool CowParserV3::Parse(borrowed_fd fd, const CowHeaderV3& header, std::optional return false; } return ParseOps(fd, label); std::optional<uint32_t> op_index = header_.op_count; if (label) { if (!ReadResumeBuffer(fd)) { PLOG(ERROR) << "Failed to read resume buffer"; return false; } op_index = FindResumeOp(label.value()); if (op_index == std::nullopt) { LOG(ERROR) << "failed to get op index from given label: " << label.value(); return false; } } return ParseOps(fd, op_index.value()); } bool CowParserV3::ReadResumeBuffer(borrowed_fd fd) { resume_points_ = std::make_shared<std::vector<ResumePoint>>(header_.resume_buffer_size); return android::base::ReadFullyAtOffset(fd, resume_points_->data(), header_.resume_buffer_size * sizeof(ResumePoint), header_.prefix.header_size + header_.buffer_size); } std::optional<uint32_t> CowParserV3::FindResumeOp(const uint32_t label) { for (auto& resume_point : *resume_points_) { if (resume_point.label == label) { return resume_point.op_index; } } LOG(ERROR) << "failed to find label: " << label << "from following labels"; LOG(ERROR) << android::base::Join(*resume_points_, " "); return std::nullopt; } off_t CowParserV3::GetDataOffset() const { return sizeof(CowHeaderV3) + header_.buffer_size + header_.op_count_max * sizeof(CowOperation); return sizeof(CowHeaderV3) + header_.buffer_size + header_.resume_buffer_size * sizeof(ResumePoint) + header_.op_count_max * sizeof(CowOperation); } bool CowParserV3::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) { bool CowParserV3::ParseOps(borrowed_fd fd, const uint32_t op_index) { ops_ = std::make_shared<std::vector<CowOperationV3>>(); ops_->resize(header_.op_count); ops_->resize(op_index); const off_t offset = header_.prefix.header_size + header_.buffer_size; const off_t offset = header_.prefix.header_size + header_.buffer_size + header_.resume_buffer_size * sizeof(ResumePoint); if (!android::base::ReadFullyAtOffset(fd, ops_->data(), ops_->size() * sizeof(CowOperationV3), offset)) { PLOG(ERROR) << "read ops failed"; Loading @@ -87,7 +126,6 @@ bool CowParserV3::ParseOps(borrowed_fd fd, std::optional<uint64_t> label) { // :TODO: sequence buffer & resume buffer follow // Once we implement labels, we'll have to discard unused ops and adjust // the header as needed. CHECK(!label); ops_->shrink_to_fit(); Loading
fs_mgr/libsnapshot/libsnapshot_cow/parser_v3.h +5 −1 Original line number Diff line number Diff line Loading @@ -45,12 +45,16 @@ class CowParserV3 final : public CowParserBase { bool Parse(android::base::borrowed_fd fd, const CowHeaderV3& header, std::optional<uint64_t> label = {}) override; bool Translate(TranslatedCowOps* out) override; std::shared_ptr<std::vector<ResumePoint>> resume_points() const { return resume_points_; } private: bool ParseOps(android::base::borrowed_fd fd, std::optional<uint64_t> label); bool ParseOps(android::base::borrowed_fd fd, const uint32_t op_index); std::optional<uint32_t> FindResumeOp(const uint32_t label); off_t GetDataOffset() const; CowHeaderV3 header_ = {}; std::shared_ptr<std::vector<CowOperationV3>> ops_; bool ReadResumeBuffer(android::base::borrowed_fd fd); std::shared_ptr<std::vector<ResumePoint>> resume_points_; }; } // namespace snapshot Loading