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

Commit dd58ffd1 authored by Akilesh Kailash's avatar Akilesh Kailash Committed by Gerrit Code Review
Browse files

Merge changes I1dc28606,I4d77c435

* changes:
  libsnapshot:VABC: Allow batch merge
  libsnaphot: Refactor cow_snapuserd test
parents e248d1fa 37641374
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -563,6 +563,7 @@ cc_test {
        "libsnapshot_snapuserd",
        "libcutils_sockets",
        "libz",
	"libfs_mgr",
        "libdm",
    ],
    header_libs: [
+127 −18
Original line number Diff line number Diff line
@@ -189,27 +189,136 @@ bool CowReader::ParseOps(std::optional<uint64_t> label) {
        LOG(INFO) << "No COW Footer, recovered data";
    }

    if (header_.num_merge_ops > 0) {
        uint64_t merge_ops = header_.num_merge_ops;
        uint64_t metadata_ops = 0;
        uint64_t current_op_num = 0;

        CHECK(ops_buffer->size() >= merge_ops);
        while (merge_ops) {
            auto& current_op = ops_buffer->data()[current_op_num];
            if (current_op.type == kCowLabelOp || current_op.type == kCowFooterOp) {
                metadata_ops += 1;
            } else {
                merge_ops -= 1;
    ops_ = ops_buffer;
    return true;
}
            current_op_num += 1;

void CowReader::InitializeMerge() {
    uint64_t num_copy_ops = 0;

    // Remove all the metadata operations
    ops_->erase(std::remove_if(ops_.get()->begin(), ops_.get()->end(),
                               [](CowOperation& op) {
                                   return (op.type == kCowFooterOp || op.type == kCowLabelOp);
                               }),
                ops_.get()->end());

    // We will re-arrange the vector in such a way that
    // kernel can batch merge. Ex:
    //
    // Existing COW format; All the copy operations
    // are at the beginning.
    // =======================================
    // Copy-op-1    - cow_op->new_block = 1
    // Copy-op-2    - cow_op->new_block = 2
    // Copy-op-3    - cow_op->new_block = 3
    // Replace-op-4 - cow_op->new_block = 6
    // Replace-op-5 - cow_op->new_block = 4
    // Replace-op-6 - cow_op->new_block = 8
    // Replace-op-7 - cow_op->new_block = 9
    // Zero-op-8    - cow_op->new_block = 7
    // Zero-op-9    - cow_op->new_block = 5
    // =======================================
    //
    // First find the operation which isn't a copy-op
    // and then sort all the operations in descending order
    // with the key being cow_op->new_block (source block)
    //
    // The data-structure will look like:
    //
    // =======================================
    // Copy-op-1    - cow_op->new_block = 1
    // Copy-op-2    - cow_op->new_block = 2
    // Copy-op-3    - cow_op->new_block = 3
    // Replace-op-7 - cow_op->new_block = 9
    // Replace-op-6 - cow_op->new_block = 8
    // Zero-op-8    - cow_op->new_block = 7
    // Replace-op-4 - cow_op->new_block = 6
    // Zero-op-9    - cow_op->new_block = 5
    // Replace-op-5 - cow_op->new_block = 4
    // =======================================
    //
    // Daemon will read the above data-structure in reverse-order
    // when reading metadata. Thus, kernel will get the metadata
    // in the following order:
    //
    // ========================================
    // Replace-op-5 - cow_op->new_block = 4
    // Zero-op-9    - cow_op->new_block = 5
    // Replace-op-4 - cow_op->new_block = 6
    // Zero-op-8    - cow_op->new_block = 7
    // Replace-op-6 - cow_op->new_block = 8
    // Replace-op-7 - cow_op->new_block = 9
    // Copy-op-3    - cow_op->new_block = 3
    // Copy-op-2    - cow_op->new_block = 2
    // Copy-op-1    - cow_op->new_block = 1
    // ===========================================
    //
    // When merging begins, kernel will start from the last
    // metadata which was read: In the above format, Copy-op-1
    // will be the first merge operation.
    //
    // Now, batching of the merge operations happens only when
    // 1: origin block numbers in the base device are contiguous
    // (cow_op->new_block) and,
    // 2: cow block numbers which are assigned by daemon in ReadMetadata()
    // are contiguous. These are monotonically increasing numbers.
    //
    // When both (1) and (2) are true, kernel will batch merge the operations.
    // However, we do not want copy operations to be batch merged as
    // a crash or system reboot during an overlapping copy can drive the device
    // to a corrupted state. Hence, merging of copy operations should always be
    // done as a individual 4k block. In the above case, since the
    // cow_op->new_block numbers are contiguous, we will ensure that the
    // cow block numbers assigned in ReadMetadata() for these respective copy
    // operations are not contiguous forcing kernel to issue merge for each
    // copy operations without batch merging.
    //
    // For all the other operations viz. Replace and Zero op, the cow block
    // numbers assigned by daemon will be contiguous allowing kernel to batch
    // merge.
    //
    // The final format after assiging COW block numbers by the daemon will
    // look something like:
    //
    // =========================================================
    // Replace-op-5 - cow_op->new_block = 4  cow-block-num = 2
    // Zero-op-9    - cow_op->new_block = 5  cow-block-num = 3
    // Replace-op-4 - cow_op->new_block = 6  cow-block-num = 4
    // Zero-op-8    - cow_op->new_block = 7  cow-block-num = 5
    // Replace-op-6 - cow_op->new_block = 8  cow-block-num = 6
    // Replace-op-7 - cow_op->new_block = 9  cow-block-num = 7
    // Copy-op-3    - cow_op->new_block = 3  cow-block-num = 9
    // Copy-op-2    - cow_op->new_block = 2  cow-block-num = 11
    // Copy-op-1    - cow_op->new_block = 1  cow-block-num = 13
    // ==========================================================
    //
    // Merge sequence will look like:
    //
    // Merge-1 - Copy-op-1
    // Merge-2 - Copy-op-2
    // Merge-3 - Copy-op-3
    // Merge-4 - Batch-merge {Replace-op-7, Replace-op-6, Zero-op-8,
    //                        Replace-op-4, Zero-op-9, Replace-op-5 }
    //==============================================================

    for (uint64_t i = 0; i < ops_->size(); i++) {
        auto& current_op = ops_->data()[i];
        if (current_op.type != kCowCopyOp) {
            break;
        }
        ops_buffer->erase(ops_buffer.get()->begin(),
                          ops_buffer.get()->begin() + header_.num_merge_ops + metadata_ops);
        num_copy_ops += 1;
    }

    ops_ = ops_buffer;
    return true;
    std::sort(ops_.get()->begin() + num_copy_ops, ops_.get()->end(),
              [](CowOperation& op1, CowOperation& op2) -> bool {
                  return op1.new_block > op2.new_block;
              });

    if (header_.num_merge_ops > 0) {
        CHECK(ops_->size() >= header_.num_merge_ops);
        ops_->erase(ops_.get()->begin(), ops_.get()->begin() + header_.num_merge_ops);
    }
}

bool CowReader::GetHeader(CowHeader* header) {
+276 −323

File changed.

Preview size limit exceeded, changes collapsed.

+6 −2
Original line number Diff line number Diff line
@@ -421,7 +421,7 @@ bool CowWriter::Sync() {
    return true;
}

bool CowWriter::CommitMerge(int merged_ops) {
bool CowWriter::CommitMerge(int merged_ops, bool sync) {
    CHECK(merge_in_progress_);
    header_.num_merge_ops += merged_ops;

@@ -436,8 +436,12 @@ bool CowWriter::CommitMerge(int merged_ops) {
        return false;
    }

    // Sync only for merging of copy operations.
    if (sync) {
        return Sync();
    }
    return true;
}

bool CowWriter::Truncate(off_t length) {
    if (is_dev_null_ || is_block_device_) {
+2 −0
Original line number Diff line number Diff line
@@ -140,6 +140,8 @@ class CowReader : public ICowReader {

    void UpdateMergeProgress(uint64_t merge_ops) { header_.num_merge_ops += merge_ops; }

    void InitializeMerge();

  private:
    bool ParseOps(std::optional<uint64_t> label);

Loading