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

Commit 53bd5585 authored by David Anderson's avatar David Anderson Committed by Daniel Zheng
Browse files

libsnapshot: Implement CowWriterV3::EmitzeroBlocks.

Add zero block operation to writer v3. We currently write this operation
to after the scratch space. Once resume point support is added we may
need to change this to write after the resume point. This CL only
supports zero blocks, so writeoperation does not take in data yet.

Bug: 307452468
Test: cow_api_test
Change-Id: I659b2e2e4f6e0d96e374ed29012318cc34b4158d
parent ee35a818
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