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

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

Merge "libsnapshot: Add unit test to simulate merge-resume"

parents baa2ffe2 21afdd4d
Loading
Loading
Loading
Loading
+55 −3
Original line number Original line Diff line number Diff line
@@ -98,6 +98,7 @@ class CowSnapuserdTest final {
    void ValidateMerge();
    void ValidateMerge();
    void ReadSnapshotDeviceAndValidate();
    void ReadSnapshotDeviceAndValidate();
    void Shutdown();
    void Shutdown();
    void MergeInterrupt();


    std::string snapshot_dev() const { return snapshot_dev_->path(); }
    std::string snapshot_dev() const { return snapshot_dev_->path(); }


@@ -105,7 +106,11 @@ class CowSnapuserdTest final {


  private:
  private:
    void SetupImpl();
    void SetupImpl();

    void MergeImpl();
    void MergeImpl();
    void SimulateDaemonRestart();
    void StartMerge();

    void CreateCowDevice();
    void CreateCowDevice();
    void CreateBaseDevice();
    void CreateBaseDevice();
    void InitCowDevice();
    void InitCowDevice();
@@ -130,7 +135,7 @@ class CowSnapuserdTest final {
    std::unique_ptr<uint8_t[]> merged_buffer_;
    std::unique_ptr<uint8_t[]> merged_buffer_;
    bool setup_ok_ = false;
    bool setup_ok_ = false;
    bool merge_ok_ = false;
    bool merge_ok_ = false;
    size_t size_ = 1_MiB;
    size_t size_ = 50_MiB;
    int cow_num_sectors_;
    int cow_num_sectors_;
    int total_base_size_;
    int total_base_size_;
};
};
@@ -154,9 +159,13 @@ unique_fd CowSnapuserdTest::CreateTempFile(const std::string& name, size_t size)
}
}


void CowSnapuserdTest::Shutdown() {
void CowSnapuserdTest::Shutdown() {
    ASSERT_TRUE(client_->StopSnapuserd());
    ASSERT_TRUE(snapshot_dev_->Destroy());
    ASSERT_TRUE(snapshot_dev_->Destroy());
    ASSERT_TRUE(dmuser_dev_->Destroy());
    ASSERT_TRUE(dmuser_dev_->Destroy());

    auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
    ASSERT_TRUE(client_->WaitForDeviceDelete(system_device_ctrl_name_));
    ASSERT_TRUE(android::fs_mgr::WaitForFileDeleted(misc_device, 10s));
    ASSERT_TRUE(client_->DetachSnapuserd());
}
}


