Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4f80e5c authored by Daniel Zheng's avatar Daniel Zheng Committed by Gerrit Code Review
Browse files

Merge "libsnapshot: implement resume buffer" into main

parents dbb4a111 c2ce0848
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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);

+1 −1
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

#include <stdint.h>

#include <deque>
#include <functional>
#include <memory>
#include <optional>
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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;
+44 −6
Original line number Diff line number Diff line
@@ -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 {
@@ -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);
@@ -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";
@@ -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();

+5 −1
Original line number Diff line number Diff line
@@ -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