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

Commit 09ccef49 authored by David Anderson's avatar David Anderson
Browse files

libsnapshot: Add helpers for accessing CowOperation offsets.

These helpers avoid manual inspection of CowOperation::source, and
fiddling with block sizes.

Bug: 280529365
Test: cow_api_test
      vts_libsnapshot_test
      apply OTA
Change-Id: I1ba276e155eb8232a3115066caaa11030c171e11
parent 8790a71b
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -73,8 +73,20 @@ class ICowReader {
    // The operation pointer must derive from ICowOpIter::Get().
    virtual ssize_t ReadData(const CowOperation* op, void* buffer, size_t buffer_size,
                             size_t ignore_bytes = 0) = 0;

    // Get the absolute source offset, in bytes, of a CowOperation. Returns
    // false if the operation does not read from source partitions.
    virtual bool GetSourceOffset(const CowOperation* op, uint64_t* source_offset) = 0;
};

static constexpr uint64_t GetBlockFromOffset(const CowHeader& header, uint64_t offset) {
    return offset / header.block_size;
}

static constexpr uint64_t GetBlockRelativeOffset(const CowHeader& header, uint64_t offset) {
    return offset % header.block_size;
}

// Iterate over a sequence of COW operations. The iterator is bidirectional.
class ICowOpIter {
  public:
@@ -119,6 +131,7 @@ class CowReader final : public ICowReader {
    bool VerifyMergeOps() override;
    bool GetFooter(CowFooter* footer) override;
    bool GetLastLabel(uint64_t* label) override;
    bool GetSourceOffset(const CowOperation* op, uint64_t* source_offset) override;

    // Create a CowOpIter object which contains footer_.num_ops
    // CowOperation objects. Get() returns a unique CowOperation object
+19 −10
Original line number Diff line number Diff line
@@ -312,19 +312,15 @@ bool CowReader::VerifyMergeOps() {
    std::unordered_map<uint64_t, const CowOperation*> overwritten_blocks;
    while (!itr->AtEnd()) {
        const auto& op = itr->Get();
        uint64_t block;
        bool offset;
        if (op->type == kCowCopyOp) {
            block = op->source;
            offset = false;
        } else if (op->type == kCowXorOp) {
            block = op->source / header_.block_size;
            offset = (op->source % header_.block_size) != 0;
        } else {
        uint64_t offset;
        if (!GetSourceOffset(op, &offset)) {
            itr->Next();
            continue;
        }

        uint64_t block = GetBlockFromOffset(header_, offset);
        bool misaligned = (GetBlockRelativeOffset(header_, offset) != 0);

        const CowOperation* overwrite = nullptr;
        if (overwritten_blocks.count(block)) {
            overwrite = overwritten_blocks[block];
@@ -332,7 +328,7 @@ bool CowReader::VerifyMergeOps() {
                       << op << "\noverwritten by previously merged op:\n"
                       << *overwrite;
        }
        if (offset && overwritten_blocks.count(block + 1)) {
        if (misaligned && overwritten_blocks.count(block + 1)) {
            overwrite = overwritten_blocks[block + 1];
            LOG(ERROR) << "Invalid Sequence! Block needed for op:\n"
                       << op << "\noverwritten by previously merged op:\n"
@@ -622,5 +618,18 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_
    return decompressor->Decompress(buffer, buffer_size, header_.block_size, ignore_bytes);
}

bool CowReader::GetSourceOffset(const CowOperation* op, uint64_t* source_offset) {
    switch (op->type) {
        case kCowCopyOp:
            *source_offset = op->source * header_.block_size;
            return true;
        case kCowXorOp:
            *source_offset = op->source;
            return true;
        default:
            return false;
    }
}

}  // namespace snapshot
}  // namespace android
+12 −2
Original line number Diff line number Diff line
@@ -155,7 +155,12 @@ ssize_t CompressedSnapshotReader::ReadBlock(uint64_t chunk, size_t start_offset,
        }

        if (op) {
            chunk = op->source;
            uint64_t source_offset;
            if (!cow_->GetSourceOffset(op, &source_offset)) {
                LOG(ERROR) << "GetSourceOffset failed in CompressedSnapshotReader for op: " << *op;
                return false;
            }
            chunk = GetBlockFromOffset(cow_->GetHeader(), source_offset);
        }

        off64_t offset = (chunk * block_size_) + start_offset;
@@ -179,7 +184,12 @@ ssize_t CompressedSnapshotReader::ReadBlock(uint64_t chunk, size_t start_offset,
            return -1;
        }

        off64_t offset = op->source + start_offset;
        uint64_t source_offset;
        if (!cow_->GetSourceOffset(op, &source_offset)) {
            LOG(ERROR) << "GetSourceOffset failed in CompressedSnapshotReader for op: " << *op;
            return false;
        }
        off64_t offset = source_offset + start_offset;

        std::string data(bytes_to_read, '\0');
        if (!android::base::ReadFullyAtOffset(fd, data.data(), data.size(), offset)) {
+7 −6
Original line number Diff line number Diff line
@@ -115,12 +115,13 @@ bool WorkerThread::ReadFromBaseDevice(const CowOperation* cow_op) {
        SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
        return false;
    }
    SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
                    << " Source: " << cow_op->source;
    uint64_t offset = cow_op->source;
    if (cow_op->type == kCowCopyOp) {
        offset *= BLOCK_SZ;
    uint64_t offset;
    if (!reader_->GetSourceOffset(cow_op, &offset)) {
        SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get source offset";
        return false;
    }
    SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
                    << " Source: " << offset;
    if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
        SNAP_PLOG(ERROR) << "Copy op failed. Read from backing store: " << backing_store_device_
                         << "at block :" << offset / BLOCK_SZ << " offset:" << offset % BLOCK_SZ;
@@ -508,7 +509,7 @@ int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffe
                if (read_ahead_buffer_map.find(cow_op->new_block) == read_ahead_buffer_map.end()) {
                    SNAP_LOG(ERROR)
                            << " Block: " << cow_op->new_block << " not found in read-ahead cache"
                            << " Source: " << cow_op->source;
                            << " Op: " << *cow_op;
                    return -1;
                }
                // If this is a final block merged in the read-ahead buffer
+6 −5
Original line number Diff line number Diff line
@@ -94,12 +94,13 @@ bool Worker::ReadFromSourceDevice(const CowOperation* cow_op) {
        SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
        return false;
    }
    SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
                    << " Source: " << cow_op->source;
    uint64_t offset = cow_op->source;
    if (cow_op->type == kCowCopyOp) {
        offset *= BLOCK_SZ;
    uint64_t offset;
    if (!reader_->GetSourceOffset(cow_op, &offset)) {
        SNAP_LOG(ERROR) << "ReadFromSourceDevice: Failed to get source offset";
        return false;
    }
    SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
                    << " Op: " << *cow_op;
    if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
        std::string op;
        if (cow_op->type == kCowCopyOp)
Loading