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

Commit b41cd681 authored by David Anderson's avatar David Anderson Committed by Gerrit Code Review
Browse files

Merge changes I07031e89,I1ba276e1

* changes:
  libsnapshot: Remove direct accesses of CowOperation::source and compression.
  libsnapshot: Add helpers for accessing CowOperation offsets.
parents 4ad8a68f cf311bd0
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -166,6 +166,13 @@ static constexpr uint8_t kCowReadAheadNotStarted = 0;
static constexpr uint8_t kCowReadAheadInProgress = 1;
static constexpr uint8_t kCowReadAheadDone = 2;

static inline uint64_t GetCowOpSourceInfoData(const CowOperation* op) {
    return op->source;
}
static inline bool GetCowOpSourceInfoCompression(const CowOperation* op) {
    return op->compression != kCowCompressNone;
}

struct CowFooter {
    CowFooterOperation op;
    uint8_t unused[64];
+14 −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
@@ -155,6 +168,7 @@ class CowReader final : public ICowReader {
    bool ParseOps(std::optional<uint64_t> label);
    bool PrepMergeOps();
    uint64_t FindNumCopyops();
    uint8_t GetCompressionType(const CowOperation* op);

    android::base::unique_fd owned_fd_;
    android::base::borrowed_fd fd_;
+27 −14
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"
@@ -521,7 +517,7 @@ bool CowReader::GetRawBytes(const CowOperation* op, void* buffer, size_t len, si
        case kCowSequenceOp:
        case kCowReplaceOp:
        case kCowXorOp:
            return GetRawBytes(op->source, buffer, len, read);
            return GetRawBytes(GetCowOpSourceInfoData(op), buffer, len, read);
        default:
            LOG(ERROR) << "Cannot get raw bytes of non-data op: " << *op;
            return false;
@@ -578,10 +574,14 @@ class CowDataStream final : public IByteStream {
    size_t remaining_;
};

uint8_t CowReader::GetCompressionType(const CowOperation* op) {
    return op->compression;
}

ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_size,
                            size_t ignore_bytes) {
    std::unique_ptr<IDecompressor> decompressor;
    switch (op->compression) {
    switch (GetCompressionType(op)) {
        case kCowCompressNone:
            break;
        case kCowCompressGz:
@@ -601,7 +601,7 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_
            }
            break;
        default:
            LOG(ERROR) << "Unknown compression type: " << op->compression;
            LOG(ERROR) << "Unknown compression type: " << GetCompressionType(op);
            return -1;
    }

@@ -609,7 +609,7 @@ ssize_t CowReader::ReadData(const CowOperation* op, void* buffer, size_t buffer_
    if (op->type == kCowXorOp) {
        offset = data_loc_->at(op->new_block);
    } else {
        offset = op->source;
        offset = GetCowOpSourceInfoData(op);
    }

    if (!decompressor) {
@@ -622,5 +622,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 = GetCowOpSourceInfoData(op) * header_.block_size;
            return true;
        case kCowXorOp:
            *source_offset = GetCowOpSourceInfoData(op);
            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)) {
+8 −8
Original line number Diff line number Diff line
@@ -145,7 +145,7 @@ TEST_F(CowTest, ReadWrite) {
    op = iter->Get();

    ASSERT_EQ(op->type, kCowReplaceOp);
    ASSERT_EQ(op->compression, kCowCompressNone);
    ASSERT_FALSE(GetCowOpSourceInfoCompression(op));
    ASSERT_EQ(op->data_length, 4096);
    ASSERT_EQ(op->new_block, 50);
    ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
@@ -224,10 +224,10 @@ TEST_F(CowTest, ReadWriteXor) {
    op = iter->Get();

    ASSERT_EQ(op->type, kCowXorOp);
    ASSERT_EQ(op->compression, kCowCompressNone);
    ASSERT_FALSE(GetCowOpSourceInfoCompression(op));
    ASSERT_EQ(op->data_length, 4096);
    ASSERT_EQ(op->new_block, 50);
    ASSERT_EQ(op->source, 98314);  // 4096 * 24 + 10
    ASSERT_EQ(GetCowOpSourceInfoData(op), 98314);  // 4096 * 24 + 10
    ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
    ASSERT_EQ(sink, data);

@@ -283,7 +283,7 @@ TEST_F(CowTest, CompressGz) {
    std::string sink(data.size(), '\0');

    ASSERT_EQ(op->type, kCowReplaceOp);
    ASSERT_EQ(op->compression, kCowCompressGz);
    ASSERT_TRUE(GetCowOpSourceInfoCompression(op));
    ASSERT_EQ(op->data_length, 56);  // compressed!
    ASSERT_EQ(op->new_block, 50);
    ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
@@ -339,7 +339,7 @@ TEST_P(CompressionTest, ThreadedBatchWrites) {
            total_blocks += 1;
            std::string sink(xor_data.size(), '\0');
            ASSERT_EQ(op->new_block, 50);
            ASSERT_EQ(op->source, 98314);  // 4096 * 24 + 10
            ASSERT_EQ(GetCowOpSourceInfoData(op), 98314);  // 4096 * 24 + 10
            ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
            ASSERT_EQ(sink, xor_data);
        }
@@ -528,7 +528,7 @@ TEST_F(CowTest, ClusterCompressGz) {
    std::string sink(data.size(), '\0');

    ASSERT_EQ(op->type, kCowReplaceOp);
    ASSERT_EQ(op->compression, kCowCompressGz);
    ASSERT_TRUE(GetCowOpSourceInfoCompression(op));
    ASSERT_EQ(op->data_length, 56);  // compressed!
    ASSERT_EQ(op->new_block, 50);
    ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
@@ -546,7 +546,7 @@ TEST_F(CowTest, ClusterCompressGz) {

    sink = {};
    sink.resize(data2.size(), '\0');
    ASSERT_EQ(op->compression, kCowCompressGz);
    ASSERT_TRUE(GetCowOpSourceInfoCompression(op));
    ASSERT_EQ(op->data_length, 41);  // compressed!
    ASSERT_EQ(op->new_block, 51);
    ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
@@ -591,7 +591,7 @@ TEST_F(CowTest, CompressTwoBlocks) {

    auto op = iter->Get();
    ASSERT_EQ(op->type, kCowReplaceOp);
    ASSERT_EQ(op->compression, kCowCompressGz);
    ASSERT_TRUE(GetCowOpSourceInfoCompression(op));
    ASSERT_EQ(op->new_block, 51);
    ASSERT_TRUE(ReadData(reader, op, sink.data(), sink.size()));
}
Loading