bool CowSnapuserdTest::Setup() {
bool CowSnapuserdTest::Setup() {
@@ -367,7 +376,7 @@ bool CowSnapuserdTest::Merge() {
    return merge_ok_;
    return merge_ok_;
}
}


void CowSnapuserdTest::MergeImpl() {
void CowSnapuserdTest::StartMerge() {
    DmTable merge_table;
    DmTable merge_table;
    ASSERT_TRUE(merge_table.AddTarget(std::make_unique<DmTargetSnapshot>(
    ASSERT_TRUE(merge_table.AddTarget(std::make_unique<DmTargetSnapshot>(
            0, total_base_size_ / kSectorSize, base_loop_->device(), dmuser_dev_->path(),
            0, total_base_size_ / kSectorSize, base_loop_->device(), dmuser_dev_->path(),
@@ -377,6 +386,11 @@ void CowSnapuserdTest::MergeImpl() {


    DeviceMapper& dm = DeviceMapper::Instance();
    DeviceMapper& dm = DeviceMapper::Instance();
    ASSERT_TRUE(dm.LoadTableAndActivate("cowsnapuserd-test-dm-snapshot", merge_table));
    ASSERT_TRUE(dm.LoadTableAndActivate("cowsnapuserd-test-dm-snapshot", merge_table));
}

void CowSnapuserdTest::MergeImpl() {
    StartMerge();
    DeviceMapper& dm = DeviceMapper::Instance();


    while (true) {
    while (true) {
        vector<DeviceMapper::TargetInfo> status;
        vector<DeviceMapper::TargetInfo> status;
@@ -405,6 +419,44 @@ void CowSnapuserdTest::ValidateMerge() {
    ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
    ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
}
}


void CowSnapuserdTest::SimulateDaemonRestart() {
    Shutdown();
    SetDeviceControlName();
    StartSnapuserdDaemon();
    InitCowDevice();
    CreateDmUserDevice();
    InitDaemon();
    CreateSnapshotDevice();
}

void CowSnapuserdTest::MergeInterrupt() {
    StartMerge();
    std::this_thread::sleep_for(4s);
    SimulateDaemonRestart();

    StartMerge();
    std::this_thread::sleep_for(3s);
    SimulateDaemonRestart();

    StartMerge();
    std::this_thread::sleep_for(3s);
    SimulateDaemonRestart();

    StartMerge();
    std::this_thread::sleep_for(1s);
    SimulateDaemonRestart();

    ASSERT_TRUE(Merge());
}

TEST(Snapuserd_Test, Snapshot_Merge_Resume) {
    CowSnapuserdTest harness;
    ASSERT_TRUE(harness.Setup());
    harness.MergeInterrupt();
    harness.ValidateMerge();
    harness.Shutdown();
}

TEST(Snapuserd_Test, Snapshot) {
TEST(Snapuserd_Test, Snapshot) {
    CowSnapuserdTest harness;
    CowSnapuserdTest harness;
    ASSERT_TRUE(harness.Setup());
    ASSERT_TRUE(harness.Setup());
+19 −12
Original line number Original line Diff line number Diff line
@@ -96,7 +96,7 @@ void Snapuserd::ConstructKernelCowHeader() {
// it will be de-compressed.
// it will be de-compressed.
bool Snapuserd::ProcessReplaceOp(const CowOperation* cow_op) {
bool Snapuserd::ProcessReplaceOp(const CowOperation* cow_op) {
    if (!reader_->ReadData(*cow_op, &bufsink_)) {
    if (!reader_->ReadData(*cow_op, &bufsink_)) {
        SNAP_LOG(ERROR) << "ReadData failed for chunk: " << cow_op->new_block;
        SNAP_LOG(ERROR) << "ProcessReplaceOp failed for block " << cow_op->new_block;
        return false;
        return false;
    }
    }


@@ -113,7 +113,8 @@ bool Snapuserd::ProcessCopyOp(const CowOperation* cow_op) {
    // if the successive blocks are contiguous.
    // if the successive blocks are contiguous.
    if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SIZE,
    if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SIZE,
                                          cow_op->source * BLOCK_SIZE)) {
                                          cow_op->source * BLOCK_SIZE)) {
        SNAP_LOG(ERROR) << "Copy-op failed. Read from backing store at: " << cow_op->source;
        SNAP_PLOG(ERROR) << "Copy-op failed. Read from backing store: " << backing_store_device_
                         << "at block :" << cow_op->source;
        return false;
        return false;
    }
    }


@@ -160,7 +161,7 @@ int Snapuserd::ReadUnalignedSector(sector_t sector, size_t size,
                    << " Aligned sector: " << it->second;
                    << " Aligned sector: " << it->second;


    if (!ProcessCowOp(it->second)) {
    if (!ProcessCowOp(it->second)) {
        SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed";
        SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size;
        return -1;
        return -1;
    }
    }


@@ -377,16 +378,21 @@ int Snapuserd::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffer,
            CHECK(cow_de->new_chunk == 0);
            CHECK(cow_de->new_chunk == 0);
            break;
            break;
        } else {
        } else {
            SNAP_LOG(ERROR) << "Error in merge operation. Found invalid metadata";
            SNAP_LOG(ERROR) << "Error in merge operation. Found invalid metadata: "
            SNAP_LOG(ERROR) << "merged_de-old-chunk: " << merged_de->old_chunk;
                            << " merged_de-old-chunk: " << merged_de->old_chunk
            SNAP_LOG(ERROR) << "merged_de-new-chunk: " << merged_de->new_chunk;
                            << " merged_de-new-chunk: " << merged_de->new_chunk
            SNAP_LOG(ERROR) << "cow_de-old-chunk: " << cow_de->old_chunk;
                            << " cow_de-old-chunk: " << cow_de->old_chunk
            SNAP_LOG(ERROR) << "cow_de-new-chunk: " << cow_de->new_chunk;
                            << " cow_de-new-chunk: " << cow_de->new_chunk
                            << " unmerged_exceptions: " << unmerged_exceptions
                            << " merged_ops_cur_iter: " << merged_ops_cur_iter
                            << " offset: " << offset;
            return -1;
            return -1;
        }
        }
    }
    }


    if (*copy_op) {
    if (*copy_op) {
        SNAP_LOG(ERROR) << "Invalid batch merge of copy ops: merged_ops_cur_iter: "
                        << merged_ops_cur_iter;
        CHECK(merged_ops_cur_iter == 1);
        CHECK(merged_ops_cur_iter == 1);
    }
    }
    return merged_ops_cur_iter;
    return merged_ops_cur_iter;
@@ -446,7 +452,7 @@ bool Snapuserd::ProcessMergeComplete(chunk_t chunk, void* buffer) {
    header.num_merge_ops += merged_ops_cur_iter;
    header.num_merge_ops += merged_ops_cur_iter;
    reader_->UpdateMergeProgress(merged_ops_cur_iter);
    reader_->UpdateMergeProgress(merged_ops_cur_iter);
    if (!writer_->CommitMerge(merged_ops_cur_iter, copy_op)) {
    if (!writer_->CommitMerge(merged_ops_cur_iter, copy_op)) {
        SNAP_LOG(ERROR) << "CommitMerge failed...";
        SNAP_LOG(ERROR) << "CommitMerge failed... merged_ops_cur_iter: " << merged_ops_cur_iter;
        return false;
        return false;
    }
    }


@@ -661,7 +667,7 @@ bool Snapuserd::ReadDmUserHeader() {
bool Snapuserd::WriteDmUserPayload(size_t size) {
bool Snapuserd::WriteDmUserPayload(size_t size) {
    if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
    if (!android::base::WriteFully(ctrl_fd_, bufsink_.GetBufPtr(),
                                   sizeof(struct dm_user_header) + size)) {
                                   sizeof(struct dm_user_header) + size)) {
        SNAP_PLOG(ERROR) << "Write to dm-user failed";
        SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << size;
        return false;
        return false;
    }
    }


@@ -670,7 +676,7 @@ bool Snapuserd::WriteDmUserPayload(size_t size) {


bool Snapuserd::ReadDmUserPayload(void* buffer, size_t size) {
bool Snapuserd::ReadDmUserPayload(void* buffer, size_t size) {
    if (!android::base::ReadFully(ctrl_fd_, buffer, size)) {
    if (!android::base::ReadFully(ctrl_fd_, buffer, size)) {
        SNAP_PLOG(ERROR) << "ReadDmUserPayload failed";
        SNAP_PLOG(ERROR) << "ReadDmUserPayload failed size: " << size;
        return false;
        return false;
    }
    }


@@ -808,7 +814,8 @@ bool Snapuserd::DmuserReadRequest() {
                ret = ReadData(sector + num_sectors_read, read_size);
                ret = ReadData(sector + num_sectors_read, read_size);
                if (ret < 0) {
                if (ret < 0) {
                    SNAP_LOG(ERROR) << "ReadData failed for chunk id: " << chunk
                    SNAP_LOG(ERROR) << "ReadData failed for chunk id: " << chunk
                                    << "Sector: " << header->sector;
                                    << " Sector: " << (sector + num_sectors_read)
                                    << " size: " << read_size << " header-len: " << header->len;
                    header->type = DM_USER_RESP_ERROR;
                    header->type = DM_USER_RESP_ERROR;
                } else {
                } else {
                    SNAP_LOG(DEBUG) << "ReadData success for chunk id: " << chunk
                    SNAP_LOG(DEBUG) << "ReadData success for chunk id: " << chunk