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

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

Merge "libsnapshot: Implement CowWriterV3::EmitzeroBlocks." into main

parents cdb935e9 53bd5585
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -145,6 +145,7 @@ class CowReader final : public ICowReader {
                     size_t ignore_bytes = 0) override;

    CowHeader& GetHeader() override { return header_; }
    const CowHeaderV3& header_v3() const { return header_; }

    bool GetRawBytes(const CowOperation* op, void* buffer, size_t len, size_t* read);
    bool GetRawBytes(uint64_t offset, void* buffer, size_t len, size_t* read);
+3 −0
Original line number Diff line number Diff line
@@ -54,6 +54,9 @@ struct CowOptions {

    // Batch write cluster ops
    bool batch_write = false;

    // Size of the cow operation buffer; used in v3 only.
    uint32_t op_count_max = 0;
};

// Interface for writing to a snapuserd COW. All operations are ordered; merges
+31 −0
Original line number Diff line number Diff line
@@ -89,5 +89,36 @@ TEST_F(CowTestV3, Header) {
    ASSERT_EQ(header.cluster_ops, 0);
}

TEST_F(CowTestV3, ZeroOp) {
    CowOptions options;
    options.op_count_max = 20;
    auto writer = CreateCowWriter(3, options, GetCowFd());
    ASSERT_TRUE(writer->AddZeroBlocks(1, 2));
    ASSERT_TRUE(writer->Finalize());

    CowReader reader;
    ASSERT_TRUE(reader.Parse(cow_->fd));
    ASSERT_EQ(reader.header_v3().op_count, 2);

    auto iter = reader.GetOpIter();
    ASSERT_NE(iter, nullptr);
    ASSERT_FALSE(iter->AtEnd());

    auto op = iter->Get();
    ASSERT_EQ(op->type, kCowZeroOp);
    ASSERT_EQ(op->data_length, 0);
    ASSERT_EQ(op->new_block, 1);
    ASSERT_EQ(op->source_info, 0);

    iter->Next();
    ASSERT_FALSE(iter->AtEnd());
    op = iter->Get();

    ASSERT_EQ(op->type, kCowZeroOp);
    ASSERT_EQ(op->data_length, 0);
    ASSERT_EQ(op->new_block, 2);
    ASSERT_EQ(op->source_info, 0);
}

}  // namespace snapshot
}  // namespace android
+2 −0
Original line number Diff line number Diff line
@@ -62,6 +62,8 @@ class CowWriterBase : public ICowWriter {
    bool InitFd();
    bool ValidateNewBlock(uint64_t new_block);

    bool IsEstimating() const { return is_dev_null_; }

    CowOptions options_;

    android::base::unique_fd fd_;
+38 −3
Original line number Diff line number Diff line
@@ -155,6 +155,7 @@ bool CowWriterV3::OpenForWrite() {
            return false;
        }
    }
    header_.op_count_max = options_.op_count_max;

    if (!Sync()) {
        LOG(ERROR) << "Header sync failed";
@@ -184,10 +185,18 @@ bool CowWriterV3::EmitXorBlocks(uint32_t new_block_start, const void* data, size
}

bool CowWriterV3::EmitZeroBlocks(uint64_t new_block_start, uint64_t num_blocks) {
    LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
    if (new_block_start && num_blocks) return false;
    for (uint64_t i = 0; i < num_blocks; i++) {
        CowOperationV3 op;
        op.type = kCowZeroOp;
        op.data_length = 0;
        op.new_block = new_block_start + i;
        op.source_info = 0;
        if (!WriteOperation(op)) {
            return false;
        }
    }
    return true;
}

bool CowWriterV3::EmitLabel(uint64_t label) {
    LOG(ERROR) << __LINE__ << " " << __FILE__ << " <- function here should never be called";
@@ -201,7 +210,33 @@ bool CowWriterV3::EmitSequenceData(size_t num_ops, const uint32_t* data) {
    return false;
}

bool CowWriterV3::WriteOperation(const CowOperationV3& op) {
    if (IsEstimating()) {
        header_.op_count++;
        header_.op_count_max++;
        return true;
    }

    if (header_.op_count + 1 > header_.op_count_max) {
        LOG(ERROR) << "Maximum number of ops reached: " << header_.op_count_max;
        return false;
    }

    const off_t offset = GetOpOffset(header_.op_count);
    if (!android::base::WriteFullyAtOffset(fd_, &op, sizeof(op), offset)) {
        return false;
    }

    header_.op_count++;
    return true;
}

bool CowWriterV3::Finalize() {
    CHECK_GE(header_.prefix.header_size, sizeof(CowHeaderV3));
    CHECK_LE(header_.prefix.header_size, sizeof(header_));
    if (!android::base::WriteFullyAtOffset(fd_, &header_, header_.prefix.header_size, 0)) {
        return false;
    }
    return Sync();
}

Loading