snapuserd: Remove legacy dm-snapshot based snapshot and snapshot-merge

Clean up all the legacy dm-snapshot based approach.

This will continue to maintain backward compatibility with vendor
partition on Android S.

Bug: 304829384
Test: OTA on Pixel
th - OTA from Android S to TOT with vendor on S
Change-Id: Id9263be881dd1a06923cd0ace007f1c027e6969d
Signed-off-by: Akilesh Kailash <akailash@google.com>
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 5ceaf28..914b4a6 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -322,24 +322,6 @@
 }
 
 cc_test {
-    name: "vabc_legacy_tests",
-    defaults: [
-        "libsnapshot_test_defaults",
-        "libsnapshot_hal_deps",
-    ],
-    cppflags: [
-        "-DLIBSNAPSHOT_TEST_VABC_LEGACY",
-    ],
-    test_suites: [
-        "device-tests",
-    ],
-    test_options: {
-        // Legacy VABC launched in Android S.
-        min_shipping_api_level: 31,
-    },
-}
-
-cc_test {
     name: "vts_ota_config_test",
     srcs: [
         "vts_ota_config_test.cpp",
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index 47e6ce9..8d0c898 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -56,14 +56,12 @@
 
 #if defined(LIBSNAPSHOT_TEST_VAB_LEGACY)
 #define DEFAULT_MODE "vab-legacy"
-#elif defined(LIBSNAPSHOT_TEST_VABC_LEGACY)
-#define DEFAULT_MODE "vabc-legacy"
 #else
 #define DEFAULT_MODE ""
 #endif
 
 DEFINE_string(force_mode, DEFAULT_MODE,
-              "Force testing older modes (vab-legacy, vabc-legacy) ignoring device config.");
+              "Force testing older modes (vab-legacy) ignoring device config.");
 DEFINE_string(force_iouring_disable, "",
               "Force testing mode (iouring_disabled) - disable io_uring");
 DEFINE_string(compression_method, "gz", "Default compression algorithm.");
@@ -140,17 +138,10 @@
     void SetupProperties() {
         std::unordered_map<std::string, std::string> properties;
 
-        ASSERT_TRUE(android::base::SetProperty("snapuserd.test.dm.snapshots", "0"))
-                << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
         ASSERT_TRUE(android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0"))
                 << "Failed to set property: snapuserd.test.io_uring.disabled";
 
-        if (FLAGS_force_mode == "vabc-legacy") {
-            ASSERT_TRUE(android::base::SetProperty("snapuserd.test.dm.snapshots", "1"))
-                    << "Failed to disable property: virtual_ab.userspace.snapshots.enabled";
-            properties["ro.virtual_ab.compression.enabled"] = "true";
-            properties["ro.virtual_ab.userspace.snapshots.enabled"] = "false";
-        } else if (FLAGS_force_mode == "vab-legacy") {
+        if (FLAGS_force_mode == "vab-legacy") {
             properties["ro.virtual_ab.compression.enabled"] = "false";
             properties["ro.virtual_ab.userspace.snapshots.enabled"] = "false";
         }
@@ -2894,7 +2885,7 @@
 
     android::base::SetProperty("ctl.stop", "snapuserd");
 
-    std::unordered_set<std::string> modes = {"", "vab-legacy", "vabc-legacy"};
+    std::unordered_set<std::string> modes = {"", "vab-legacy"};
     if (modes.count(FLAGS_force_mode) == 0) {
         std::cerr << "Unexpected force_config argument\n";
         return 1;
@@ -2905,7 +2896,6 @@
 
     int ret = RUN_ALL_TESTS();
 
-    android::base::SetProperty("snapuserd.test.dm.snapshots", "0");
     android::base::SetProperty("snapuserd.test.io_uring.force_disable", "0");
 
     android::snapshot::KillSnapuserd();
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index bd296a3..649309d 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -59,9 +59,6 @@
     ],
     local_include_dirs: ["include/"],
     srcs: [
-        "dm-snapshot-merge/snapuserd.cpp",
-        "dm-snapshot-merge/snapuserd_readahead.cpp",
-        "dm-snapshot-merge/snapuserd_worker.cpp",
         "dm_user_block_server.cpp",
         "snapuserd_buffer.cpp",
         "user-space-merge/handler_manager.cpp",
@@ -109,7 +106,6 @@
         "fs_mgr_defaults",
     ],
     srcs: [
-        "dm-snapshot-merge/snapuserd_server.cpp",
         "snapuserd_daemon.cpp",
         "user-space-merge/snapuserd_server.cpp",
     ],
@@ -190,45 +186,6 @@
     symlinks: ["snapuserd"],
 }
 
-cc_test {
-    name: "snapuserd_test_legacy",
-    defaults: [
-        "fs_mgr_defaults",
-        "libsnapshot_cow_defaults",
-    ],
-    srcs: [
-        "dm-snapshot-merge/cow_snapuserd_test.cpp",
-        "dm-snapshot-merge/snapuserd.cpp",
-        "dm-snapshot-merge/snapuserd_worker.cpp",
-        "snapuserd_buffer.cpp",
-    ],
-    shared_libs: [
-        "libbase",
-        "liblog",
-    ],
-    static_libs: [
-        "libbrotli",
-        "libgtest",
-        "libsnapshot_cow",
-        "libsnapuserd_client",
-        "libcutils_sockets",
-        "libz",
-        "libdm",
-        "libext2_uuid",
-        "libext4_utils",
-        "libfs_mgr_file_wait",
-    ],
-    header_libs: [
-        "libstorage_literals_headers",
-        "libfiemap_headers",
-    ],
-    test_options: {
-        min_shipping_api_level: 30,
-    },
-    auto_gen_config: true,
-    require_root: false,
-}
-
 cc_defaults {
     name: "snapuserd_test_defaults",
     defaults: [
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
deleted file mode 100644
index 737c480..0000000
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/cow_snapuserd_test.cpp
+++ /dev/null
@@ -1,1238 +0,0 @@
-// Copyright (C) 2018 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#include <fcntl.h>
-#include <linux/fs.h>
-#include <linux/memfd.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/syscall.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <chrono>
-#include <iostream>
-#include <memory>
-#include <string_view>
-
-#include <android-base/file.h>
-#include <android-base/unique_fd.h>
-#include <fs_mgr/file_wait.h>
-#include <gtest/gtest.h>
-#include <libdm/dm.h>
-#include <libdm/loop_control.h>
-#include <libsnapshot/cow_writer.h>
-#include <snapuserd/snapuserd_buffer.h>
-#include <snapuserd/snapuserd_client.h>
-#include <storage_literals/storage_literals.h>
-
-#include "snapuserd.h"
-
-namespace android {
-namespace snapshot {
-
-using namespace android::storage_literals;
-using android::base::unique_fd;
-using LoopDevice = android::dm::LoopDevice;
-using namespace std::chrono_literals;
-using namespace android::dm;
-using namespace std;
-
-static constexpr char kSnapuserdSocketTest[] = "snapuserdTest";
-
-class TempDevice {
-  public:
-    TempDevice(const std::string& name, const DmTable& table)
-        : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
-        valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5));
-    }
-    TempDevice(TempDevice&& other) noexcept
-        : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
-        other.valid_ = false;
-    }
-    ~TempDevice() {
-        if (valid_) {
-            dm_.DeleteDevice(name_);
-        }
-    }
-    bool Destroy() {
-        if (!valid_) {
-            return false;
-        }
-        valid_ = false;
-        return dm_.DeleteDevice(name_);
-    }
-    const std::string& path() const { return path_; }
-    const std::string& name() const { return name_; }
-    bool valid() const { return valid_; }
-
-    TempDevice(const TempDevice&) = delete;
-    TempDevice& operator=(const TempDevice&) = delete;
-
-    TempDevice& operator=(TempDevice&& other) noexcept {
-        name_ = other.name_;
-        valid_ = other.valid_;
-        other.valid_ = false;
-        return *this;
-    }
-
-  private:
-    DeviceMapper& dm_;
-    std::string name_;
-    std::string path_;
-    bool valid_;
-};
-
-class CowSnapuserdTest final {
-  public:
-    bool Setup();
-    bool SetupOrderedOps();
-    bool SetupOrderedOpsInverted();
-    bool SetupCopyOverlap_1();
-    bool SetupCopyOverlap_2();
-    bool Merge();
-    void ValidateMerge();
-    void ReadSnapshotDeviceAndValidate();
-    void Shutdown();
-    void MergeInterrupt();
-    void MergeInterruptFixed(int duration);
-    void MergeInterruptRandomly(int max_duration);
-    void ReadDmUserBlockWithoutDaemon();
-    void ReadLastBlock();
-
-    std::string snapshot_dev() const { return snapshot_dev_->path(); }
-
-    static const uint64_t kSectorSize = 512;
-
-  private:
-    void SetupImpl();
-
-    void MergeImpl();
-    void SimulateDaemonRestart();
-    void StartMerge();
-
-    std::unique_ptr<ICowWriter> CreateCowDeviceInternal();
-    void CreateCowDevice();
-    void CreateCowDeviceOrderedOps();
-    void CreateCowDeviceOrderedOpsInverted();
-    void CreateCowDeviceWithCopyOverlap_1();
-    void CreateCowDeviceWithCopyOverlap_2();
-    bool SetupDaemon();
-    void CreateBaseDevice();
-    void InitCowDevice();
-    void SetDeviceControlName();
-    void InitDaemon();
-    void CreateDmUserDevice();
-    void StartSnapuserdDaemon();
-    void CreateSnapshotDevice();
-
-    unique_ptr<LoopDevice> base_loop_;
-    unique_ptr<TempDevice> dmuser_dev_;
-    unique_ptr<TempDevice> snapshot_dev_;
-
-    std::string system_device_ctrl_name_;
-    std::string system_device_name_;
-
-    unique_fd base_fd_;
-    std::unique_ptr<TemporaryFile> cow_system_;
-    std::unique_ptr<SnapuserdClient> client_;
-    std::unique_ptr<uint8_t[]> orig_buffer_;
-    std::unique_ptr<uint8_t[]> merged_buffer_;
-    bool setup_ok_ = false;
-    bool merge_ok_ = false;
-    size_t size_ = 50_MiB;
-    int cow_num_sectors_;
-    int total_base_size_;
-};
-
-class CowSnapuserdMetadataTest final {
-  public:
-    void Setup();
-    void SetupPartialArea();
-    void ValidateMetadata();
-    void ValidatePartialFilledArea();
-
-  private:
-    void InitMetadata();
-    std::unique_ptr<ICowWriter> CreateCowDeviceInternal();
-    void CreateCowDevice();
-    void CreateCowPartialFilledArea();
-
-    std::unique_ptr<Snapuserd> snapuserd_;
-    std::unique_ptr<TemporaryFile> cow_system_;
-    size_t size_ = 1_MiB;
-};
-
-static unique_fd CreateTempFile(const std::string& name, size_t size) {
-    unique_fd fd(syscall(__NR_memfd_create, name.c_str(), MFD_ALLOW_SEALING));
-    if (fd < 0) {
-        return {};
-    }
-    if (size) {
-        if (ftruncate(fd, size) < 0) {
-            perror("ftruncate");
-            return {};
-        }
-        if (fcntl(fd, F_ADD_SEALS, F_SEAL_GROW | F_SEAL_SHRINK) < 0) {
-            perror("fcntl");
-            return {};
-        }
-    }
-    return fd;
-}
-
-void CowSnapuserdTest::Shutdown() {
-    ASSERT_TRUE(snapshot_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() {
-    SetupImpl();
-    return setup_ok_;
-}
-
-bool CowSnapuserdTest::SetupOrderedOps() {
-    CreateBaseDevice();
-    CreateCowDeviceOrderedOps();
-    return SetupDaemon();
-}
-
-bool CowSnapuserdTest::SetupOrderedOpsInverted() {
-    CreateBaseDevice();
-    CreateCowDeviceOrderedOpsInverted();
-    return SetupDaemon();
-}
-
-bool CowSnapuserdTest::SetupCopyOverlap_1() {
-    CreateBaseDevice();
-    CreateCowDeviceWithCopyOverlap_1();
-    return SetupDaemon();
-}
-
-bool CowSnapuserdTest::SetupCopyOverlap_2() {
-    CreateBaseDevice();
-    CreateCowDeviceWithCopyOverlap_2();
-    return SetupDaemon();
-}
-
-bool CowSnapuserdTest::SetupDaemon() {
-    SetDeviceControlName();
-
-    StartSnapuserdDaemon();
-    InitCowDevice();
-
-    CreateDmUserDevice();
-    InitDaemon();
-
-    CreateSnapshotDevice();
-    setup_ok_ = true;
-
-    return setup_ok_;
-}
-
-void CowSnapuserdTest::StartSnapuserdDaemon() {
-    pid_t pid = fork();
-    ASSERT_GE(pid, 0);
-    if (pid == 0) {
-        std::string arg0 = "/system/bin/snapuserd";
-        std::string arg1 = "-socket="s + kSnapuserdSocketTest;
-        char* const argv[] = {arg0.data(), arg1.data(), nullptr};
-        ASSERT_GE(execv(arg0.c_str(), argv), 0);
-    } else {
-        client_ = SnapuserdClient::Connect(kSnapuserdSocketTest, 10s);
-        ASSERT_NE(client_, nullptr);
-    }
-}
-
-std::unique_ptr<ICowWriter> CowSnapuserdTest::CreateCowDeviceInternal() {
-    std::string path = android::base::GetExecutableDirectory();
-    cow_system_ = std::make_unique<TemporaryFile>(path);
-
-    CowOptions options;
-    options.compression = "gz";
-
-    unique_fd fd(cow_system_->fd);
-    cow_system_->fd = -1;
-
-    return CreateCowWriter(kDefaultCowVersion, options, std::move(fd));
-}
-
-void CowSnapuserdTest::ReadLastBlock() {
-    unique_fd rnd_fd;
-    total_base_size_ = BLOCK_SZ * 2;
-
-    base_fd_ = CreateTempFile("base_device", total_base_size_);
-    ASSERT_GE(base_fd_, 0);
-
-    rnd_fd.reset(open("/dev/random", O_RDONLY));
-    ASSERT_TRUE(rnd_fd > 0);
-
-    std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(BLOCK_SZ);
-
-    for (size_t j = 0; j < ((total_base_size_) / BLOCK_SZ); j++) {
-        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), BLOCK_SZ, 0), true);
-        ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), BLOCK_SZ), true);
-    }
-
-    ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
-
-    base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
-    ASSERT_TRUE(base_loop_->valid());
-
-    std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(total_base_size_);
-    loff_t offset = 0;
-
-    // Fill random data
-    for (size_t j = 0; j < (total_base_size_ / BLOCK_SZ); j++) {
-        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, BLOCK_SZ, 0),
-                  true);
-
-        offset += BLOCK_SZ;
-    }
-
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    ASSERT_TRUE(writer->AddRawBlocks(0, random_buffer_1_.get(), BLOCK_SZ));
-    ASSERT_TRUE(writer->AddRawBlocks(1, (char*)random_buffer_1_.get() + BLOCK_SZ, BLOCK_SZ));
-
-    ASSERT_TRUE(writer->Finalize());
-
-    SetDeviceControlName();
-
-    StartSnapuserdDaemon();
-    InitCowDevice();
-
-    CreateDmUserDevice();
-    InitDaemon();
-
-    CreateSnapshotDevice();
-
-    unique_fd snapshot_fd(open(snapshot_dev_->path().c_str(), O_RDONLY));
-    ASSERT_TRUE(snapshot_fd > 0);
-
-    std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(BLOCK_SZ);
-
-    offset = 7680;
-    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), 512, offset), true);
-    ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)random_buffer_1_.get() + offset, 512), 0);
-}
-
-void CowSnapuserdTest::CreateBaseDevice() {
-    unique_fd rnd_fd;
-
-    total_base_size_ = (size_ * 5);
-    base_fd_ = CreateTempFile("base_device", total_base_size_);
-    ASSERT_GE(base_fd_, 0);
-
-    rnd_fd.reset(open("/dev/random", O_RDONLY));
-    ASSERT_TRUE(rnd_fd > 0);
-
-    std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
-
-    for (size_t j = 0; j < ((total_base_size_) / 1_MiB); j++) {
-        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
-        ASSERT_EQ(android::base::WriteFully(base_fd_, random_buffer.get(), 1_MiB), true);
-    }
-
-    ASSERT_EQ(lseek(base_fd_, 0, SEEK_SET), 0);
-
-    base_loop_ = std::make_unique<LoopDevice>(base_fd_, 10s);
-    ASSERT_TRUE(base_loop_->valid());
-}
-
-void CowSnapuserdTest::ReadSnapshotDeviceAndValidate() {
-    unique_fd snapshot_fd(open(snapshot_dev_->path().c_str(), O_RDONLY));
-    ASSERT_TRUE(snapshot_fd > 0);
-
-    std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
-
-    // COPY
-    loff_t offset = 0;
-    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
-    ASSERT_EQ(memcmp(snapuserd_buffer.get(), orig_buffer_.get(), size_), 0);
-
-    // REPLACE
-    offset += size_;
-    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
-    ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + size_, size_), 0);
-
-    // ZERO
-    offset += size_;
-    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
-    ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 2), size_), 0);
-
-    // REPLACE
-    offset += size_;
-    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
-    ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 3), size_), 0);
-
-    // XOR
-    offset += size_;
-    ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
-    ASSERT_EQ(memcmp(snapuserd_buffer.get(), (char*)orig_buffer_.get() + (size_ * 4), size_), 0);
-}
-
-void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_2() {
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    size_t num_blocks = size_ / writer->GetBlockSize();
-    size_t x = num_blocks;
-    size_t blk_src_copy = 0;
-
-    // Create overlapping copy operations
-    while (1) {
-        ASSERT_TRUE(writer->AddCopy(blk_src_copy, blk_src_copy + 1));
-        x -= 1;
-        if (x == 1) {
-            break;
-        }
-        blk_src_copy += 1;
-    }
-
-    // Flush operations
-    ASSERT_TRUE(writer->Finalize());
-
-    // Construct the buffer required for validation
-    orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-
-    // Read the entire base device
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
-              true);
-
-    // Merged operations required for validation
-    int block_size = 4096;
-    x = num_blocks;
-    loff_t src_offset = block_size;
-    loff_t dest_offset = 0;
-
-    while (1) {
-        memmove((char*)orig_buffer_.get() + dest_offset, (char*)orig_buffer_.get() + src_offset,
-                block_size);
-        x -= 1;
-        if (x == 1) {
-            break;
-        }
-        src_offset += block_size;
-        dest_offset += block_size;
-    }
-}
-
-void CowSnapuserdTest::CreateCowDeviceWithCopyOverlap_1() {
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    size_t num_blocks = size_ / writer->GetBlockSize();
-    size_t x = num_blocks;
-    size_t blk_src_copy = num_blocks - 1;
-
-    // Create overlapping copy operations
-    while (1) {
-        ASSERT_TRUE(writer->AddCopy(blk_src_copy + 1, blk_src_copy));
-        x -= 1;
-        if (x == 0) {
-            ASSERT_EQ(blk_src_copy, 0);
-            break;
-        }
-        blk_src_copy -= 1;
-    }
-
-    // Flush operations
-    ASSERT_TRUE(writer->Finalize());
-
-    // Construct the buffer required for validation
-    orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-
-    // Read the entire base device
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
-              true);
-
-    // Merged operations
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), writer->GetBlockSize(),
-                                               0),
-              true);
-    ASSERT_EQ(android::base::ReadFullyAtOffset(
-                      base_fd_, (char*)orig_buffer_.get() + writer->GetBlockSize(), size_, 0),
-              true);
-}
-
-void CowSnapuserdTest::CreateCowDeviceOrderedOpsInverted() {
-    unique_fd rnd_fd;
-    loff_t offset = 0;
-
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    rnd_fd.reset(open("/dev/random", O_RDONLY));
-    ASSERT_TRUE(rnd_fd > 0);
-
-    std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
-
-    // Fill random data
-    for (size_t j = 0; j < (size_ / 1_MiB); j++) {
-        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
-                  true);
-
-        offset += 1_MiB;
-    }
-
-    size_t num_blocks = size_ / writer->GetBlockSize();
-    size_t blk_end_copy = num_blocks * 3;
-    size_t source_blk = num_blocks - 1;
-    size_t blk_src_copy = blk_end_copy - 1;
-    uint16_t xor_offset = 5;
-
-    size_t x = num_blocks;
-    while (1) {
-        ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy));
-        x -= 1;
-        if (x == 0) {
-            break;
-        }
-        source_blk -= 1;
-        blk_src_copy -= 1;
-    }
-
-    for (size_t i = num_blocks; i > 0; i--) {
-        ASSERT_TRUE(writer->AddXorBlocks(
-                num_blocks + i - 1, &random_buffer_1_.get()[writer->GetBlockSize() * (i - 1)],
-                writer->GetBlockSize(), 2 * num_blocks + i - 1, xor_offset));
-    }
-    // Flush operations
-    ASSERT_TRUE(writer->Finalize());
-    // Construct the buffer required for validation
-    orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-    // Read the entire base device
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
-              true);
-    // Merged Buffer
-    memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
-    memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
-    for (int i = 0; i < size_; i++) {
-        orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
-    }
-}
-
-void CowSnapuserdTest::CreateCowDeviceOrderedOps() {
-    unique_fd rnd_fd;
-    loff_t offset = 0;
-
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    rnd_fd.reset(open("/dev/random", O_RDONLY));
-    ASSERT_TRUE(rnd_fd > 0);
-
-    std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
-
-    // Fill random data
-    for (size_t j = 0; j < (size_ / 1_MiB); j++) {
-        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
-                  true);
-
-        offset += 1_MiB;
-    }
-    memset(random_buffer_1_.get(), 0, size_);
-
-    size_t num_blocks = size_ / writer->GetBlockSize();
-    size_t x = num_blocks;
-    size_t source_blk = 0;
-    size_t blk_src_copy = 2 * num_blocks;
-    uint16_t xor_offset = 5;
-
-    while (1) {
-        ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy));
-
-        x -= 1;
-        if (x == 0) {
-            break;
-        }
-        source_blk += 1;
-        blk_src_copy += 1;
-    }
-
-    ASSERT_TRUE(writer->AddXorBlocks(num_blocks, random_buffer_1_.get(), size_, 2 * num_blocks,
-                                     xor_offset));
-    // Flush operations
-    ASSERT_TRUE(writer->Finalize());
-    // Construct the buffer required for validation
-    orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-    // Read the entire base device
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), total_base_size_, 0),
-              true);
-    // Merged Buffer
-    memmove(orig_buffer_.get(), (char*)orig_buffer_.get() + 2 * size_, size_);
-    memmove(orig_buffer_.get() + size_, (char*)orig_buffer_.get() + 2 * size_ + xor_offset, size_);
-    for (int i = 0; i < size_; i++) {
-        orig_buffer_.get()[size_ + i] ^= random_buffer_1_.get()[i];
-    }
-}
-
-void CowSnapuserdTest::CreateCowDevice() {
-    unique_fd rnd_fd;
-    loff_t offset = 0;
-
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    rnd_fd.reset(open("/dev/random", O_RDONLY));
-    ASSERT_TRUE(rnd_fd > 0);
-
-    std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
-
-    // Fill random data
-    for (size_t j = 0; j < (size_ / 1_MiB); j++) {
-        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
-                  true);
-
-        offset += 1_MiB;
-    }
-
-    size_t num_blocks = size_ / writer->GetBlockSize();
-    size_t blk_end_copy = num_blocks * 2;
-    size_t source_blk = num_blocks - 1;
-    size_t blk_src_copy = blk_end_copy - 1;
-
-    uint32_t sequence[num_blocks * 2];
-    // Sequence for Copy ops
-    for (int i = 0; i < num_blocks; i++) {
-        sequence[i] = num_blocks - 1 - i;
-    }
-    // Sequence for Xor ops
-    for (int i = 0; i < num_blocks; i++) {
-        sequence[num_blocks + i] = 5 * num_blocks - 1 - i;
-    }
-    ASSERT_TRUE(writer->AddSequenceData(2 * num_blocks, sequence));
-
-    size_t x = num_blocks;
-    while (1) {
-        ASSERT_TRUE(writer->AddCopy(source_blk, blk_src_copy));
-        x -= 1;
-        if (x == 0) {
-            break;
-        }
-        source_blk -= 1;
-        blk_src_copy -= 1;
-    }
-
-    source_blk = num_blocks;
-    blk_src_copy = blk_end_copy;
-
-    ASSERT_TRUE(writer->AddRawBlocks(source_blk, random_buffer_1_.get(), size_));
-
-    size_t blk_zero_copy_start = source_blk + num_blocks;
-    size_t blk_zero_copy_end = blk_zero_copy_start + num_blocks;
-
-    ASSERT_TRUE(writer->AddZeroBlocks(blk_zero_copy_start, num_blocks));
-
-    size_t blk_random2_replace_start = blk_zero_copy_end;
-
-    ASSERT_TRUE(writer->AddRawBlocks(blk_random2_replace_start, random_buffer_1_.get(), size_));
-
-    size_t blk_xor_start = blk_random2_replace_start + num_blocks;
-    size_t xor_offset = BLOCK_SZ / 2;
-    ASSERT_TRUE(writer->AddXorBlocks(blk_xor_start, random_buffer_1_.get(), size_, num_blocks,
-                                     xor_offset));
-
-    // Flush operations
-    ASSERT_TRUE(writer->Finalize());
-    // Construct the buffer required for validation
-    orig_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-    std::string zero_buffer(size_, 0);
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, orig_buffer_.get(), size_, size_), true);
-    memcpy((char*)orig_buffer_.get() + size_, random_buffer_1_.get(), size_);
-    memcpy((char*)orig_buffer_.get() + (size_ * 2), (void*)zero_buffer.c_str(), size_);
-    memcpy((char*)orig_buffer_.get() + (size_ * 3), random_buffer_1_.get(), size_);
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, &orig_buffer_.get()[size_ * 4], size_,
-                                               size_ + xor_offset),
-              true);
-    for (int i = 0; i < size_; i++) {
-        orig_buffer_.get()[(size_ * 4) + i] =
-                (uint8_t)(orig_buffer_.get()[(size_ * 4) + i] ^ random_buffer_1_.get()[i]);
-    }
-}
-
-void CowSnapuserdTest::InitCowDevice() {
-    cow_num_sectors_ = client_->InitDmUserCow(system_device_ctrl_name_, cow_system_->path,
-                                              base_loop_->device());
-    ASSERT_NE(cow_num_sectors_, 0);
-}
-
-void CowSnapuserdTest::SetDeviceControlName() {
-    system_device_name_.clear();
-    system_device_ctrl_name_.clear();
-
-    std::string str(cow_system_->path);
-    std::size_t found = str.find_last_of("/\\");
-    ASSERT_NE(found, std::string::npos);
-    system_device_name_ = str.substr(found + 1);
-
-    system_device_ctrl_name_ = system_device_name_ + "-ctrl";
-}
-
-void CowSnapuserdTest::CreateDmUserDevice() {
-    DmTable dmuser_table;
-    ASSERT_TRUE(dmuser_table.AddTarget(
-            std::make_unique<DmTargetUser>(0, cow_num_sectors_, system_device_ctrl_name_)));
-    ASSERT_TRUE(dmuser_table.valid());
-
-    dmuser_dev_ = std::make_unique<TempDevice>(system_device_name_, dmuser_table);
-    ASSERT_TRUE(dmuser_dev_->valid());
-    ASSERT_FALSE(dmuser_dev_->path().empty());
-
-    auto misc_device = "/dev/dm-user/" + system_device_ctrl_name_;
-    ASSERT_TRUE(android::fs_mgr::WaitForFile(misc_device, 10s));
-}
-
-void CowSnapuserdTest::ReadDmUserBlockWithoutDaemon() {
-    DmTable dmuser_table;
-    std::string dm_user_name = "dm-test-device";
-    unique_fd fd;
-
-    // Create a dm-user block device
-    ASSERT_TRUE(dmuser_table.AddTarget(std::make_unique<DmTargetUser>(0, 123456, dm_user_name)));
-    ASSERT_TRUE(dmuser_table.valid());
-
-    dmuser_dev_ = std::make_unique<TempDevice>(dm_user_name, dmuser_table);
-    ASSERT_TRUE(dmuser_dev_->valid());
-    ASSERT_FALSE(dmuser_dev_->path().empty());
-
-    fd.reset(open(dmuser_dev_->path().c_str(), O_RDONLY));
-    ASSERT_GE(fd, 0);
-
-    std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(1_MiB);
-
-    loff_t offset = 0;
-    // Every IO should fail as there is no daemon to process the IO
-    for (size_t j = 0; j < 10; j++) {
-        ASSERT_EQ(ReadFullyAtOffset(fd, (char*)buffer.get() + offset, BLOCK_SZ, offset), false);
-
-        offset += BLOCK_SZ;
-    }
-
-    fd = {};
-    ASSERT_TRUE(dmuser_dev_->Destroy());
-}
-
-void CowSnapuserdTest::InitDaemon() {
-    bool ok = client_->AttachDmUser(system_device_ctrl_name_);
-    ASSERT_TRUE(ok);
-}
-
-void CowSnapuserdTest::CreateSnapshotDevice() {
-    DmTable snap_table;
-    ASSERT_TRUE(snap_table.AddTarget(std::make_unique<DmTargetSnapshot>(
-            0, total_base_size_ / kSectorSize, base_loop_->device(), dmuser_dev_->path(),
-            SnapshotStorageMode::Persistent, 8)));
-    ASSERT_TRUE(snap_table.valid());
-
-    snap_table.set_readonly(true);
-
-    snapshot_dev_ = std::make_unique<TempDevice>("cowsnapuserd-test-dm-snapshot", snap_table);
-    ASSERT_TRUE(snapshot_dev_->valid());
-    ASSERT_FALSE(snapshot_dev_->path().empty());
-}
-
-void CowSnapuserdTest::SetupImpl() {
-    CreateBaseDevice();
-    CreateCowDevice();
-
-    SetDeviceControlName();
-
-    StartSnapuserdDaemon();
-    InitCowDevice();
-
-    CreateDmUserDevice();
-    InitDaemon();
-
-    CreateSnapshotDevice();
-    setup_ok_ = true;
-}
-
-bool CowSnapuserdTest::Merge() {
-    MergeImpl();
-    return merge_ok_;
-}
-
-void CowSnapuserdTest::StartMerge() {
-    DmTable merge_table;
-    ASSERT_TRUE(merge_table.AddTarget(std::make_unique<DmTargetSnapshot>(
-            0, total_base_size_ / kSectorSize, base_loop_->device(), dmuser_dev_->path(),
-            SnapshotStorageMode::Merge, 8)));
-    ASSERT_TRUE(merge_table.valid());
-    ASSERT_EQ(total_base_size_ / kSectorSize, merge_table.num_sectors());
-
-    DeviceMapper& dm = DeviceMapper::Instance();
-    ASSERT_TRUE(dm.LoadTableAndActivate("cowsnapuserd-test-dm-snapshot", merge_table));
-}
-
-void CowSnapuserdTest::MergeImpl() {
-    StartMerge();
-    DeviceMapper& dm = DeviceMapper::Instance();
-
-    while (true) {
-        vector<DeviceMapper::TargetInfo> status;
-        ASSERT_TRUE(dm.GetTableStatus("cowsnapuserd-test-dm-snapshot", &status));
-        ASSERT_EQ(status.size(), 1);
-        ASSERT_EQ(strncmp(status[0].spec.target_type, "snapshot-merge", strlen("snapshot-merge")),
-                  0);
-
-        DmTargetSnapshot::Status merge_status;
-        ASSERT_TRUE(DmTargetSnapshot::ParseStatusText(status[0].data, &merge_status));
-        ASSERT_TRUE(merge_status.error.empty());
-        if (merge_status.sectors_allocated == merge_status.metadata_sectors) {
-            break;
-        }
-
-        std::this_thread::sleep_for(250ms);
-    }
-
-    merge_ok_ = true;
-}
-
-void CowSnapuserdTest::ValidateMerge() {
-    merged_buffer_ = std::make_unique<uint8_t[]>(total_base_size_);
-    ASSERT_EQ(android::base::ReadFullyAtOffset(base_fd_, merged_buffer_.get(), total_base_size_, 0),
-              true);
-    ASSERT_EQ(memcmp(merged_buffer_.get(), orig_buffer_.get(), total_base_size_), 0);
-}
-
-void CowSnapuserdTest::SimulateDaemonRestart() {
-    Shutdown();
-    std::this_thread::sleep_for(500ms);
-    SetDeviceControlName();
-    StartSnapuserdDaemon();
-    InitCowDevice();
-    CreateDmUserDevice();
-    InitDaemon();
-    CreateSnapshotDevice();
-}
-
-void CowSnapuserdTest::MergeInterruptRandomly(int max_duration) {
-    std::srand(std::time(nullptr));
-    StartMerge();
-
-    for (int i = 0; i < 20; i++) {
-        int duration = std::rand() % max_duration;
-        std::this_thread::sleep_for(std::chrono::milliseconds(duration));
-        SimulateDaemonRestart();
-        StartMerge();
-    }
-
-    SimulateDaemonRestart();
-    ASSERT_TRUE(Merge());
-}
-
-void CowSnapuserdTest::MergeInterruptFixed(int duration) {
-    StartMerge();
-
-    for (int i = 0; i < 25; i++) {
-        std::this_thread::sleep_for(std::chrono::milliseconds(duration));
-        SimulateDaemonRestart();
-        StartMerge();
-    }
-
-    SimulateDaemonRestart();
-    ASSERT_TRUE(Merge());
-}
-
-void CowSnapuserdTest::MergeInterrupt() {
-    // Interrupt merge at various intervals
-    StartMerge();
-    std::this_thread::sleep_for(250ms);
-    SimulateDaemonRestart();
-
-    StartMerge();
-    std::this_thread::sleep_for(250ms);
-    SimulateDaemonRestart();
-
-    StartMerge();
-    std::this_thread::sleep_for(150ms);
-    SimulateDaemonRestart();
-
-    StartMerge();
-    std::this_thread::sleep_for(100ms);
-    SimulateDaemonRestart();
-
-    StartMerge();
-    std::this_thread::sleep_for(800ms);
-    SimulateDaemonRestart();
-
-    StartMerge();
-    std::this_thread::sleep_for(600ms);
-    SimulateDaemonRestart();
-
-    ASSERT_TRUE(Merge());
-}
-
-std::unique_ptr<ICowWriter> CowSnapuserdMetadataTest::CreateCowDeviceInternal() {
-    std::string path = android::base::GetExecutableDirectory();
-    cow_system_ = std::make_unique<TemporaryFile>(path);
-
-    CowOptions options;
-    options.compression = "gz";
-
-    unique_fd fd(cow_system_->fd);
-    cow_system_->fd = -1;
-
-    return CreateCowWriter(kDefaultCowVersion, options, std::move(fd));
-}
-
-void CowSnapuserdMetadataTest::CreateCowPartialFilledArea() {
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    // Area 0 is completely filled with 256 exceptions
-    for (int i = 0; i < 256; i++) {
-        ASSERT_TRUE(writer->AddCopy(i, 256 + i));
-    }
-
-    // Area 1 is partially filled with 2 copy ops and 10 zero ops
-    ASSERT_TRUE(writer->AddCopy(500, 1000));
-    ASSERT_TRUE(writer->AddCopy(501, 1001));
-
-    ASSERT_TRUE(writer->AddZeroBlocks(300, 10));
-
-    // Flush operations
-    ASSERT_TRUE(writer->Finalize());
-}
-
-void CowSnapuserdMetadataTest::ValidatePartialFilledArea() {
-    int area_sz = snapuserd_->GetMetadataAreaSize();
-
-    ASSERT_EQ(area_sz, 2);
-
-    // Verify the partially filled area
-    void* buffer = snapuserd_->GetExceptionBuffer(1);
-    loff_t offset = 0;
-    struct disk_exception* de;
-    for (int i = 11; i >= 0; i--) {
-        de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-        ASSERT_EQ(de->old_chunk, i);
-        offset += sizeof(struct disk_exception);
-    }
-
-    de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-    ASSERT_EQ(de->old_chunk, 0);
-    ASSERT_EQ(de->new_chunk, 0);
-}
-
-void CowSnapuserdMetadataTest::SetupPartialArea() {
-    CreateCowPartialFilledArea();
-    InitMetadata();
-}
-
-void CowSnapuserdMetadataTest::CreateCowDevice() {
-    unique_fd rnd_fd;
-    loff_t offset = 0;
-
-    auto writer = CreateCowDeviceInternal();
-    ASSERT_NE(writer, nullptr);
-
-    rnd_fd.reset(open("/dev/random", O_RDONLY));
-    ASSERT_TRUE(rnd_fd > 0);
-
-    std::unique_ptr<uint8_t[]> random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
-
-    // Fill random data
-    for (size_t j = 0; j < (size_ / 1_MiB); j++) {
-        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_1_.get() + offset, 1_MiB, 0),
-                  true);
-
-        offset += 1_MiB;
-    }
-
-    size_t num_blocks = size_ / writer->GetBlockSize();
-
-    // Overlapping region. This has to be split
-    // into two batch operations
-    ASSERT_TRUE(writer->AddCopy(23, 20));
-    ASSERT_TRUE(writer->AddCopy(22, 19));
-    ASSERT_TRUE(writer->AddCopy(21, 18));
-    ASSERT_TRUE(writer->AddCopy(20, 17));
-    ASSERT_TRUE(writer->AddCopy(19, 16));
-    ASSERT_TRUE(writer->AddCopy(18, 15));
-
-    // Contiguous region but blocks in ascending order
-    // Daemon has to ensure that these blocks are merged
-    // in a batch
-    ASSERT_TRUE(writer->AddCopy(50, 75));
-    ASSERT_TRUE(writer->AddCopy(51, 76));
-    ASSERT_TRUE(writer->AddCopy(52, 77));
-    ASSERT_TRUE(writer->AddCopy(53, 78));
-
-    // Dis-contiguous region
-    ASSERT_TRUE(writer->AddCopy(110, 130));
-    ASSERT_TRUE(writer->AddCopy(105, 125));
-    ASSERT_TRUE(writer->AddCopy(100, 120));
-
-    // Overlap
-    ASSERT_TRUE(writer->AddCopy(25, 30));
-    ASSERT_TRUE(writer->AddCopy(30, 31));
-
-    size_t source_blk = num_blocks;
-
-    ASSERT_TRUE(writer->AddRawBlocks(source_blk, random_buffer_1_.get(), size_));
-
-    size_t blk_zero_copy_start = source_blk + num_blocks;
-
-    ASSERT_TRUE(writer->AddZeroBlocks(blk_zero_copy_start, num_blocks));
-
-    // Flush operations
-    ASSERT_TRUE(writer->Finalize());
-}
-
-void CowSnapuserdMetadataTest::InitMetadata() {
-    snapuserd_ = std::make_unique<Snapuserd>("", cow_system_->path, "");
-    ASSERT_TRUE(snapuserd_->InitCowDevice());
-}
-
-void CowSnapuserdMetadataTest::Setup() {
-    CreateCowDevice();
-    InitMetadata();
-}
-
-void CowSnapuserdMetadataTest::ValidateMetadata() {
-    int area_sz = snapuserd_->GetMetadataAreaSize();
-    ASSERT_EQ(area_sz, 3);
-
-    size_t old_chunk;
-    size_t new_chunk;
-
-    for (int i = 0; i < area_sz; i++) {
-        void* buffer = snapuserd_->GetExceptionBuffer(i);
-        loff_t offset = 0;
-        if (i == 0) {
-            old_chunk = 256;
-            new_chunk = 2;
-        } else if (i == 1) {
-            old_chunk = 512;
-            new_chunk = 259;
-        }
-        for (int j = 0; j < 256; j++) {
-            struct disk_exception* de =
-                    reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-
-            if (i != 2) {
-                ASSERT_EQ(de->old_chunk, old_chunk);
-                ASSERT_EQ(de->new_chunk, new_chunk);
-                old_chunk += 1;
-                new_chunk += 1;
-            } else {
-                break;
-            }
-            offset += sizeof(struct disk_exception);
-        }
-
-        if (i == 2) {
-            // The first 5 copy operation is not batch merged
-            // as the sequence is discontiguous
-            struct disk_exception* de =
-                    reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 30);
-            ASSERT_EQ(de->new_chunk, 518);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 25);
-            ASSERT_EQ(de->new_chunk, 520);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 100);
-            ASSERT_EQ(de->new_chunk, 521);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 105);
-            ASSERT_EQ(de->new_chunk, 522);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 110);
-            ASSERT_EQ(de->new_chunk, 523);
-            offset += sizeof(struct disk_exception);
-
-            // The next 4 operations are batch merged as
-            // both old and new chunk are contiguous
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 53);
-            ASSERT_EQ(de->new_chunk, 524);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 52);
-            ASSERT_EQ(de->new_chunk, 525);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 51);
-            ASSERT_EQ(de->new_chunk, 526);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 50);
-            ASSERT_EQ(de->new_chunk, 527);
-            offset += sizeof(struct disk_exception);
-
-            // This is handling overlap operation with
-            // two batch merge operations.
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 18);
-            ASSERT_EQ(de->new_chunk, 528);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 19);
-            ASSERT_EQ(de->new_chunk, 529);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 20);
-            ASSERT_EQ(de->new_chunk, 530);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 21);
-            ASSERT_EQ(de->new_chunk, 532);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 22);
-            ASSERT_EQ(de->new_chunk, 533);
-            offset += sizeof(struct disk_exception);
-
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 23);
-            ASSERT_EQ(de->new_chunk, 534);
-            offset += sizeof(struct disk_exception);
-
-            // End of metadata
-            de = reinterpret_cast<struct disk_exception*>((char*)buffer + offset);
-            ASSERT_EQ(de->old_chunk, 0);
-            ASSERT_EQ(de->new_chunk, 0);
-            offset += sizeof(struct disk_exception);
-        }
-    }
-}
-
-TEST(Snapuserd_Test, Snapshot_Metadata) {
-    CowSnapuserdMetadataTest harness;
-    harness.Setup();
-    harness.ValidateMetadata();
-}
-
-TEST(Snapuserd_Test, Snapshot_Metadata_Overlap) {
-    CowSnapuserdMetadataTest harness;
-    harness.SetupPartialArea();
-    harness.ValidatePartialFilledArea();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Resume) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.Setup());
-    harness.MergeInterrupt();
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_IO_TEST) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.Setup());
-    harness.ReadSnapshotDeviceAndValidate();
-    ASSERT_TRUE(harness.Merge());
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_END_IO_TEST) {
-    CowSnapuserdTest harness;
-    harness.ReadLastBlock();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_1) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.SetupCopyOverlap_1());
-    ASSERT_TRUE(harness.Merge());
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_TEST_2) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.SetupCopyOverlap_2());
-    ASSERT_TRUE(harness.Merge());
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_COPY_Overlap_Merge_Resume_TEST) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.SetupCopyOverlap_1());
-    harness.MergeInterrupt();
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, ReadDmUserBlockWithoutDaemon) {
-    CowSnapuserdTest harness;
-    harness.ReadDmUserBlockWithoutDaemon();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Ordered) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOps());
-    harness.MergeInterruptFixed(300);
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Ordered) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOps());
-    harness.MergeInterruptRandomly(500);
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Fixed_Inverted) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOpsInverted());
-    harness.MergeInterruptFixed(50);
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-TEST(Snapuserd_Test, Snapshot_Merge_Crash_Random_Inverted) {
-    CowSnapuserdTest harness;
-    ASSERT_TRUE(harness.SetupOrderedOpsInverted());
-    harness.MergeInterruptRandomly(50);
-    harness.ValidateMerge();
-    harness.Shutdown();
-}
-
-}  // namespace snapshot
-}  // namespace android
-
-int main(int argc, char** argv) {
-    ::testing::InitGoogleTest(&argc, argv);
-    return RUN_ALL_TESTS();
-}
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
deleted file mode 100644
index 93bb0b2..0000000
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.cpp
+++ /dev/null
@@ -1,870 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "snapuserd.h"
-
-#include <dirent.h>
-#include <fcntl.h>
-#include <linux/fs.h>
-#include <unistd.h>
-#include <algorithm>
-
-#include <csignal>
-#include <optional>
-#include <set>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/parseint.h>
-#include <android-base/properties.h>
-#include <android-base/strings.h>
-#include <android-base/unique_fd.h>
-#include <snapuserd/snapuserd_client.h>
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-#define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
-#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
-
-Snapuserd::Snapuserd(const std::string& misc_name, const std::string& cow_device,
-                     const std::string& backing_device) {
-    misc_name_ = misc_name;
-    cow_device_ = cow_device;
-    backing_store_device_ = backing_device;
-    control_device_ = "/dev/dm-user/" + misc_name;
-}
-
-bool Snapuserd::InitializeWorkers() {
-    for (int i = 0; i < NUM_THREADS_PER_PARTITION; i++) {
-        std::unique_ptr<WorkerThread> wt = std::make_unique<WorkerThread>(
-                cow_device_, backing_store_device_, control_device_, misc_name_, GetSharedPtr());
-
-        worker_threads_.push_back(std::move(wt));
-    }
-
-    read_ahead_thread_ = std::make_unique<ReadAheadThread>(cow_device_, backing_store_device_,
-                                                           misc_name_, GetSharedPtr());
-    return true;
-}
-
-std::unique_ptr<CowReader> Snapuserd::CloneReaderForWorker() {
-    return reader_->CloneCowReader();
-}
-
-bool Snapuserd::CommitMerge(int num_merge_ops) {
-    struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
-    ch->num_merge_ops += num_merge_ops;
-
-    if (read_ahead_feature_ && read_ahead_ops_.size() > 0) {
-        struct BufferState* ra_state = GetBufferState();
-        ra_state->read_ahead_state = kCowReadAheadInProgress;
-    }
-
-    int ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC);
-    if (ret < 0) {
-        SNAP_PLOG(ERROR) << "msync header failed: " << ret;
-        return false;
-    }
-
-    merge_initiated_ = true;
-
-    return true;
-}
-
-void Snapuserd::PrepareReadAhead() {
-    if (!read_ahead_feature_) {
-        return;
-    }
-
-    struct BufferState* ra_state = GetBufferState();
-    // Check if the data has to be re-constructed from COW device
-    if (ra_state->read_ahead_state == kCowReadAheadDone) {
-        populate_data_from_cow_ = true;
-    } else {
-        populate_data_from_cow_ = false;
-    }
-
-    StartReadAhead();
-}
-
-bool Snapuserd::GetRABuffer(std::unique_lock<std::mutex>* lock, uint64_t block, void* buffer) {
-    if (!lock->owns_lock()) {
-        SNAP_LOG(ERROR) << "GetRABuffer - Lock not held";
-        return false;
-    }
-    std::unordered_map<uint64_t, void*>::iterator it = read_ahead_buffer_map_.find(block);
-
-    // This will be true only for IO's generated as part of reading a root
-    // filesystem. IO's related to merge should always be in read-ahead cache.
-    if (it == read_ahead_buffer_map_.end()) {
-        return false;
-    }
-
-    // Theoretically, we can send the data back from the read-ahead buffer
-    // all the way to the kernel without memcpy. However, if the IO is
-    // un-aligned, the wrapper function will need to touch the read-ahead
-    // buffers and transitions will be bit more complicated.
-    memcpy(buffer, it->second, BLOCK_SZ);
-    return true;
-}
-
-// ========== State transition functions for read-ahead operations ===========
-
-bool Snapuserd::GetReadAheadPopulatedBuffer(uint64_t block, void* buffer) {
-    if (!read_ahead_feature_) {
-        return false;
-    }
-
-    {
-        std::unique_lock<std::mutex> lock(lock_);
-        if (io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE) {
-            return false;
-        }
-
-        if (io_state_ == READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS) {
-            return GetRABuffer(&lock, block, buffer);
-        }
-    }
-
-    {
-        // Read-ahead thread IO is in-progress. Wait for it to complete
-        std::unique_lock<std::mutex> lock(lock_);
-        while (!(io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE ||
-                 io_state_ == READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS)) {
-            cv.wait(lock);
-        }
-
-        return GetRABuffer(&lock, block, buffer);
-    }
-}
-
-// This is invoked by read-ahead thread waiting for merge IO's
-// to complete
-bool Snapuserd::WaitForMergeToComplete() {
-    {
-        std::unique_lock<std::mutex> lock(lock_);
-        while (!(io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_BEGIN ||
-                 io_state_ == READ_AHEAD_IO_TRANSITION::IO_TERMINATED)) {
-            cv.wait(lock);
-        }
-
-        if (io_state_ == READ_AHEAD_IO_TRANSITION::IO_TERMINATED) {
-            return false;
-        }
-
-        io_state_ = READ_AHEAD_IO_TRANSITION::READ_AHEAD_IN_PROGRESS;
-        return true;
-    }
-}
-
-// This is invoked during the launch of worker threads. We wait
-// for read-ahead thread to by fully up before worker threads
-// are launched; else we will have a race between worker threads
-// and read-ahead thread specifically during re-construction.
-bool Snapuserd::WaitForReadAheadToStart() {
-    {
-        std::unique_lock<std::mutex> lock(lock_);
-        while (!(io_state_ == READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS ||
-                 io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE)) {
-            cv.wait(lock);
-        }
-
-        if (io_state_ == READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE) {
-            return false;
-        }
-
-        return true;
-    }
-}
-
-// Invoked by worker threads when a sequence of merge operation
-// is complete notifying read-ahead thread to make forward
-// progress.
-void Snapuserd::StartReadAhead() {
-    {
-        std::lock_guard<std::mutex> lock(lock_);
-        io_state_ = READ_AHEAD_IO_TRANSITION::READ_AHEAD_BEGIN;
-    }
-
-    cv.notify_one();
-}
-
-void Snapuserd::MergeCompleted() {
-    {
-        std::lock_guard<std::mutex> lock(lock_);
-        io_state_ = READ_AHEAD_IO_TRANSITION::IO_TERMINATED;
-    }
-
-    cv.notify_one();
-}
-
-bool Snapuserd::ReadAheadIOCompleted(bool sync) {
-    if (sync) {
-        // Flush the entire buffer region
-        int ret = msync(mapped_addr_, total_mapped_addr_length_, MS_SYNC);
-        if (ret < 0) {
-            PLOG(ERROR) << "msync failed after ReadAheadIOCompleted: " << ret;
-            return false;
-        }
-
-        // Metadata and data are synced. Now, update the state.
-        // We need to update the state after flushing data; if there is a crash
-        // when read-ahead IO is in progress, the state of data in the COW file
-        // is unknown. kCowReadAheadDone acts as a checkpoint wherein the data
-        // in the scratch space is good and during next reboot, read-ahead thread
-        // can safely re-construct the data.
-        struct BufferState* ra_state = GetBufferState();
-        ra_state->read_ahead_state = kCowReadAheadDone;
-
-        ret = msync(mapped_addr_, BLOCK_SZ, MS_SYNC);
-        if (ret < 0) {
-            PLOG(ERROR) << "msync failed to flush Readahead completion state...";
-            return false;
-        }
-    }
-
-    // Notify the worker threads
-    {
-        std::lock_guard<std::mutex> lock(lock_);
-        io_state_ = READ_AHEAD_IO_TRANSITION::IO_IN_PROGRESS;
-    }
-
-    cv.notify_all();
-    return true;
-}
-
-void Snapuserd::ReadAheadIOFailed() {
-    {
-        std::lock_guard<std::mutex> lock(lock_);
-        io_state_ = READ_AHEAD_IO_TRANSITION::READ_AHEAD_FAILURE;
-    }
-
-    cv.notify_all();
-}
-
-//========== End of state transition functions ====================
-
-bool Snapuserd::IsChunkIdMetadata(chunk_t chunk) {
-    uint32_t stride = exceptions_per_area_ + 1;
-    lldiv_t divresult = lldiv(chunk, stride);
-
-    return (divresult.rem == NUM_SNAPSHOT_HDR_CHUNKS);
-}
-
-// Find the next free chunk-id to be assigned. Check if the next free
-// chunk-id represents a metadata page. If so, skip it.
-chunk_t Snapuserd::GetNextAllocatableChunkId(chunk_t chunk) {
-    chunk_t next_chunk = chunk + 1;
-
-    if (IsChunkIdMetadata(next_chunk)) {
-        next_chunk += 1;
-    }
-    return next_chunk;
-}
-
-void Snapuserd::CheckMergeCompletionStatus() {
-    if (!merge_initiated_) {
-        SNAP_LOG(INFO) << "Merge was not initiated. Total-data-ops: "
-                       << reader_->get_num_total_data_ops();
-        return;
-    }
-
-    struct CowHeader* ch = reinterpret_cast<struct CowHeader*>(mapped_addr_);
-
-    SNAP_LOG(INFO) << "Merge-status: Total-Merged-ops: " << ch->num_merge_ops
-                   << " Total-data-ops: " << reader_->get_num_total_data_ops();
-}
-
-/*
- * Read the metadata from COW device and
- * construct the metadata as required by the kernel.
- *
- * Please see design on kernel COW format
- *
- * 1: Read the metadata from internal COW device
- * 2: There are 3 COW operations:
- *     a: Replace op
- *     b: Copy op
- *     c: Zero op
- * 3: For each of the 3 operations, op->new_block
- *    represents the block number in the base device
- *    for which one of the 3 operations have to be applied.
- *    This represents the old_chunk in the kernel COW format
- * 4: We need to assign new_chunk for a corresponding old_chunk
- * 5: The algorithm is similar to how kernel assigns chunk number
- *    while creating exceptions. However, there are few cases
- *    which needs to be addressed here:
- *      a: During merge process, kernel scans the metadata page
- *      from backwards when merge is initiated. Since, we need
- *      to make sure that the merge ordering follows our COW format,
- *      we read the COW operation from backwards and populate the
- *      metadata so that when kernel starts the merging from backwards,
- *      those ops correspond to the beginning of our COW format.
- *      b: Kernel can merge successive operations if the two chunk IDs
- *      are contiguous. This can be problematic when there is a crash
- *      during merge; specifically when the merge operation has dependency.
- *      These dependencies can only happen during copy operations.
- *
- *      To avoid this problem, we make sure overlap copy operations
- *      are not batch merged.
- * 6: Use a monotonically increasing chunk number to assign the
- *    new_chunk
- * 7: Each chunk-id represents either
- *        a: Metadata page or
- *        b: Data page
- * 8: Chunk-id representing a data page is stored in a map.
- * 9: Chunk-id representing a metadata page is converted into a vector
- *    index. We store this in vector as kernel requests metadata during
- *    two stage:
- *       a: When initial dm-snapshot device is created, kernel requests
- *          all the metadata and stores it in its internal data-structures.
- *       b: During merge, kernel once again requests the same metadata
- *          once-again.
- *    In both these cases, a quick lookup based on chunk-id is done.
- * 10: When chunk number is incremented, we need to make sure that
- *    if the chunk is representing a metadata page and skip.
- * 11: Each 4k page will contain 256 disk exceptions. We call this
- *    exceptions_per_area_
- * 12: Kernel will stop issuing metadata IO request when new-chunk ID is 0.
- */
-bool Snapuserd::ReadMetadata() {
-    reader_ = std::make_unique<CowReader>();
-    CowOptions options;
-    bool metadata_found = false;
-    int replace_ops = 0, zero_ops = 0, copy_ops = 0;
-
-    SNAP_LOG(DEBUG) << "ReadMetadata: Parsing cow file";
-
-    if (!reader_->Parse(cow_fd_)) {
-        SNAP_LOG(ERROR) << "Failed to parse";
-        return false;
-    }
-
-    const auto& header = reader_->GetHeader();
-    if (!(header.block_size == BLOCK_SZ)) {
-        SNAP_LOG(ERROR) << "Invalid header block size found: " << header.block_size;
-        return false;
-    }
-
-    SNAP_LOG(DEBUG) << "Merge-ops: " << header.num_merge_ops;
-
-    if (!MmapMetadata()) {
-        SNAP_LOG(ERROR) << "mmap failed";
-        return false;
-    }
-
-    // Initialize the iterator for reading metadata
-    std::unique_ptr<ICowOpIter> cowop_rm_iter = reader_->GetRevMergeOpIter();
-
-    exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception);
-
-    // Start from chunk number 2. Chunk 0 represents header and chunk 1
-    // represents first metadata page.
-    chunk_t data_chunk_id = NUM_SNAPSHOT_HDR_CHUNKS + 1;
-    size_t num_ops = 0;
-
-    loff_t offset = 0;
-    std::unique_ptr<uint8_t[]> de_ptr =
-            std::make_unique<uint8_t[]>(exceptions_per_area_ * sizeof(struct disk_exception));
-
-    // This memset is important. Kernel will stop issuing IO when new-chunk ID
-    // is 0. When Area is not filled completely with all 256 exceptions,
-    // this memset will ensure that metadata read is completed.
-    memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
-
-    while (!cowop_rm_iter->AtEnd()) {
-        const CowOperation* cow_op = cowop_rm_iter->Get();
-        struct disk_exception* de =
-                reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
-
-        metadata_found = true;
-        // This loop will handle all the replace and zero ops.
-        // We will handle the copy ops later as it requires special
-        // handling of assigning chunk-id's. Furthermore, we make
-        // sure that replace/zero and copy ops are not batch merged; hence,
-        // the bump in the chunk_id before break of this loop
-        if (IsOrderedOp(*cow_op)) {
-            data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
-            break;
-        }
-
-        if (cow_op->type() == kCowReplaceOp) {
-            replace_ops++;
-        } else if (cow_op->type() == kCowZeroOp) {
-            zero_ops++;
-        }
-
-        // Construct the disk-exception
-        de->old_chunk = cow_op->new_block;
-        de->new_chunk = data_chunk_id;
-
-        // Store operation pointer.
-        chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op));
-        num_ops += 1;
-        offset += sizeof(struct disk_exception);
-        cowop_rm_iter->Next();
-
-        SNAP_LOG(DEBUG) << num_ops << ":"
-                        << " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk;
-
-        if (num_ops == exceptions_per_area_) {
-            // Store it in vector at the right index. This maps the chunk-id to
-            // vector index.
-            vec_.push_back(std::move(de_ptr));
-            offset = 0;
-            num_ops = 0;
-
-            // Create buffer for next area
-            de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ *
-                                                 sizeof(struct disk_exception));
-            memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
-
-            if (cowop_rm_iter->AtEnd()) {
-                vec_.push_back(std::move(de_ptr));
-            }
-        }
-
-        data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
-    }
-
-    int num_ra_ops_per_iter = ((GetBufferDataSize()) / BLOCK_SZ);
-    std::optional<chunk_t> prev_id = {};
-    std::vector<const CowOperation*> vec;
-    std::set<uint64_t> dest_blocks;
-    std::set<uint64_t> source_blocks;
-    size_t pending_ordered_ops = exceptions_per_area_ - num_ops;
-    uint64_t total_ordered_ops = reader_->get_num_ordered_ops_to_merge();
-
-    SNAP_LOG(DEBUG) << " Processing copy-ops at Area: " << vec_.size()
-                    << " Number of replace/zero ops completed in this area: " << num_ops
-                    << " Pending copy ops for this area: " << pending_ordered_ops;
-
-    while (!cowop_rm_iter->AtEnd()) {
-        do {
-            const CowOperation* cow_op = cowop_rm_iter->Get();
-
-            // We have two cases specific cases:
-            //
-            // =====================================================
-            // Case 1: Overlapping copy regions
-            //
-            // Ex:
-            //
-            // Source -> Destination
-            //
-            // 1: 15 -> 18
-            // 2: 16 -> 19
-            // 3: 17 -> 20
-            // 4: 18 -> 21
-            // 5: 19 -> 22
-            // 6: 20 -> 23
-            //
-            // We have 6 copy operations to be executed in OTA and there is a overlap. Update-engine
-            // will write to COW file as follows:
-            //
-            // Op-1: 20 -> 23
-            // Op-2: 19 -> 22
-            // Op-3: 18 -> 21
-            // Op-4: 17 -> 20
-            // Op-5: 16 -> 19
-            // Op-6: 15 -> 18
-            //
-            // Note that the blocks numbers are contiguous. Hence, all 6 copy
-            // operations can be batch merged. However, that will be
-            // problematic if we have a crash as block 20, 19, 18 would have
-            // been overwritten and hence subsequent recovery may end up with
-            // a silent data corruption when op-1, op-2 and op-3 are
-            // re-executed.
-            //
-            // To address the above problem, read-ahead thread will
-            // read all the 6 source blocks, cache them in the scratch
-            // space of the COW file. During merge, read-ahead
-            // thread will serve the blocks from the read-ahead cache.
-            // If there is a crash during merge; on subsequent reboot,
-            // read-ahead thread will recover the data from the
-            // scratch space and re-construct it thereby there
-            // is no loss of data.
-            //
-            // Note that we will follow the same order of COW operations
-            // as present in the COW file. This will make sure that
-            // the merge of operations are done based on the ops present
-            // in the file.
-            //===========================================================
-            uint64_t block_source = cow_op->source();
-            if (prev_id.has_value()) {
-                if (dest_blocks.count(cow_op->new_block) || source_blocks.count(block_source)) {
-                    break;
-                }
-            }
-            metadata_found = true;
-            pending_ordered_ops -= 1;
-            vec.push_back(cow_op);
-            dest_blocks.insert(block_source);
-            source_blocks.insert(cow_op->new_block);
-            prev_id = cow_op->new_block;
-            cowop_rm_iter->Next();
-        } while (!cowop_rm_iter->AtEnd() && pending_ordered_ops);
-
-        data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
-        SNAP_LOG(DEBUG) << "Batch Merge copy-ops of size: " << vec.size()
-                        << " Area: " << vec_.size() << " Area offset: " << offset
-                        << " Pending-ordered-ops in this area: " << pending_ordered_ops;
-
-        for (size_t i = 0; i < vec.size(); i++) {
-            struct disk_exception* de =
-                    reinterpret_cast<struct disk_exception*>((char*)de_ptr.get() + offset);
-            const CowOperation* cow_op = vec[i];
-
-            de->old_chunk = cow_op->new_block;
-            de->new_chunk = data_chunk_id;
-
-            // Store operation pointer.
-            chunk_vec_.push_back(std::make_pair(ChunkToSector(data_chunk_id), cow_op));
-            offset += sizeof(struct disk_exception);
-            num_ops += 1;
-            if (cow_op->type() == kCowCopyOp) {
-                copy_ops++;
-            }
-
-            if (read_ahead_feature_) {
-                read_ahead_ops_.push_back(cow_op);
-            }
-
-            SNAP_LOG(DEBUG) << num_ops << ":"
-                            << " Ordered-op: "
-                            << " Old-chunk: " << de->old_chunk << " New-chunk: " << de->new_chunk;
-
-            if (num_ops == exceptions_per_area_) {
-                // Store it in vector at the right index. This maps the chunk-id to
-                // vector index.
-                vec_.push_back(std::move(de_ptr));
-                num_ops = 0;
-                offset = 0;
-
-                // Create buffer for next area
-                de_ptr = std::make_unique<uint8_t[]>(exceptions_per_area_ *
-                                                     sizeof(struct disk_exception));
-                memset(de_ptr.get(), 0, (exceptions_per_area_ * sizeof(struct disk_exception)));
-
-                if (cowop_rm_iter->AtEnd()) {
-                    vec_.push_back(std::move(de_ptr));
-                    SNAP_LOG(DEBUG) << "ReadMetadata() completed; Number of Areas: " << vec_.size();
-                }
-
-                if (!(pending_ordered_ops == 0)) {
-                    SNAP_LOG(ERROR) << "Invalid pending_ordered_ops: expected: 0 found: "
-                                    << pending_ordered_ops;
-                    return false;
-                }
-                pending_ordered_ops = exceptions_per_area_;
-            }
-
-            data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
-            total_ordered_ops -= 1;
-            /*
-             * Split the number of ops based on the size of read-ahead buffer
-             * region. We need to ensure that kernel doesn't issue IO on blocks
-             * which are not read by the read-ahead thread.
-             */
-            if (read_ahead_feature_ && (total_ordered_ops % num_ra_ops_per_iter == 0)) {
-                data_chunk_id = GetNextAllocatableChunkId(data_chunk_id);
-            }
-        }
-        vec.clear();
-        dest_blocks.clear();
-        source_blocks.clear();
-        prev_id.reset();
-    }
-
-    // Partially filled area or there is no metadata
-    // If there is no metadata, fill with zero so that kernel
-    // is aware that merge is completed.
-    if (num_ops || !metadata_found) {
-        vec_.push_back(std::move(de_ptr));
-        SNAP_LOG(DEBUG) << "ReadMetadata() completed. Partially filled area num_ops: " << num_ops
-                        << "Areas : " << vec_.size();
-    }
-
-    chunk_vec_.shrink_to_fit();
-    vec_.shrink_to_fit();
-    read_ahead_ops_.shrink_to_fit();
-
-    // Sort the vector based on sectors as we need this during un-aligned access
-    std::sort(chunk_vec_.begin(), chunk_vec_.end(), compare);
-
-    SNAP_LOG(INFO) << "ReadMetadata completed. Final-chunk-id: " << data_chunk_id
-                   << " Num Sector: " << ChunkToSector(data_chunk_id)
-                   << " Replace-ops: " << replace_ops << " Zero-ops: " << zero_ops
-                   << " Copy-ops: " << copy_ops << " Areas: " << vec_.size()
-                   << " Num-ops-merged: " << header.num_merge_ops
-                   << " Total-data-ops: " << reader_->get_num_total_data_ops();
-
-    // Total number of sectors required for creating dm-user device
-    num_sectors_ = ChunkToSector(data_chunk_id);
-    merge_initiated_ = false;
-    PrepareReadAhead();
-
-    return true;
-}
-
-bool Snapuserd::MmapMetadata() {
-    const auto& header = reader_->GetHeader();
-
-    if (header.prefix.major_version >= 2 && header.buffer_size > 0) {
-        total_mapped_addr_length_ = header.prefix.header_size + BUFFER_REGION_DEFAULT_SIZE;
-        read_ahead_feature_ = true;
-    } else {
-        // mmap the first 4k page - older COW format
-        total_mapped_addr_length_ = BLOCK_SZ;
-        read_ahead_feature_ = false;
-    }
-
-    mapped_addr_ = mmap(NULL, total_mapped_addr_length_, PROT_READ | PROT_WRITE, MAP_SHARED,
-                        cow_fd_.get(), 0);
-    if (mapped_addr_ == MAP_FAILED) {
-        SNAP_LOG(ERROR) << "mmap metadata failed";
-        return false;
-    }
-
-    return true;
-}
-
-void Snapuserd::UnmapBufferRegion() {
-    int ret = munmap(mapped_addr_, total_mapped_addr_length_);
-    if (ret < 0) {
-        SNAP_PLOG(ERROR) << "munmap failed";
-    }
-}
-
-void MyLogger(android::base::LogId, android::base::LogSeverity severity, const char*, const char*,
-              unsigned int, const char* message) {
-    if (severity == android::base::ERROR) {
-        fprintf(stderr, "%s\n", message);
-    } else {
-        fprintf(stdout, "%s\n", message);
-    }
-}
-
-bool Snapuserd::InitCowDevice() {
-    cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
-    if (cow_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
-        return false;
-    }
-
-    return ReadMetadata();
-}
-
-void Snapuserd::ReadBlocksToCache(const std::string& dm_block_device,
-                                  const std::string& partition_name, off_t offset, size_t size) {
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY)));
-    if (fd.get() == -1) {
-        SNAP_PLOG(ERROR) << "Error reading " << dm_block_device
-                         << " partition-name: " << partition_name;
-        return;
-    }
-
-    size_t remain = size;
-    off_t file_offset = offset;
-    // We pick 4M I/O size based on the fact that the current
-    // update_verifier has a similar I/O size.
-    size_t read_sz = 1024 * BLOCK_SZ;
-    std::vector<uint8_t> buf(read_sz);
-
-    while (remain > 0) {
-        size_t to_read = std::min(remain, read_sz);
-
-        if (!android::base::ReadFullyAtOffset(fd.get(), buf.data(), to_read, file_offset)) {
-            SNAP_PLOG(ERROR) << "Failed to read block from block device: " << dm_block_device
-                             << " at offset: " << file_offset
-                             << " partition-name: " << partition_name << " total-size: " << size
-                             << " remain_size: " << remain;
-            return;
-        }
-
-        file_offset += to_read;
-        remain -= to_read;
-    }
-
-    SNAP_LOG(INFO) << "Finished reading block-device: " << dm_block_device
-                   << " partition: " << partition_name << " size: " << size
-                   << " offset: " << offset;
-}
-
-void Snapuserd::ReadBlocks(const std::string& partition_name, const std::string& dm_block_device) {
-    SNAP_LOG(DEBUG) << "Reading partition: " << partition_name
-                    << " Block-Device: " << dm_block_device;
-
-    uint64_t dev_sz = 0;
-
-    unique_fd fd(TEMP_FAILURE_RETRY(open(dm_block_device.c_str(), O_RDONLY | O_CLOEXEC)));
-    if (fd < 0) {
-        SNAP_LOG(ERROR) << "Cannot open block device";
-        return;
-    }
-
-    dev_sz = get_block_device_size(fd.get());
-    if (!dev_sz) {
-        SNAP_PLOG(ERROR) << "Could not determine block device size: " << dm_block_device;
-        return;
-    }
-
-    int num_threads = 2;
-    size_t num_blocks = dev_sz >> BLOCK_SHIFT;
-    size_t num_blocks_per_thread = num_blocks / num_threads;
-    size_t read_sz_per_thread = num_blocks_per_thread << BLOCK_SHIFT;
-    off_t offset = 0;
-
-    for (int i = 0; i < num_threads; i++) {
-        (void)std::async(std::launch::async, &Snapuserd::ReadBlocksToCache, this, dm_block_device,
-                         partition_name, offset, read_sz_per_thread);
-
-        offset += read_sz_per_thread;
-    }
-}
-
-/*
- * Entry point to launch threads
- */
-bool Snapuserd::Start() {
-    std::vector<std::future<bool>> threads;
-    std::future<bool> ra_thread;
-    bool rathread = (read_ahead_feature_ && (read_ahead_ops_.size() > 0));
-
-    // Start the read-ahead thread and wait
-    // for it as the data has to be re-constructed
-    // from COW device.
-    if (rathread) {
-        ra_thread = std::async(std::launch::async, &ReadAheadThread::RunThread,
-                               read_ahead_thread_.get());
-        if (!WaitForReadAheadToStart()) {
-            SNAP_LOG(ERROR) << "Failed to start Read-ahead thread...";
-            return false;
-        }
-
-        SNAP_LOG(INFO) << "Read-ahead thread started...";
-    }
-
-    // Launch worker threads
-    for (int i = 0; i < worker_threads_.size(); i++) {
-        threads.emplace_back(
-                std::async(std::launch::async, &WorkerThread::RunThread, worker_threads_[i].get()));
-    }
-
-    bool second_stage_init = true;
-
-    // We don't want to read the blocks during first stage init.
-    if (android::base::EndsWith(misc_name_, "-init") || is_socket_present_) {
-        second_stage_init = false;
-    }
-
-    if (second_stage_init) {
-        SNAP_LOG(INFO) << "Reading blocks to cache....";
-        auto& dm = DeviceMapper::Instance();
-        auto dm_block_devices = dm.FindDmPartitions();
-        if (dm_block_devices.empty()) {
-            SNAP_LOG(ERROR) << "No dm-enabled block device is found.";
-        } else {
-            auto parts = android::base::Split(misc_name_, "-");
-            std::string partition_name = parts[0];
-
-            const char* suffix_b = "_b";
-            const char* suffix_a = "_a";
-
-            partition_name.erase(partition_name.find_last_not_of(suffix_b) + 1);
-            partition_name.erase(partition_name.find_last_not_of(suffix_a) + 1);
-
-            if (dm_block_devices.find(partition_name) == dm_block_devices.end()) {
-                SNAP_LOG(ERROR) << "Failed to find dm block device for " << partition_name;
-            } else {
-                ReadBlocks(partition_name, dm_block_devices.at(partition_name));
-            }
-        }
-    } else {
-        SNAP_LOG(INFO) << "Not reading block device into cache";
-    }
-
-    bool ret = true;
-    for (auto& t : threads) {
-        ret = t.get() && ret;
-    }
-
-    if (rathread) {
-        // Notify the read-ahead thread that all worker threads
-        // are done. We need this explicit notification when
-        // there is an IO failure or there was a switch
-        // of dm-user table; thus, forcing the read-ahead
-        // thread to wake up.
-        MergeCompleted();
-        ret = ret && ra_thread.get();
-    }
-
-    return ret;
-}
-
-uint64_t Snapuserd::GetBufferMetadataOffset() {
-    const auto& header = reader_->GetHeader();
-
-    size_t size = header.prefix.header_size + sizeof(BufferState);
-    return size;
-}
-
-/*
- * Metadata for read-ahead is 16 bytes. For a 2 MB region, we will
- * end up with 8k (2 PAGE) worth of metadata. Thus, a 2MB buffer
- * region is split into:
- *
- * 1: 8k metadata
- *
- */
-size_t Snapuserd::GetBufferMetadataSize() {
-    const auto& header = reader_->GetHeader();
-
-    size_t metadata_bytes = (header.buffer_size * sizeof(struct ScratchMetadata)) / BLOCK_SZ;
-    return metadata_bytes;
-}
-
-size_t Snapuserd::GetBufferDataOffset() {
-    const auto& header = reader_->GetHeader();
-
-    return (header.prefix.header_size + GetBufferMetadataSize());
-}
-
-/*
- * (2MB - 8K = 2088960 bytes) will be the buffer region to hold the data.
- */
-size_t Snapuserd::GetBufferDataSize() {
-    const auto& header = reader_->GetHeader();
-
-    size_t size = header.buffer_size - GetBufferMetadataSize();
-    return size;
-}
-
-struct BufferState* Snapuserd::GetBufferState() {
-    const auto& header = reader_->GetHeader();
-
-    struct BufferState* ra_state =
-            reinterpret_cast<struct BufferState*>((char*)mapped_addr_ + header.prefix.header_size);
-    return ra_state;
-}
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h
deleted file mode 100644
index beb6004..0000000
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd.h
+++ /dev/null
@@ -1,332 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <linux/types.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <sys/mman.h>
-
-#include <bitset>
-#include <condition_variable>
-#include <csignal>
-#include <cstring>
-#include <future>
-#include <iostream>
-#include <limits>
-#include <map>
-#include <mutex>
-#include <string>
-#include <thread>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include <android-base/file.h>
-#include <android-base/logging.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <ext4_utils/ext4_utils.h>
-#include <libdm/dm.h>
-#include <libsnapshot/cow_reader.h>
-#include <libsnapshot/cow_writer.h>
-#include <snapuserd/snapuserd_buffer.h>
-#include <snapuserd/snapuserd_kernel.h>
-
-namespace android {
-namespace snapshot {
-
-using android::base::unique_fd;
-using namespace std::chrono_literals;
-
-static constexpr size_t PAYLOAD_SIZE = (1UL << 20);
-static_assert(PAYLOAD_SIZE >= BLOCK_SZ);
-
-/*
- * With 4 threads, we get optimal performance
- * when update_verifier reads the partition during
- * boot.
- */
-static constexpr int NUM_THREADS_PER_PARTITION = 4;
-
-/*
- * State transitions between worker threads and read-ahead
- * threads.
- *
- * READ_AHEAD_BEGIN: Worker threads initiates the read-ahead
- *                   thread to begin reading the copy operations
- *                   for each bounded region.
- *
- * READ_AHEAD_IN_PROGRESS: When read ahead thread is in-flight
- *                         and reading the copy operations.
- *
- * IO_IN_PROGRESS: Merge operation is in-progress by worker threads.
- *
- * IO_TERMINATED: When all the worker threads are done, request the
- *                read-ahead thread to terminate
- *
- * READ_AHEAD_FAILURE: If there are any IO failures when read-ahead
- *                     thread is reading from COW device.
- *
- * The transition of each states is described in snapuserd_readahead.cpp
- */
-enum class READ_AHEAD_IO_TRANSITION {
-    READ_AHEAD_BEGIN,
-    READ_AHEAD_IN_PROGRESS,
-    IO_IN_PROGRESS,
-    IO_TERMINATED,
-    READ_AHEAD_FAILURE,
-};
-
-class Snapuserd;
-
-class ReadAheadThread {
-  public:
-    ReadAheadThread(const std::string& cow_device, const std::string& backing_device,
-                    const std::string& misc_name, std::shared_ptr<Snapuserd> snapuserd);
-    bool RunThread();
-
-  private:
-    void InitializeRAIter();
-    bool RAIterDone();
-    void RAIterNext();
-    const CowOperation* GetRAOpIter();
-    void InitializeBuffer();
-
-    bool InitializeFds();
-    void CloseFds() {
-        cow_fd_ = {};
-        backing_store_fd_ = {};
-    }
-
-    bool ReadAheadIOStart();
-    void PrepareReadAhead(uint64_t* source_offset, int* pending_ops, std::vector<uint64_t>& blocks);
-    bool ReconstructDataFromCow();
-    void CheckOverlap(const CowOperation* cow_op);
-
-    void* read_ahead_buffer_;
-    void* metadata_buffer_;
-    std::vector<const CowOperation*>::reverse_iterator read_ahead_iter_;
-    std::string cow_device_;
-    std::string backing_store_device_;
-    std::string misc_name_;
-
-    unique_fd cow_fd_;
-    unique_fd backing_store_fd_;
-
-    std::shared_ptr<Snapuserd> snapuserd_;
-
-    std::unordered_set<uint64_t> dest_blocks_;
-    std::unordered_set<uint64_t> source_blocks_;
-    bool overlap_;
-};
-
-class WorkerThread {
-  public:
-    WorkerThread(const std::string& cow_device, const std::string& backing_device,
-                 const std::string& control_device, const std::string& misc_name,
-                 std::shared_ptr<Snapuserd> snapuserd);
-    bool RunThread();
-
-  private:
-    // Initialization
-    void InitializeBufsink();
-    bool InitializeFds();
-    bool InitReader();
-    void CloseFds() {
-        ctrl_fd_ = {};
-        backing_store_fd_ = {};
-    }
-
-    // Functions interacting with dm-user
-    bool ReadDmUserHeader();
-    bool DmuserReadRequest();
-    bool DmuserWriteRequest();
-    bool ReadDmUserPayload(void* buffer, size_t size);
-    bool WriteDmUserPayload(size_t size, bool header_response);
-
-    bool ReadDiskExceptions(chunk_t chunk, size_t size);
-    bool ZerofillDiskExceptions(size_t read_size);
-    void ConstructKernelCowHeader();
-
-    // IO Path
-    bool ProcessIORequest();
-    int ReadData(sector_t sector, size_t size);
-    int ReadUnalignedSector(sector_t sector, size_t size,
-                            std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it);
-
-    // Processing COW operations
-    bool ProcessCowOp(const CowOperation* cow_op);
-    bool ProcessReplaceOp(const CowOperation* cow_op);
-    // Handles Copy
-    bool ProcessCopyOp(const CowOperation* cow_op);
-    bool ProcessZeroOp();
-
-    bool ReadFromBaseDevice(const CowOperation* cow_op);
-    bool GetReadAheadPopulatedBuffer(const CowOperation* cow_op);
-
-    // Merge related functions
-    bool ProcessMergeComplete(chunk_t chunk, void* buffer);
-    loff_t GetMergeStartOffset(void* merged_buffer, void* unmerged_buffer,
-                               int* unmerged_exceptions);
-
-    int GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffer, loff_t offset,
-                             int unmerged_exceptions, bool* copy_op, bool* commit);
-
-    sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
-    chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; }
-
-    std::unique_ptr<CowReader> reader_;
-    BufferSink bufsink_;
-
-    std::string cow_device_;
-    std::string backing_store_device_;
-    std::string control_device_;
-    std::string misc_name_;
-
-    unique_fd cow_fd_;
-    unique_fd backing_store_fd_;
-    unique_fd ctrl_fd_;
-
-    std::shared_ptr<Snapuserd> snapuserd_;
-    uint32_t exceptions_per_area_;
-};
-
-class Snapuserd : public std::enable_shared_from_this<Snapuserd> {
-  public:
-    Snapuserd(const std::string& misc_name, const std::string& cow_device,
-              const std::string& backing_device);
-    bool InitCowDevice();
-    bool Start();
-    const std::string& GetControlDevicePath() { return control_device_; }
-    const std::string& GetMiscName() { return misc_name_; }
-    uint64_t GetNumSectors() { return num_sectors_; }
-    bool IsAttached() const { return attached_; }
-    void AttachControlDevice() { attached_ = true; }
-
-    void CheckMergeCompletionStatus();
-    bool CommitMerge(int num_merge_ops);
-
-    void CloseFds() { cow_fd_ = {}; }
-    void FreeResources() {
-        worker_threads_.clear();
-        read_ahead_thread_ = nullptr;
-    }
-    size_t GetMetadataAreaSize() { return vec_.size(); }
-    void* GetExceptionBuffer(size_t i) { return vec_[i].get(); }
-
-    bool InitializeWorkers();
-    std::unique_ptr<CowReader> CloneReaderForWorker();
-    std::shared_ptr<Snapuserd> GetSharedPtr() { return shared_from_this(); }
-
-    std::vector<std::pair<sector_t, const CowOperation*>>& GetChunkVec() { return chunk_vec_; }
-    const std::vector<std::unique_ptr<uint8_t[]>>& GetMetadataVec() const { return vec_; }
-
-    static bool compare(std::pair<sector_t, const CowOperation*> p1,
-                        std::pair<sector_t, const CowOperation*> p2) {
-        return p1.first < p2.first;
-    }
-
-    void UnmapBufferRegion();
-    bool MmapMetadata();
-
-    // Read-ahead related functions
-    std::vector<const CowOperation*>& GetReadAheadOpsVec() { return read_ahead_ops_; }
-    std::unordered_map<uint64_t, void*>& GetReadAheadMap() { return read_ahead_buffer_map_; }
-    void* GetMappedAddr() { return mapped_addr_; }
-    bool IsReadAheadFeaturePresent() { return read_ahead_feature_; }
-    void PrepareReadAhead();
-    void StartReadAhead();
-    void MergeCompleted();
-    bool ReadAheadIOCompleted(bool sync);
-    void ReadAheadIOFailed();
-    bool WaitForMergeToComplete();
-    bool GetReadAheadPopulatedBuffer(uint64_t block, void* buffer);
-    bool ReconstructDataFromCow() { return populate_data_from_cow_; }
-    void ReconstructDataFromCowFinish() { populate_data_from_cow_ = false; }
-    bool WaitForReadAheadToStart();
-
-    uint64_t GetBufferMetadataOffset();
-    size_t GetBufferMetadataSize();
-    size_t GetBufferDataOffset();
-    size_t GetBufferDataSize();
-
-    // Final block to be merged in a given read-ahead buffer region
-    void SetFinalBlockMerged(uint64_t x) { final_block_merged_ = x; }
-    uint64_t GetFinalBlockMerged() { return final_block_merged_; }
-    // Total number of blocks to be merged in a given read-ahead buffer region
-    void SetTotalRaBlocksMerged(int x) { total_ra_blocks_merged_ = x; }
-    int GetTotalRaBlocksMerged() { return total_ra_blocks_merged_; }
-    void SetSocketPresent(bool socket) { is_socket_present_ = socket; }
-
-  private:
-    bool IsChunkIdMetadata(chunk_t chunk);
-    chunk_t GetNextAllocatableChunkId(chunk_t chunk_id);
-
-    bool GetRABuffer(std::unique_lock<std::mutex>* lock, uint64_t block, void* buffer);
-    bool ReadMetadata();
-    sector_t ChunkToSector(chunk_t chunk) { return chunk << CHUNK_SHIFT; }
-    chunk_t SectorToChunk(sector_t sector) { return sector >> CHUNK_SHIFT; }
-    bool IsBlockAligned(int read_size) { return ((read_size & (BLOCK_SZ - 1)) == 0); }
-    struct BufferState* GetBufferState();
-
-    void ReadBlocks(const std::string& partition_name, const std::string& dm_block_device);
-    void ReadBlocksToCache(const std::string& dm_block_device, const std::string& partition_name,
-                           off_t offset, size_t size);
-
-    std::string cow_device_;
-    std::string backing_store_device_;
-    std::string control_device_;
-    std::string misc_name_;
-
-    unique_fd cow_fd_;
-
-    uint32_t exceptions_per_area_;
-    uint64_t num_sectors_;
-
-    std::unique_ptr<CowReader> reader_;
-
-    // Vector of disk exception which is a
-    // mapping of old-chunk to new-chunk
-    std::vector<std::unique_ptr<uint8_t[]>> vec_;
-
-    // chunk_vec stores the pseudo mapping of sector
-    // to COW operations.
-    std::vector<std::pair<sector_t, const CowOperation*>> chunk_vec_;
-
-    std::mutex lock_;
-    std::condition_variable cv;
-
-    void* mapped_addr_;
-    size_t total_mapped_addr_length_;
-
-    std::vector<std::unique_ptr<WorkerThread>> worker_threads_;
-    // Read-ahead related
-    std::unordered_map<uint64_t, void*> read_ahead_buffer_map_;
-    std::vector<const CowOperation*> read_ahead_ops_;
-    bool populate_data_from_cow_ = false;
-    bool read_ahead_feature_;
-    uint64_t final_block_merged_;
-    int total_ra_blocks_merged_ = 0;
-    READ_AHEAD_IO_TRANSITION io_state_;
-    std::unique_ptr<ReadAheadThread> read_ahead_thread_;
-
-    bool merge_initiated_ = false;
-    bool attached_ = false;
-    bool is_socket_present_;
-};
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
deleted file mode 100644
index f1b9245..0000000
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_readahead.cpp
+++ /dev/null
@@ -1,482 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "snapuserd.h"
-
-#include <csignal>
-#include <optional>
-#include <set>
-
-#include <snapuserd/snapuserd_client.h>
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-#define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
-#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
-
-/*
- * Merging a copy operation involves the following flow:
- *
- * 1: dm-snapshot layer requests merge for a 4k block. dm-user sends the request
- *    to the daemon
- * 2: daemon reads the source block
- * 3: daemon copies the source data
- * 4: IO completion sent back to dm-user (a switch from user space to kernel)
- * 5: dm-snapshot merges the data to base device
- * 6: dm-snapshot sends the merge-completion IO to dm-user
- * 7: dm-user re-directs the merge completion IO to daemon (one more switch)
- * 8: daemon updates the COW file about the completed merge request (a write syscall) and followed
- * by a fysnc. 9: Send the IO completion back to dm-user
- *
- * The above sequence is a significant overhead especially when merging one 4k
- * block at a time.
- *
- * Read-ahead layer will optimize the above path by reading the data from base
- * device in the background so that merging thread can retrieve the data from
- * the read-ahead cache. Additionally, syncing of merged data is deferred to
- * read-ahead thread threadby the IO path is not bottlenecked.
- *
- * We create a scratch space of 2MB to store the read-ahead data in the COW
- * device.
- *
- *      +-----------------------+
- *      |     Header (fixed)    |
- *      +-----------------------+
- *      |    Scratch space      |  <-- 2MB
- *      +-----------------------+
- *
- *      Scratch space is as follows:
- *
- *      +-----------------------+
- *      |       Metadata        | <- 4k page
- *      +-----------------------+
- *      |       Metadata        | <- 4k page
- *      +-----------------------+
- *      |                       |
- *      |    Read-ahead data    |
- *      |                       |
- *      +-----------------------+
- *
- * State transitions and communication between read-ahead thread and worker
- * thread during merge:
- * =====================================================================
- *
- *   Worker Threads                                 Read-Ahead thread
- *   ------------------------------------------------------------------
- *
- *      |
- *      |
- *  --> -----------------READ_AHEAD_BEGIN------------->|
- *  |   |                                              | READ_AHEAD_IN_PROGRESS
- *  |  WAIT                                            |
- *  |   |                                              |
- *  |   |<-----------------IO_IN_PROGRESS---------------
- *  |   |                                              |
- *  |   | IO_IN_PRGRESS                               WAIT
- *  |   |                                              |
- *  |<--|                                              |
- *      |                                              |
- *      ------------------IO_TERMINATED--------------->|
- *                                                     END
- *
- *
- * ===================================================================
- *
- * Example:
- *
- * We have 6 copy operations to be executed in OTA and there is a overlap. Update-engine
- * will write to COW file as follows:
- *
- * Op-1: 20 -> 23
- * Op-2: 19 -> 22
- * Op-3: 18 -> 21
- * Op-4: 17 -> 20
- * Op-5: 16 -> 19
- * Op-6: 15 -> 18
- *
- * Read-ahead thread will read all the 6 source blocks and store the data in the
- * scratch space. Metadata will contain the destination block numbers. Thus,
- * scratch space will look something like this:
- *
- * +--------------+
- * | Block   23   |
- * | offset - 1   |
- * +--------------+
- * | Block   22   |
- * | offset - 2   |
- * +--------------+
- * | Block   21   |
- * | offset - 3   |
- * +--------------+
- *    ...
- *    ...
- * +--------------+
- * | Data-Block 20| <-- offset - 1
- * +--------------+
- * | Data-Block 19| <-- offset - 2
- * +--------------+
- * | Data-Block 18| <-- offset - 3
- * +--------------+
- *     ...
- *     ...
- *
- * ====================================================================
- * IO Path:
- *
- * Read-ahead will serve the data to worker threads during merge only
- * after metadata and data are persisted to the scratch space. Worker
- * threads during merge will always retrieve the data from cache; if the
- * cache is not populated, it will wait for the read-ahead thread to finish.
- * Furthermore, the number of operations merged will by synced to the header
- * only when all the blocks in the read-ahead cache are merged. In the above
- * case, when all 6 operations are merged, COW Header is updated with
- * num_merge_ops = 6.
- *
- * Merge resume after crash:
- *
- * Let's say we have a crash after 5 operations are merged. i.e. after
- * Op-5: 16->19 is completed but before the Op-6 is merged. Thus, COW Header
- * num_merge_ops will be 0 as the all the ops were not merged yet. During next
- * reboot, read-ahead thread will re-construct the data in-memory from the
- * scratch space; when merge resumes, Op-1 will be re-exectued. However,
- * data will be served from read-ahead cache safely even though, block 20
- * was over-written by Op-4.
- *
- */
-
-ReadAheadThread::ReadAheadThread(const std::string& cow_device, const std::string& backing_device,
-                                 const std::string& misc_name,
-                                 std::shared_ptr<Snapuserd> snapuserd) {
-    cow_device_ = cow_device;
-    backing_store_device_ = backing_device;
-    misc_name_ = misc_name;
-    snapuserd_ = snapuserd;
-}
-
-void ReadAheadThread::CheckOverlap(const CowOperation* cow_op) {
-    uint64_t source_block = cow_op->source();
-    if (dest_blocks_.count(cow_op->new_block) || source_blocks_.count(source_block)) {
-        overlap_ = true;
-    }
-
-    dest_blocks_.insert(source_block);
-    source_blocks_.insert(cow_op->new_block);
-}
-
-void ReadAheadThread::PrepareReadAhead(uint64_t* source_offset, int* pending_ops,
-                                       std::vector<uint64_t>& blocks) {
-    int num_ops = *pending_ops;
-    int nr_consecutive = 0;
-    CHECK_NE(source_offset, nullptr);
-
-    if (!RAIterDone() && num_ops) {
-        // Get the first block with offset
-        const CowOperation* cow_op = GetRAOpIter();
-        CHECK_NE(cow_op, nullptr);
-        *source_offset = cow_op->source();
-        if (cow_op->type() == kCowCopyOp) {
-            *source_offset *= BLOCK_SZ;
-        }
-        RAIterNext();
-        num_ops -= 1;
-        nr_consecutive = 1;
-        blocks.push_back(cow_op->new_block);
-
-        if (!overlap_) {
-            CheckOverlap(cow_op);
-        }
-
-        /*
-         * Find number of consecutive blocks working backwards.
-         */
-        while (!RAIterDone() && num_ops) {
-            const CowOperation* op = GetRAOpIter();
-            CHECK_NE(op, nullptr);
-            uint64_t next_offset = op->source();
-            if (op->type() == kCowCopyOp) {
-                next_offset *= BLOCK_SZ;
-            }
-            if (next_offset + nr_consecutive * BLOCK_SZ != *source_offset) {
-                break;
-            }
-            nr_consecutive += 1;
-            num_ops -= 1;
-            blocks.push_back(op->new_block);
-            RAIterNext();
-
-            if (!overlap_) {
-                CheckOverlap(op);
-            }
-        }
-    }
-}
-
-bool ReadAheadThread::ReconstructDataFromCow() {
-    std::unordered_map<uint64_t, void*>& read_ahead_buffer_map = snapuserd_->GetReadAheadMap();
-    read_ahead_buffer_map.clear();
-    loff_t metadata_offset = 0;
-    loff_t start_data_offset = snapuserd_->GetBufferDataOffset();
-    int num_ops = 0;
-    int total_blocks_merged = 0;
-
-    // This memcpy is important as metadata_buffer_ will be an unaligned address and will fault
-    // on 32-bit systems
-    std::unique_ptr<uint8_t[]> metadata_buffer =
-            std::make_unique<uint8_t[]>(snapuserd_->GetBufferMetadataSize());
-    memcpy(metadata_buffer.get(), metadata_buffer_, snapuserd_->GetBufferMetadataSize());
-
-    while (true) {
-        struct ScratchMetadata* bm = reinterpret_cast<struct ScratchMetadata*>(
-                (char*)metadata_buffer.get() + metadata_offset);
-
-        // Done reading metadata
-        if (bm->new_block == 0 && bm->file_offset == 0) {
-            break;
-        }
-
-        loff_t buffer_offset = bm->file_offset - start_data_offset;
-        void* bufptr = static_cast<void*>((char*)read_ahead_buffer_ + buffer_offset);
-        read_ahead_buffer_map[bm->new_block] = bufptr;
-        num_ops += 1;
-        total_blocks_merged += 1;
-
-        metadata_offset += sizeof(struct ScratchMetadata);
-    }
-
-    // We are done re-constructing the mapping; however, we need to make sure
-    // all the COW operations to-be merged are present in the re-constructed
-    // mapping.
-    while (!RAIterDone()) {
-        const CowOperation* op = GetRAOpIter();
-        if (read_ahead_buffer_map.find(op->new_block) != read_ahead_buffer_map.end()) {
-            num_ops -= 1;
-            snapuserd_->SetFinalBlockMerged(op->new_block);
-            RAIterNext();
-        } else {
-            // Verify that we have covered all the ops which were re-constructed
-            // from COW device - These are the ops which are being
-            // re-constructed after crash.
-            if (!(num_ops == 0)) {
-                SNAP_LOG(ERROR) << "ReconstructDataFromCow failed. Not all ops recoverd "
-                                << " Pending ops: " << num_ops;
-                snapuserd_->ReadAheadIOFailed();
-                return false;
-            }
-            break;
-        }
-    }
-
-    snapuserd_->SetTotalRaBlocksMerged(total_blocks_merged);
-
-    snapuserd_->ReconstructDataFromCowFinish();
-
-    if (!snapuserd_->ReadAheadIOCompleted(true)) {
-        SNAP_LOG(ERROR) << "ReadAheadIOCompleted failed...";
-        snapuserd_->ReadAheadIOFailed();
-        return false;
-    }
-
-    SNAP_LOG(INFO) << "ReconstructDataFromCow success";
-    return true;
-}
-
-bool ReadAheadThread::ReadAheadIOStart() {
-    // Check if the data has to be constructed from the COW file.
-    // This will be true only once during boot up after a crash
-    // during merge.
-    if (snapuserd_->ReconstructDataFromCow()) {
-        return ReconstructDataFromCow();
-    }
-
-    std::unordered_map<uint64_t, void*>& read_ahead_buffer_map = snapuserd_->GetReadAheadMap();
-    read_ahead_buffer_map.clear();
-
-    int num_ops = (snapuserd_->GetBufferDataSize()) / BLOCK_SZ;
-    loff_t metadata_offset = 0;
-
-    struct ScratchMetadata* bm =
-            reinterpret_cast<struct ScratchMetadata*>((char*)metadata_buffer_ + metadata_offset);
-
-    bm->new_block = 0;
-    bm->file_offset = 0;
-
-    std::vector<uint64_t> blocks;
-
-    loff_t buffer_offset = 0;
-    loff_t offset = 0;
-    loff_t file_offset = snapuserd_->GetBufferDataOffset();
-    int total_blocks_merged = 0;
-    overlap_ = false;
-    dest_blocks_.clear();
-    source_blocks_.clear();
-
-    while (true) {
-        uint64_t source_offset;
-        int linear_blocks;
-
-        PrepareReadAhead(&source_offset, &num_ops, blocks);
-        linear_blocks = blocks.size();
-        if (linear_blocks == 0) {
-            // No more blocks to read
-            SNAP_LOG(DEBUG) << " Read-ahead completed....";
-            break;
-        }
-
-        // Get the first block in the consecutive set of blocks
-        source_offset = source_offset - (linear_blocks - 1) * BLOCK_SZ;
-        size_t io_size = (linear_blocks * BLOCK_SZ);
-        num_ops -= linear_blocks;
-        total_blocks_merged += linear_blocks;
-
-        // Mark the block number as the one which will
-        // be the final block to be merged in this entire region.
-        // Read-ahead thread will get
-        // notified when this block is merged to make
-        // forward progress
-        snapuserd_->SetFinalBlockMerged(blocks.back());
-
-        while (linear_blocks) {
-            uint64_t new_block = blocks.back();
-            blocks.pop_back();
-            // Assign the mapping
-            void* bufptr = static_cast<void*>((char*)read_ahead_buffer_ + offset);
-            read_ahead_buffer_map[new_block] = bufptr;
-            offset += BLOCK_SZ;
-
-            bm = reinterpret_cast<struct ScratchMetadata*>((char*)metadata_buffer_ +
-                                                           metadata_offset);
-            bm->new_block = new_block;
-            bm->file_offset = file_offset;
-
-            metadata_offset += sizeof(struct ScratchMetadata);
-            file_offset += BLOCK_SZ;
-
-            linear_blocks -= 1;
-        }
-
-        // Read from the base device consecutive set of blocks in one shot
-        if (!android::base::ReadFullyAtOffset(backing_store_fd_,
-                                              (char*)read_ahead_buffer_ + buffer_offset, io_size,
-                                              source_offset)) {
-            SNAP_PLOG(ERROR) << "Ordered-op failed. Read from backing store: "
-                             << backing_store_device_ << "at block :" << source_offset / BLOCK_SZ
-                             << " offset :" << source_offset % BLOCK_SZ
-                             << " buffer_offset : " << buffer_offset << " io_size : " << io_size
-                             << " buf-addr : " << read_ahead_buffer_;
-
-            snapuserd_->ReadAheadIOFailed();
-            return false;
-        }
-
-        // This is important - explicitly set the contents to zero. This is used
-        // when re-constructing the data after crash. This indicates end of
-        // reading metadata contents when re-constructing the data
-        bm = reinterpret_cast<struct ScratchMetadata*>((char*)metadata_buffer_ + metadata_offset);
-        bm->new_block = 0;
-        bm->file_offset = 0;
-
-        buffer_offset += io_size;
-    }
-
-    snapuserd_->SetTotalRaBlocksMerged(total_blocks_merged);
-
-    // Flush the data only if we have a overlapping blocks in the region
-    if (!snapuserd_->ReadAheadIOCompleted(overlap_)) {
-        SNAP_LOG(ERROR) << "ReadAheadIOCompleted failed...";
-        snapuserd_->ReadAheadIOFailed();
-        return false;
-    }
-
-    return true;
-}
-
-bool ReadAheadThread::RunThread() {
-    if (!InitializeFds()) {
-        return false;
-    }
-
-    InitializeRAIter();
-    InitializeBuffer();
-
-    while (!RAIterDone()) {
-        if (!ReadAheadIOStart()) {
-            return false;
-        }
-
-        bool status = snapuserd_->WaitForMergeToComplete();
-
-        if (status && !snapuserd_->CommitMerge(snapuserd_->GetTotalRaBlocksMerged())) {
-            return false;
-        }
-
-        if (!status) break;
-    }
-
-    CloseFds();
-    SNAP_LOG(INFO) << " ReadAhead thread terminating....";
-    return true;
-}
-
-// Initialization
-bool ReadAheadThread::InitializeFds() {
-    backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
-    if (backing_store_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_;
-        return false;
-    }
-
-    cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
-    if (cow_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
-        return false;
-    }
-
-    return true;
-}
-
-void ReadAheadThread::InitializeRAIter() {
-    std::vector<const CowOperation*>& read_ahead_ops = snapuserd_->GetReadAheadOpsVec();
-    read_ahead_iter_ = read_ahead_ops.rbegin();
-}
-
-bool ReadAheadThread::RAIterDone() {
-    std::vector<const CowOperation*>& read_ahead_ops = snapuserd_->GetReadAheadOpsVec();
-    return read_ahead_iter_ == read_ahead_ops.rend();
-}
-
-void ReadAheadThread::RAIterNext() {
-    read_ahead_iter_++;
-}
-
-const CowOperation* ReadAheadThread::GetRAOpIter() {
-    return *read_ahead_iter_;
-}
-
-void ReadAheadThread::InitializeBuffer() {
-    void* mapped_addr = snapuserd_->GetMappedAddr();
-    // Map the scratch space region into memory
-    metadata_buffer_ =
-            static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferMetadataOffset());
-    read_ahead_buffer_ = static_cast<void*>((char*)mapped_addr + snapuserd_->GetBufferDataOffset());
-}
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp
deleted file mode 100644
index 577b09d..0000000
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.cpp
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <arpa/inet.h>
-#include <cutils/sockets.h>
-#include <errno.h>
-#include <netinet/in.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <android-base/cmsg.h>
-#include <android-base/logging.h>
-#include <android-base/properties.h>
-#include <android-base/scopeguard.h>
-#include <fs_mgr/file_wait.h>
-#include <snapuserd/snapuserd_client.h>
-
-#include "snapuserd_server.h"
-
-#define _REALLY_INCLUDE_SYS__SYSTEM_PROPERTIES_H_
-#include <sys/_system_properties.h>
-
-namespace android {
-namespace snapshot {
-
-using namespace std::string_literals;
-
-using android::base::borrowed_fd;
-using android::base::unique_fd;
-
-DaemonOperations SnapuserdServer::Resolveop(std::string& input) {
-    if (input == "init") return DaemonOperations::INIT;
-    if (input == "start") return DaemonOperations::START;
-    if (input == "stop") return DaemonOperations::STOP;
-    if (input == "query") return DaemonOperations::QUERY;
-    if (input == "delete") return DaemonOperations::DELETE;
-    if (input == "detach") return DaemonOperations::DETACH;
-    if (input == "supports") return DaemonOperations::SUPPORTS;
-
-    return DaemonOperations::INVALID;
-}
-
-SnapuserdServer::~SnapuserdServer() {
-    // Close any client sockets that were added via AcceptClient().
-    for (size_t i = 1; i < watched_fds_.size(); i++) {
-        close(watched_fds_[i].fd);
-    }
-}
-
-std::string SnapuserdServer::GetDaemonStatus() {
-    std::string msg = "";
-
-    if (IsTerminating())
-        msg = "passive";
-    else
-        msg = "active";
-
-    return msg;
-}
-
-void SnapuserdServer::Parsemsg(std::string const& msg, const char delim,
-                               std::vector<std::string>& out) {
-    std::stringstream ss(msg);
-    std::string s;
-
-    while (std::getline(ss, s, delim)) {
-        out.push_back(s);
-    }
-}
-
-void SnapuserdServer::ShutdownThreads() {
-    StopThreads();
-    JoinAllThreads();
-}
-
-DmUserHandler::DmUserHandler(std::shared_ptr<Snapuserd> snapuserd)
-    : snapuserd_(snapuserd), misc_name_(snapuserd_->GetMiscName()) {}
-
-bool SnapuserdServer::Sendmsg(android::base::borrowed_fd fd, const std::string& msg) {
-    ssize_t ret = TEMP_FAILURE_RETRY(send(fd.get(), msg.data(), msg.size(), MSG_NOSIGNAL));
-    if (ret < 0) {
-        PLOG(ERROR) << "Snapuserd:server: send() failed";
-        return false;
-    }
-
-    if (ret < msg.size()) {
-        LOG(ERROR) << "Partial send; expected " << msg.size() << " bytes, sent " << ret;
-        return false;
-    }
-    return true;
-}
-
-bool SnapuserdServer::Recv(android::base::borrowed_fd fd, std::string* data) {
-    char msg[MAX_PACKET_SIZE];
-    ssize_t rv = TEMP_FAILURE_RETRY(recv(fd.get(), msg, sizeof(msg), 0));
-    if (rv < 0) {
-        PLOG(ERROR) << "recv failed";
-        return false;
-    }
-    *data = std::string(msg, rv);
-    return true;
-}
-
-bool SnapuserdServer::Receivemsg(android::base::borrowed_fd fd, const std::string& str) {
-    const char delim = ',';
-
-    std::vector<std::string> out;
-    Parsemsg(str, delim, out);
-    DaemonOperations op = Resolveop(out[0]);
-
-    switch (op) {
-        case DaemonOperations::INIT: {
-            // Message format:
-            // init,<misc_name>,<cow_device_path>,<backing_device>
-            //
-            // Reads the metadata and send the number of sectors
-            if (out.size() != 4) {
-                LOG(ERROR) << "Malformed init message, " << out.size() << " parts";
-                return Sendmsg(fd, "fail");
-            }
-
-            auto handler = AddHandler(out[1], out[2], out[3]);
-            if (!handler) {
-                return Sendmsg(fd, "fail");
-            }
-
-            auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors());
-            return Sendmsg(fd, retval);
-        }
-        case DaemonOperations::START: {
-            // Message format:
-            // start,<misc_name>
-            //
-            // Start the new thread which binds to dm-user misc device
-            if (out.size() != 2) {
-                LOG(ERROR) << "Malformed start message, " << out.size() << " parts";
-                return Sendmsg(fd, "fail");
-            }
-
-            std::lock_guard<std::mutex> lock(lock_);
-            auto iter = FindHandler(&lock, out[1]);
-            if (iter == dm_users_.end()) {
-                LOG(ERROR) << "Could not find handler: " << out[1];
-                return Sendmsg(fd, "fail");
-            }
-            if (!(*iter)->snapuserd() || (*iter)->snapuserd()->IsAttached()) {
-                LOG(ERROR) << "Tried to re-attach control device: " << out[1];
-                return Sendmsg(fd, "fail");
-            }
-            if (!StartHandler(*iter)) {
-                return Sendmsg(fd, "fail");
-            }
-            return Sendmsg(fd, "success");
-        }
-        case DaemonOperations::STOP: {
-            // Message format: stop
-            //
-            // Stop all the threads gracefully and then shutdown the
-            // main thread
-            SetTerminating();
-            ShutdownThreads();
-            return true;
-        }
-        case DaemonOperations::QUERY: {
-            // Message format: query
-            //
-            // As part of transition, Second stage daemon will be
-            // created before terminating the first stage daemon. Hence,
-            // for a brief period client may have to distiguish between
-            // first stage daemon and second stage daemon.
-            //
-            // Second stage daemon is marked as active and hence will
-            // be ready to receive control message.
-            return Sendmsg(fd, GetDaemonStatus());
-        }
-        case DaemonOperations::DELETE: {
-            // Message format:
-            // delete,<misc_name>
-            if (out.size() != 2) {
-                LOG(ERROR) << "Malformed delete message, " << out.size() << " parts";
-                return Sendmsg(fd, "fail");
-            }
-            if (!RemoveAndJoinHandler(out[1])) {
-                return Sendmsg(fd, "fail");
-            }
-            return Sendmsg(fd, "success");
-        }
-        case DaemonOperations::DETACH: {
-            terminating_ = true;
-            return true;
-        }
-        case DaemonOperations::SUPPORTS: {
-            if (out.size() != 2) {
-                LOG(ERROR) << "Malformed supports message, " << out.size() << " parts";
-                return Sendmsg(fd, "fail");
-            }
-            if (out[1] == "second_stage_socket_handoff") {
-                return Sendmsg(fd, "success");
-            }
-            return Sendmsg(fd, "fail");
-        }
-        default: {
-            LOG(ERROR) << "Received unknown message type from client";
-            Sendmsg(fd, "fail");
-            return false;
-        }
-    }
-}
-
-void SnapuserdServer::RunThread(std::shared_ptr<DmUserHandler> handler) {
-    LOG(INFO) << "Entering thread for handler: " << handler->misc_name();
-
-    handler->snapuserd()->SetSocketPresent(is_socket_present_);
-    if (!handler->snapuserd()->Start()) {
-        LOG(ERROR) << " Failed to launch all worker threads";
-    }
-
-    handler->snapuserd()->CloseFds();
-    handler->snapuserd()->CheckMergeCompletionStatus();
-    handler->snapuserd()->UnmapBufferRegion();
-
-    auto misc_name = handler->misc_name();
-    LOG(INFO) << "Handler thread about to exit: " << misc_name;
-
-    {
-        std::lock_guard<std::mutex> lock(lock_);
-        auto iter = FindHandler(&lock, handler->misc_name());
-        if (iter == dm_users_.end()) {
-            // RemoveAndJoinHandler() already removed us from the list, and is
-            // now waiting on a join(), so just return. Additionally, release
-            // all the resources held by snapuserd object which are shared
-            // by worker threads. This should be done when the last reference
-            // of "handler" is released; but we will explicitly release here
-            // to make sure snapuserd object is freed as it is the biggest
-            // consumer of memory in the daemon.
-            handler->FreeResources();
-            LOG(INFO) << "Exiting handler thread to allow for join: " << misc_name;
-            return;
-        }
-
-        LOG(INFO) << "Exiting handler thread and freeing resources: " << misc_name;
-
-        if (handler->snapuserd()->IsAttached()) {
-            handler->thread().detach();
-        }
-
-        // Important: free resources within the lock. This ensures that if
-        // WaitForDelete() is called, the handler is either in the list, or
-        // it's not and its resources are guaranteed to be freed.
-        handler->FreeResources();
-    }
-}
-
-bool SnapuserdServer::Start(const std::string& socketname) {
-    bool start_listening = true;
-
-    sockfd_.reset(android_get_control_socket(socketname.c_str()));
-    if (sockfd_ < 0) {
-        sockfd_.reset(socket_local_server(socketname.c_str(), ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                          SOCK_STREAM));
-        if (sockfd_ < 0) {
-            PLOG(ERROR) << "Failed to create server socket " << socketname;
-            return false;
-        }
-        start_listening = false;
-    }
-    return StartWithSocket(start_listening);
-}
-
-bool SnapuserdServer::StartWithSocket(bool start_listening) {
-    if (start_listening && listen(sockfd_.get(), 4) < 0) {
-        PLOG(ERROR) << "listen socket failed";
-        return false;
-    }
-
-    AddWatchedFd(sockfd_, POLLIN);
-    is_socket_present_ = true;
-
-    // If started in first-stage init, the property service won't be online.
-    if (access("/dev/socket/property_service", F_OK) == 0) {
-        if (!android::base::SetProperty("snapuserd.ready", "true")) {
-            LOG(ERROR) << "Failed to set snapuserd.ready property";
-            return false;
-        }
-    }
-
-    LOG(DEBUG) << "Snapuserd server now accepting connections";
-    return true;
-}
-
-bool SnapuserdServer::Run() {
-    LOG(INFO) << "Now listening on snapuserd socket";
-
-    while (!IsTerminating()) {
-        int rv = TEMP_FAILURE_RETRY(poll(watched_fds_.data(), watched_fds_.size(), -1));
-        if (rv < 0) {
-            PLOG(ERROR) << "poll failed";
-            return false;
-        }
-        if (!rv) {
-            continue;
-        }
-
-        if (watched_fds_[0].revents) {
-            AcceptClient();
-        }
-
-        auto iter = watched_fds_.begin() + 1;
-        while (iter != watched_fds_.end()) {
-            if (iter->revents && !HandleClient(iter->fd, iter->revents)) {
-                close(iter->fd);
-                iter = watched_fds_.erase(iter);
-            } else {
-                iter++;
-            }
-        }
-    }
-
-    JoinAllThreads();
-    return true;
-}
-
-void SnapuserdServer::JoinAllThreads() {
-    // Acquire the thread list within the lock.
-    std::vector<std::shared_ptr<DmUserHandler>> dm_users;
-    {
-        std::lock_guard<std::mutex> guard(lock_);
-        dm_users = std::move(dm_users_);
-    }
-
-    for (auto& client : dm_users) {
-        auto& th = client->thread();
-
-        if (th.joinable()) th.join();
-    }
-}
-
-void SnapuserdServer::AddWatchedFd(android::base::borrowed_fd fd, int events) {
-    struct pollfd p = {};
-    p.fd = fd.get();
-    p.events = events;
-    watched_fds_.emplace_back(std::move(p));
-}
-
-void SnapuserdServer::AcceptClient() {
-    int fd = TEMP_FAILURE_RETRY(accept4(sockfd_.get(), nullptr, nullptr, SOCK_CLOEXEC));
-    if (fd < 0) {
-        PLOG(ERROR) << "accept4 failed";
-        return;
-    }
-
-    AddWatchedFd(fd, POLLIN);
-}
-
-bool SnapuserdServer::HandleClient(android::base::borrowed_fd fd, int revents) {
-    if (revents & POLLHUP) {
-        LOG(DEBUG) << "Snapuserd client disconnected";
-        return false;
-    }
-
-    std::string str;
-    if (!Recv(fd, &str)) {
-        return false;
-    }
-    if (!Receivemsg(fd, str)) {
-        LOG(ERROR) << "Encountered error handling client message, revents: " << revents;
-        return false;
-    }
-    return true;
-}
-
-void SnapuserdServer::Interrupt() {
-    // Force close the socket so poll() fails.
-    sockfd_ = {};
-    SetTerminating();
-}
-
-std::shared_ptr<DmUserHandler> SnapuserdServer::AddHandler(const std::string& misc_name,
-                                                           const std::string& cow_device_path,
-                                                           const std::string& backing_device) {
-    auto snapuserd = std::make_shared<Snapuserd>(misc_name, cow_device_path, backing_device);
-    if (!snapuserd->InitCowDevice()) {
-        LOG(ERROR) << "Failed to initialize Snapuserd";
-        return nullptr;
-    }
-
-    if (!snapuserd->InitializeWorkers()) {
-        LOG(ERROR) << "Failed to initialize workers";
-        return nullptr;
-    }
-
-    auto handler = std::make_shared<DmUserHandler>(snapuserd);
-    {
-        std::lock_guard<std::mutex> lock(lock_);
-        if (FindHandler(&lock, misc_name) != dm_users_.end()) {
-            LOG(ERROR) << "Handler already exists: " << misc_name;
-            return nullptr;
-        }
-        dm_users_.push_back(handler);
-    }
-    return handler;
-}
-
-bool SnapuserdServer::StartHandler(const std::shared_ptr<DmUserHandler>& handler) {
-    if (handler->snapuserd()->IsAttached()) {
-        LOG(ERROR) << "Handler already attached";
-        return false;
-    }
-
-    handler->snapuserd()->AttachControlDevice();
-
-    handler->thread() = std::thread(std::bind(&SnapuserdServer::RunThread, this, handler));
-    return true;
-}
-
-auto SnapuserdServer::FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
-                                  const std::string& misc_name) -> HandlerList::iterator {
-    CHECK(proof_of_lock);
-
-    for (auto iter = dm_users_.begin(); iter != dm_users_.end(); iter++) {
-        if ((*iter)->misc_name() == misc_name) {
-            return iter;
-        }
-    }
-    return dm_users_.end();
-}
-
-bool SnapuserdServer::RemoveAndJoinHandler(const std::string& misc_name) {
-    std::shared_ptr<DmUserHandler> handler;
-    {
-        std::lock_guard<std::mutex> lock(lock_);
-
-        auto iter = FindHandler(&lock, misc_name);
-        if (iter == dm_users_.end()) {
-            // Client already deleted.
-            return true;
-        }
-        handler = std::move(*iter);
-        dm_users_.erase(iter);
-    }
-
-    auto& th = handler->thread();
-    if (th.joinable()) {
-        th.join();
-    }
-    return true;
-}
-
-bool SnapuserdServer::WaitForSocket() {
-    auto scope_guard = android::base::make_scope_guard([this]() -> void { JoinAllThreads(); });
-
-    auto socket_path = ANDROID_SOCKET_DIR "/"s + kSnapuserdSocketProxy;
-
-    if (!android::fs_mgr::WaitForFile(socket_path, std::chrono::milliseconds::max())) {
-        LOG(ERROR)
-                << "Failed to wait for proxy socket, second-stage snapuserd will fail to connect";
-        return false;
-    }
-
-    // We must re-initialize property service access, since we launched before
-    // second-stage init.
-    __system_properties_init();
-
-    if (!android::base::WaitForProperty("snapuserd.proxy_ready", "true")) {
-        LOG(ERROR)
-                << "Failed to wait for proxy property, second-stage snapuserd will fail to connect";
-        return false;
-    }
-
-    unique_fd fd(socket_local_client(kSnapuserdSocketProxy, ANDROID_SOCKET_NAMESPACE_RESERVED,
-                                     SOCK_SEQPACKET));
-    if (fd < 0) {
-        PLOG(ERROR) << "Failed to connect to socket proxy";
-        return false;
-    }
-
-    char code[1];
-    std::vector<unique_fd> fds;
-    ssize_t rv = android::base::ReceiveFileDescriptorVector(fd, code, sizeof(code), 1, &fds);
-    if (rv < 0) {
-        PLOG(ERROR) << "Failed to receive server socket over proxy";
-        return false;
-    }
-    if (fds.empty()) {
-        LOG(ERROR) << "Expected at least one file descriptor from proxy";
-        return false;
-    }
-
-    // We don't care if the ACK is received.
-    code[0] = 'a';
-    if (TEMP_FAILURE_RETRY(send(fd, code, sizeof(code), MSG_NOSIGNAL)) < 0) {
-        PLOG(ERROR) << "Failed to send ACK to proxy";
-        return false;
-    }
-
-    sockfd_ = std::move(fds[0]);
-    if (!StartWithSocket(true)) {
-        return false;
-    }
-    return Run();
-}
-
-bool SnapuserdServer::RunForSocketHandoff() {
-    unique_fd proxy_fd(android_get_control_socket(kSnapuserdSocketProxy));
-    if (proxy_fd < 0) {
-        PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocketProxy;
-    }
-    borrowed_fd server_fd(android_get_control_socket(kSnapuserdSocket));
-    if (server_fd < 0) {
-        PLOG(FATAL) << "Proxy could not get android control socket " << kSnapuserdSocket;
-    }
-
-    if (listen(proxy_fd.get(), 4) < 0) {
-        PLOG(FATAL) << "Proxy listen socket failed";
-    }
-
-    if (!android::base::SetProperty("snapuserd.proxy_ready", "true")) {
-        LOG(FATAL) << "Proxy failed to set ready property";
-    }
-
-    unique_fd client_fd(
-            TEMP_FAILURE_RETRY(accept4(proxy_fd.get(), nullptr, nullptr, SOCK_CLOEXEC)));
-    if (client_fd < 0) {
-        PLOG(FATAL) << "Proxy accept failed";
-    }
-
-    char code[1] = {'a'};
-    std::vector<int> fds = {server_fd.get()};
-    ssize_t rv = android::base::SendFileDescriptorVector(client_fd, code, sizeof(code), fds);
-    if (rv < 0) {
-        PLOG(FATAL) << "Proxy could not send file descriptor to snapuserd";
-    }
-    // Wait for an ACK - results don't matter, we just don't want to risk closing
-    // the proxy socket too early.
-    if (recv(client_fd, code, sizeof(code), 0) < 0) {
-        PLOG(FATAL) << "Proxy could not receive terminating code from snapuserd";
-    }
-    return true;
-}
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.h
deleted file mode 100644
index 3b6ff15..0000000
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_server.h
+++ /dev/null
@@ -1,149 +0,0 @@
-// Copyright (C) 2020 The Android Open Source Project
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//      http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#pragma once
-
-#include <poll.h>
-
-#include <cstdio>
-#include <cstring>
-#include <functional>
-#include <future>
-#include <iostream>
-#include <mutex>
-#include <sstream>
-#include <string>
-#include <thread>
-#include <vector>
-
-#include <android-base/unique_fd.h>
-#include "snapuserd.h"
-
-namespace android {
-namespace snapshot {
-
-static constexpr uint32_t MAX_PACKET_SIZE = 512;
-
-enum class DaemonOperations {
-    INIT,
-    START,
-    QUERY,
-    STOP,
-    DELETE,
-    DETACH,
-    SUPPORTS,
-    INVALID,
-};
-
-class DmUserHandler {
-  public:
-    explicit DmUserHandler(std::shared_ptr<Snapuserd> snapuserd);
-
-    void FreeResources() {
-        // Each worker thread holds a reference to snapuserd.
-        // Clear them so that all the resources
-        // held by snapuserd is released
-        if (snapuserd_) {
-            snapuserd_->FreeResources();
-            snapuserd_ = nullptr;
-        }
-    }
-    const std::shared_ptr<Snapuserd>& snapuserd() const { return snapuserd_; }
-    std::thread& thread() { return thread_; }
-
-    const std::string& misc_name() const { return misc_name_; }
-
-  private:
-    std::thread thread_;
-    std::shared_ptr<Snapuserd> snapuserd_;
-    std::string misc_name_;
-};
-
-class Stoppable {
-    std::promise<void> exitSignal_;
-    std::future<void> futureObj_;
-
-  public:
-    Stoppable() : futureObj_(exitSignal_.get_future()) {}
-
-    virtual ~Stoppable() {}
-
-    bool StopRequested() {
-        // checks if value in future object is available
-        if (futureObj_.wait_for(std::chrono::milliseconds(0)) == std::future_status::timeout) {
-            return false;
-        }
-        return true;
-    }
-    // Request the thread to stop by setting value in promise object
-    void StopThreads() { exitSignal_.set_value(); }
-};
-
-class SnapuserdServer : public Stoppable {
-  private:
-    android::base::unique_fd sockfd_;
-    bool terminating_;
-    volatile bool received_socket_signal_ = false;
-    std::vector<struct pollfd> watched_fds_;
-    bool is_socket_present_ = false;
-
-    std::mutex lock_;
-
-    using HandlerList = std::vector<std::shared_ptr<DmUserHandler>>;
-    HandlerList dm_users_;
-
-    void AddWatchedFd(android::base::borrowed_fd fd, int events);
-    void AcceptClient();
-    bool HandleClient(android::base::borrowed_fd fd, int revents);
-    bool Recv(android::base::borrowed_fd fd, std::string* data);
-    bool Sendmsg(android::base::borrowed_fd fd, const std::string& msg);
-    bool Receivemsg(android::base::borrowed_fd fd, const std::string& str);
-
-    void ShutdownThreads();
-    bool RemoveAndJoinHandler(const std::string& control_device);
-    DaemonOperations Resolveop(std::string& input);
-    std::string GetDaemonStatus();
-    void Parsemsg(std::string const& msg, const char delim, std::vector<std::string>& out);
-
-    bool IsTerminating() { return terminating_; }
-
-    void RunThread(std::shared_ptr<DmUserHandler> handler);
-    void JoinAllThreads();
-    bool StartWithSocket(bool start_listening);
-
-    // Find a DmUserHandler within a lock.
-    HandlerList::iterator FindHandler(std::lock_guard<std::mutex>* proof_of_lock,
-                                      const std::string& misc_name);
-
-  public:
-    SnapuserdServer() { terminating_ = false; }
-    ~SnapuserdServer();
-
-    bool Start(const std::string& socketname);
-    bool Run();
-    void Interrupt();
-    bool RunForSocketHandoff();
-    bool WaitForSocket();
-
-    std::shared_ptr<DmUserHandler> AddHandler(const std::string& misc_name,
-                                              const std::string& cow_device_path,
-                                              const std::string& backing_device);
-    bool StartHandler(const std::shared_ptr<DmUserHandler>& handler);
-
-    void SetTerminating() { terminating_ = true; }
-    void ReceivedSocketSignal() { received_socket_signal_ = true; }
-};
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp b/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
deleted file mode 100644
index 1f5d568..0000000
--- a/fs_mgr/libsnapshot/snapuserd/dm-snapshot-merge/snapuserd_worker.cpp
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "snapuserd.h"
-
-#include <csignal>
-#include <optional>
-#include <set>
-
-#include <snapuserd/snapuserd_client.h>
-
-namespace android {
-namespace snapshot {
-
-using namespace android;
-using namespace android::dm;
-using android::base::unique_fd;
-
-#define SNAP_LOG(level) LOG(level) << misc_name_ << ": "
-#define SNAP_PLOG(level) PLOG(level) << misc_name_ << ": "
-
-WorkerThread::WorkerThread(const std::string& cow_device, const std::string& backing_device,
-                           const std::string& control_device, const std::string& misc_name,
-                           std::shared_ptr<Snapuserd> snapuserd) {
-    cow_device_ = cow_device;
-    backing_store_device_ = backing_device;
-    control_device_ = control_device;
-    misc_name_ = misc_name;
-    snapuserd_ = snapuserd;
-    exceptions_per_area_ = (CHUNK_SIZE << SECTOR_SHIFT) / sizeof(struct disk_exception);
-}
-
-bool WorkerThread::InitializeFds() {
-    backing_store_fd_.reset(open(backing_store_device_.c_str(), O_RDONLY));
-    if (backing_store_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << backing_store_device_;
-        return false;
-    }
-
-    cow_fd_.reset(open(cow_device_.c_str(), O_RDWR));
-    if (cow_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Open Failed: " << cow_device_;
-        return false;
-    }
-
-    ctrl_fd_.reset(open(control_device_.c_str(), O_RDWR));
-    if (ctrl_fd_ < 0) {
-        SNAP_PLOG(ERROR) << "Unable to open " << control_device_;
-        return false;
-    }
-
-    return true;
-}
-
-bool WorkerThread::InitReader() {
-    reader_ = snapuserd_->CloneReaderForWorker();
-
-    if (!reader_->InitForMerge(std::move(cow_fd_))) {
-        return false;
-    }
-    return true;
-}
-
-// Construct kernel COW header in memory
-// This header will be in sector 0. The IO
-// request will always be 4k. After constructing
-// the header, zero out the remaining block.
-void WorkerThread::ConstructKernelCowHeader() {
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-
-    memset(buffer, 0, BLOCK_SZ);
-
-    struct disk_header* dh = reinterpret_cast<struct disk_header*>(buffer);
-
-    dh->magic = SNAP_MAGIC;
-    dh->valid = SNAPSHOT_VALID;
-    dh->version = SNAPSHOT_DISK_VERSION;
-    dh->chunk_size = CHUNK_SIZE;
-}
-
-// Start the replace operation. This will read the
-// internal COW format and if the block is compressed,
-// it will be de-compressed.
-bool WorkerThread::ProcessReplaceOp(const CowOperation* cow_op) {
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (!buffer) {
-        SNAP_LOG(ERROR) << "No space in buffer sink";
-        return false;
-    }
-    ssize_t rv = reader_->ReadData(cow_op, buffer, BLOCK_SZ);
-    if (rv != BLOCK_SZ) {
-        SNAP_LOG(ERROR) << "ProcessReplaceOp failed for block " << cow_op->new_block
-                        << ", return = " << rv << ", COW operation = " << *cow_op;
-        return false;
-    }
-    return true;
-}
-
-bool WorkerThread::ReadFromBaseDevice(const CowOperation* cow_op) {
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get payload buffer";
-        return false;
-    }
-    uint64_t offset;
-    if (!reader_->GetSourceOffset(cow_op, &offset)) {
-        SNAP_LOG(ERROR) << "ReadFromBaseDevice: Failed to get source offset";
-        return false;
-    }
-    SNAP_LOG(DEBUG) << " ReadFromBaseDevice...: new-block: " << cow_op->new_block
-                    << " Source: " << offset;
-    if (!android::base::ReadFullyAtOffset(backing_store_fd_, buffer, BLOCK_SZ, offset)) {
-        SNAP_PLOG(ERROR) << "Copy op failed. Read from backing store: " << backing_store_device_
-                         << "at block :" << offset / BLOCK_SZ << " offset:" << offset % BLOCK_SZ;
-        return false;
-    }
-
-    return true;
-}
-
-bool WorkerThread::GetReadAheadPopulatedBuffer(const CowOperation* cow_op) {
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "GetReadAheadPopulatedBuffer: Failed to get payload buffer";
-        return false;
-    }
-
-    if (!snapuserd_->GetReadAheadPopulatedBuffer(cow_op->new_block, buffer)) {
-        return false;
-    }
-
-    return true;
-}
-
-// Start the copy operation. This will read the backing
-// block device which is represented by cow_op->source.
-bool WorkerThread::ProcessCopyOp(const CowOperation* cow_op) {
-    if (!GetReadAheadPopulatedBuffer(cow_op)) {
-        SNAP_LOG(DEBUG) << " GetReadAheadPopulatedBuffer failed..."
-                        << " new_block: " << cow_op->new_block;
-        if (!ReadFromBaseDevice(cow_op)) {
-            return false;
-        }
-    }
-
-    return true;
-}
-
-bool WorkerThread::ProcessZeroOp() {
-    // Zero out the entire block
-    void* buffer = bufsink_.GetPayloadBuffer(BLOCK_SZ);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "ProcessZeroOp: Failed to get payload buffer";
-        return false;
-    }
-
-    memset(buffer, 0, BLOCK_SZ);
-    return true;
-}
-
-bool WorkerThread::ProcessCowOp(const CowOperation* cow_op) {
-    if (cow_op == nullptr) {
-        SNAP_LOG(ERROR) << "ProcessCowOp: Invalid cow_op";
-        return false;
-    }
-
-    switch (cow_op->type()) {
-        case kCowReplaceOp: {
-            return ProcessReplaceOp(cow_op);
-        }
-
-        case kCowZeroOp: {
-            return ProcessZeroOp();
-        }
-
-        case kCowCopyOp: {
-            return ProcessCopyOp(cow_op);
-        }
-
-        default: {
-            SNAP_LOG(ERROR) << "Unsupported operation-type found: "
-                            << static_cast<uint8_t>(cow_op->type());
-        }
-    }
-    return false;
-}
-
-int WorkerThread::ReadUnalignedSector(
-        sector_t sector, size_t size,
-        std::vector<std::pair<sector_t, const CowOperation*>>::iterator& it) {
-    size_t skip_sector_size = 0;
-
-    SNAP_LOG(DEBUG) << "ReadUnalignedSector: sector " << sector << " size: " << size
-                    << " Aligned sector: " << it->first;
-
-    if (!ProcessCowOp(it->second)) {
-        SNAP_LOG(ERROR) << "ReadUnalignedSector: " << sector << " failed of size: " << size
-                        << " Aligned sector: " << it->first;
-        return -1;
-    }
-
-    int num_sectors_skip = sector - it->first;
-
-    if (num_sectors_skip > 0) {
-        skip_sector_size = num_sectors_skip << SECTOR_SHIFT;
-        char* buffer = reinterpret_cast<char*>(bufsink_.GetBufPtr());
-        struct dm_user_message* msg = (struct dm_user_message*)(&(buffer[0]));
-
-        if (skip_sector_size == BLOCK_SZ) {
-            SNAP_LOG(ERROR) << "Invalid un-aligned IO request at sector: " << sector
-                            << " Base-sector: " << it->first;
-            return -1;
-        }
-
-        memmove(msg->payload.buf, (char*)msg->payload.buf + skip_sector_size,
-                (BLOCK_SZ - skip_sector_size));
-    }
-
-    bufsink_.ResetBufferOffset();
-    return std::min(size, (BLOCK_SZ - skip_sector_size));
-}
-
-/*
- * Read the data for a given COW Operation.
- *
- * Kernel can issue IO at a sector granularity.
- * Hence, an IO may end up with reading partial
- * data from a COW operation or we may also
- * end up with interspersed request between
- * two COW operations.
- *
- */
-int WorkerThread::ReadData(sector_t sector, size_t size) {
-    std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
-    std::vector<std::pair<sector_t, const CowOperation*>>::iterator it;
-    /*
-     * chunk_map stores COW operation at 4k granularity.
-     * If the requested IO with the sector falls on the 4k
-     * boundary, then we can read the COW op directly without
-     * any issue.
-     *
-     * However, if the requested sector is not 4K aligned,
-     * then we will have the find the nearest COW operation
-     * and chop the 4K block to fetch the requested sector.
-     */
-    it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(), std::make_pair(sector, nullptr),
-                          Snapuserd::compare);
-
-    bool read_end_of_device = false;
-    if (it == chunk_vec.end()) {
-        // |-------|-------|-------|
-        // 0       1       2       3
-        //
-        // Block 0 - op 1
-        // Block 1 - op 2
-        // Block 2 - op 3
-        //
-        // chunk_vec will have block 0, 1, 2 which maps to relavant COW ops.
-        //
-        // Each block is 4k bytes. Thus, the last block will span 8 sectors
-        // ranging till block 3 (However, block 3 won't be in chunk_vec as
-        // it doesn't have any mapping to COW ops. Now, if we get an I/O request for a sector
-        // spanning between block 2 and block 3, we need to step back
-        // and get hold of the last element.
-        //
-        // Additionally, dm-snapshot makes sure that I/O request beyond block 3
-        // will not be routed to the daemon. Hence, it is safe to assume that
-        // if a sector is not available in the chunk_vec, the I/O falls in the
-        // end of region.
-        it = std::prev(chunk_vec.end());
-        read_end_of_device = true;
-    }
-
-    // We didn't find the required sector; hence find the previous sector
-    // as lower_bound will gives us the value greater than
-    // the requested sector
-    if (it->first != sector) {
-        if (it != chunk_vec.begin() && !read_end_of_device) {
-            --it;
-        }
-
-        /*
-         * If the IO is spanned between two COW operations,
-         * split the IO into two parts:
-         *
-         * 1: Read the first part from the single COW op
-         * 2: Read the second part from the next COW op.
-         *
-         * Ex: Let's say we have a 1024 Bytes IO request.
-         *
-         * 0       COW OP-1  4096     COW OP-2  8192
-         * |******************|*******************|
-         *              |*****|*****|
-         *           3584           4608
-         *              <- 1024B - >
-         *
-         * We have two COW operations which are 4k blocks.
-         * The IO is requested for 1024 Bytes which are spanned
-         * between two COW operations. We will split this IO
-         * into two parts:
-         *
-         * 1: IO of size 512B from offset 3584 bytes (COW OP-1)
-         * 2: IO of size 512B from offset 4096 bytes (COW OP-2)
-         */
-        return ReadUnalignedSector(sector, size, it);
-    }
-
-    int num_ops = DIV_ROUND_UP(size, BLOCK_SZ);
-    sector_t read_sector = sector;
-    while (num_ops) {
-        // We have to make sure that the reads are
-        // sequential; there shouldn't be a data
-        // request merged with a metadata IO.
-        if (it->first != read_sector) {
-            SNAP_LOG(ERROR) << "Invalid IO request: read_sector: " << read_sector
-                            << " cow-op sector: " << it->first;
-            return -1;
-        } else if (!ProcessCowOp(it->second)) {
-            return -1;
-        }
-        num_ops -= 1;
-        read_sector += (BLOCK_SZ >> SECTOR_SHIFT);
-
-        it++;
-
-        if (it == chunk_vec.end() && num_ops) {
-            SNAP_LOG(ERROR) << "Invalid IO request at sector " << sector
-                            << " COW ops completed; pending read-request: " << num_ops;
-            return -1;
-        }
-        // Update the buffer offset
-        bufsink_.UpdateBufferOffset(BLOCK_SZ);
-    }
-
-    // Reset the buffer offset
-    bufsink_.ResetBufferOffset();
-    return size;
-}
-
-/*
- * dm-snap does prefetch reads while reading disk-exceptions.
- * By default, prefetch value is set to 12; this means that
- * dm-snap will issue 12 areas wherein each area is a 4k page
- * of disk-exceptions.
- *
- * If during prefetch, if the chunk-id seen is beyond the
- * actual number of metadata page, fill the buffer with zero.
- * When dm-snap starts parsing the buffer, it will stop
- * reading metadata page once the buffer content is zero.
- */
-bool WorkerThread::ZerofillDiskExceptions(size_t read_size) {
-    size_t size = exceptions_per_area_ * sizeof(struct disk_exception);
-
-    if (read_size > size) {
-        return false;
-    }
-
-    void* buffer = bufsink_.GetPayloadBuffer(size);
-    if (buffer == nullptr) {
-        SNAP_LOG(ERROR) << "ZerofillDiskExceptions: Failed to get payload buffer";
-        return false;
-    }
-
-    memset(buffer, 0, size);
-    return true;
-}
-
-/*
- * A disk exception is a simple mapping of old_chunk to new_chunk.
- * When dm-snapshot device is created, kernel requests these mapping.
- *
- * Each disk exception is of size 16 bytes. Thus a single 4k page can
- * have:
- *
- * exceptions_per_area_ = 4096/16 = 256. This entire 4k page
- * is considered a metadata page and it is represented by chunk ID.
- *
- * Convert the chunk ID to index into the vector which gives us
- * the metadata page.
- */
-bool WorkerThread::ReadDiskExceptions(chunk_t chunk, size_t read_size) {
-    uint32_t stride = exceptions_per_area_ + 1;
-    size_t size;
-    const std::vector<std::unique_ptr<uint8_t[]>>& vec = snapuserd_->GetMetadataVec();
-
-    // ChunkID to vector index
-    lldiv_t divresult = lldiv(chunk, stride);
-
-    if (divresult.quot < vec.size()) {
-        size = exceptions_per_area_ * sizeof(struct disk_exception);
-
-        if (read_size != size) {
-            SNAP_LOG(ERROR) << "ReadDiskExceptions: read_size: " << read_size
-                            << " does not match with size: " << size;
-            return false;
-        }
-
-        void* buffer = bufsink_.GetPayloadBuffer(size);
-        if (buffer == nullptr) {
-            SNAP_LOG(ERROR) << "ReadDiskExceptions: Failed to get payload buffer of size: " << size;
-            return false;
-        }
-
-        memcpy(buffer, vec[divresult.quot].get(), size);
-    } else {
-        return ZerofillDiskExceptions(read_size);
-    }
-
-    return true;
-}
-
-loff_t WorkerThread::GetMergeStartOffset(void* merged_buffer, void* unmerged_buffer,
-                                         int* unmerged_exceptions) {
-    loff_t offset = 0;
-    *unmerged_exceptions = 0;
-
-    while (*unmerged_exceptions <= exceptions_per_area_) {
-        struct disk_exception* merged_de =
-                reinterpret_cast<struct disk_exception*>((char*)merged_buffer + offset);
-        struct disk_exception* cow_de =
-                reinterpret_cast<struct disk_exception*>((char*)unmerged_buffer + offset);
-
-        // Unmerged op by the kernel
-        if (merged_de->old_chunk != 0 || merged_de->new_chunk != 0) {
-            if (!(merged_de->old_chunk == cow_de->old_chunk)) {
-                SNAP_LOG(ERROR) << "GetMergeStartOffset: merged_de->old_chunk: "
-                                << merged_de->old_chunk
-                                << "cow_de->old_chunk: " << cow_de->old_chunk;
-                return -1;
-            }
-
-            if (!(merged_de->new_chunk == cow_de->new_chunk)) {
-                SNAP_LOG(ERROR) << "GetMergeStartOffset: merged_de->new_chunk: "
-                                << merged_de->new_chunk
-                                << "cow_de->new_chunk: " << cow_de->new_chunk;
-                return -1;
-            }
-
-            offset += sizeof(struct disk_exception);
-            *unmerged_exceptions += 1;
-            continue;
-        }
-
-        break;
-    }
-
-    SNAP_LOG(DEBUG) << "Unmerged_Exceptions: " << *unmerged_exceptions << " Offset: " << offset;
-    return offset;
-}
-
-int WorkerThread::GetNumberOfMergedOps(void* merged_buffer, void* unmerged_buffer, loff_t offset,
-                                       int unmerged_exceptions, bool* ordered_op, bool* commit) {
-    int merged_ops_cur_iter = 0;
-    std::unordered_map<uint64_t, void*>& read_ahead_buffer_map = snapuserd_->GetReadAheadMap();
-    *ordered_op = false;
-    std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
-
-    // Find the operations which are merged in this cycle.
-    while ((unmerged_exceptions + merged_ops_cur_iter) < exceptions_per_area_) {
-        struct disk_exception* merged_de =
-                reinterpret_cast<struct disk_exception*>((char*)merged_buffer + offset);
-        struct disk_exception* cow_de =
-                reinterpret_cast<struct disk_exception*>((char*)unmerged_buffer + offset);
-
-        if (!(merged_de->new_chunk == 0)) {
-            SNAP_LOG(ERROR) << "GetNumberOfMergedOps: Invalid new-chunk: " << merged_de->new_chunk;
-            return -1;
-        }
-
-        if (!(merged_de->old_chunk == 0)) {
-            SNAP_LOG(ERROR) << "GetNumberOfMergedOps: Invalid old-chunk: " << merged_de->old_chunk;
-            return -1;
-        }
-
-        if (cow_de->new_chunk != 0) {
-            merged_ops_cur_iter += 1;
-            offset += sizeof(struct disk_exception);
-            auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
-                                       std::make_pair(ChunkToSector(cow_de->new_chunk), nullptr),
-                                       Snapuserd::compare);
-
-            if (!(it != chunk_vec.end())) {
-                SNAP_LOG(ERROR) << "Sector not found: " << ChunkToSector(cow_de->new_chunk);
-                return -1;
-            }
-
-            if (!(it->first == ChunkToSector(cow_de->new_chunk))) {
-                SNAP_LOG(ERROR) << "Invalid sector: " << ChunkToSector(cow_de->new_chunk);
-                return -1;
-            }
-            const CowOperation* cow_op = it->second;
-
-            if (snapuserd_->IsReadAheadFeaturePresent() && IsOrderedOp(*cow_op)) {
-                *ordered_op = true;
-                // Every single ordered operation has to come from read-ahead
-                // cache.
-                if (read_ahead_buffer_map.find(cow_op->new_block) == read_ahead_buffer_map.end()) {
-                    SNAP_LOG(ERROR)
-                            << " Block: " << cow_op->new_block << " not found in read-ahead cache"
-                            << " Op: " << *cow_op;
-                    return -1;
-                }
-                // If this is a final block merged in the read-ahead buffer
-                // region, notify the read-ahead thread to make forward
-                // progress
-                if (cow_op->new_block == snapuserd_->GetFinalBlockMerged()) {
-                    *commit = true;
-                }
-            }
-
-            // zero out to indicate that operation is merged.
-            cow_de->old_chunk = 0;
-            cow_de->new_chunk = 0;
-        } else if (cow_de->old_chunk == 0) {
-            // Already merged op in previous iteration or
-            // This could also represent a partially filled area.
-            //
-            // If the op was merged in previous cycle, we don't have
-            // to count them.
-            break;
-        } else {
-            SNAP_LOG(ERROR) << "Error in merge operation. Found invalid metadata: "
-                            << " merged_de-old-chunk: " << merged_de->old_chunk
-                            << " merged_de-new-chunk: " << merged_de->new_chunk
-                            << " cow_de-old-chunk: " << cow_de->old_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 merged_ops_cur_iter;
-}
-
-bool WorkerThread::ProcessMergeComplete(chunk_t chunk, void* buffer) {
-    uint32_t stride = exceptions_per_area_ + 1;
-    const std::vector<std::unique_ptr<uint8_t[]>>& vec = snapuserd_->GetMetadataVec();
-    bool ordered_op = false;
-    bool commit = false;
-
-    // ChunkID to vector index
-    lldiv_t divresult = lldiv(chunk, stride);
-
-    if (!(divresult.quot < vec.size())) {
-        SNAP_LOG(ERROR) << "ProcessMergeComplete: Invalid chunk: " << chunk
-                        << " Metadata-Index: " << divresult.quot << " Area-size: " << vec.size();
-        return false;
-    }
-
-    SNAP_LOG(DEBUG) << "ProcessMergeComplete: chunk: " << chunk
-                    << " Metadata-Index: " << divresult.quot;
-
-    int unmerged_exceptions = 0;
-    loff_t offset = GetMergeStartOffset(buffer, vec[divresult.quot].get(), &unmerged_exceptions);
-
-    if (offset < 0) {
-        SNAP_LOG(ERROR) << "GetMergeStartOffset failed: unmerged_exceptions: "
-                        << unmerged_exceptions;
-        return false;
-    }
-
-    int merged_ops_cur_iter = GetNumberOfMergedOps(buffer, vec[divresult.quot].get(), offset,
-                                                   unmerged_exceptions, &ordered_op, &commit);
-
-    // There should be at least one operation merged in this cycle
-    if (!(merged_ops_cur_iter > 0)) {
-        SNAP_LOG(ERROR) << "Merge operation failed: " << merged_ops_cur_iter;
-        return false;
-    }
-
-    if (ordered_op) {
-        if (commit) {
-            // Push the flushing logic to read-ahead thread so that merge thread
-            // can make forward progress. Sync will happen in the background
-            snapuserd_->StartReadAhead();
-        }
-    } else {
-        // Non-copy ops and all ops in older COW format
-        if (!snapuserd_->CommitMerge(merged_ops_cur_iter)) {
-            SNAP_LOG(ERROR) << "CommitMerge failed...";
-            return false;
-        }
-    }
-
-    SNAP_LOG(DEBUG) << "Merge success: " << merged_ops_cur_iter << "chunk: " << chunk;
-    return true;
-}
-
-// Read Header from dm-user misc device. This gives
-// us the sector number for which IO is issued by dm-snapshot device
-bool WorkerThread::ReadDmUserHeader() {
-    if (!android::base::ReadFully(ctrl_fd_, bufsink_.GetBufPtr(), sizeof(struct dm_user_header))) {
-        if (errno != ENOTBLK) {
-            SNAP_PLOG(ERROR) << "Control-read failed";
-        }
-
-        return false;
-    }
-
-    return true;
-}
-
-// Send the payload/data back to dm-user misc device.
-bool WorkerThread::WriteDmUserPayload(size_t size, bool header_response) {
-    size_t payload_size = size;
-    void* buf = bufsink_.GetPayloadBufPtr();
-    if (header_response) {
-        payload_size += sizeof(struct dm_user_header);
-        buf = bufsink_.GetBufPtr();
-    }
-
-    if (!android::base::WriteFully(ctrl_fd_, buf, payload_size)) {
-        SNAP_PLOG(ERROR) << "Write to dm-user failed size: " << payload_size;
-        return false;
-    }
-
-    return true;
-}
-
-bool WorkerThread::ReadDmUserPayload(void* buffer, size_t size) {
-    if (!android::base::ReadFully(ctrl_fd_, buffer, size)) {
-        SNAP_PLOG(ERROR) << "ReadDmUserPayload failed size: " << size;
-        return false;
-    }
-
-    return true;
-}
-
-bool WorkerThread::DmuserWriteRequest() {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
-
-    // device mapper has the capability to allow
-    // targets to flush the cache when writes are completed. This
-    // is controlled by each target by a flag "flush_supported".
-    // This flag is set by dm-user. When flush is supported,
-    // a number of zero-length bio's will be submitted to
-    // the target for the purpose of flushing cache. It is the
-    // responsibility of the target driver - which is dm-user in this
-    // case, to remap these bio's to the underlying device. Since,
-    // there is no underlying device for dm-user, this zero length
-    // bio's gets routed to daemon.
-    //
-    // Flush operations are generated post merge by dm-snap by having
-    // REQ_PREFLUSH flag set. Snapuser daemon doesn't have anything
-    // to flush per se; hence, just respond back with a success message.
-    if (header->sector == 0) {
-        if (!(header->len == 0)) {
-            SNAP_LOG(ERROR) << "Invalid header length received from sector 0: " << header->len;
-            header->type = DM_USER_RESP_ERROR;
-        } else {
-            header->type = DM_USER_RESP_SUCCESS;
-        }
-
-        if (!WriteDmUserPayload(0, true)) {
-            return false;
-        }
-        return true;
-    }
-
-    std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
-    size_t remaining_size = header->len;
-    size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
-
-    chunk_t chunk = SectorToChunk(header->sector);
-    auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
-                               std::make_pair(header->sector, nullptr), Snapuserd::compare);
-
-    bool not_found = (it == chunk_vec.end() || it->first != header->sector);
-
-    if (not_found) {
-        void* buffer = bufsink_.GetPayloadBuffer(read_size);
-        if (buffer == nullptr) {
-            SNAP_LOG(ERROR) << "DmuserWriteRequest: Failed to get payload buffer of size: "
-                            << read_size;
-            header->type = DM_USER_RESP_ERROR;
-        } else {
-            header->type = DM_USER_RESP_SUCCESS;
-
-            if (!ReadDmUserPayload(buffer, read_size)) {
-                SNAP_LOG(ERROR) << "ReadDmUserPayload failed for chunk id: " << chunk
-                                << "Sector: " << header->sector;
-                header->type = DM_USER_RESP_ERROR;
-            }
-
-            if (header->type == DM_USER_RESP_SUCCESS && !ProcessMergeComplete(chunk, buffer)) {
-                SNAP_LOG(ERROR) << "ProcessMergeComplete failed for chunk id: " << chunk
-                                << "Sector: " << header->sector;
-                header->type = DM_USER_RESP_ERROR;
-            }
-        }
-    } else {
-        SNAP_LOG(ERROR) << "DmuserWriteRequest: Invalid sector received: header->sector";
-        header->type = DM_USER_RESP_ERROR;
-    }
-
-    if (!WriteDmUserPayload(0, true)) {
-        return false;
-    }
-
-    return true;
-}
-
-bool WorkerThread::DmuserReadRequest() {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
-    size_t remaining_size = header->len;
-    loff_t offset = 0;
-    sector_t sector = header->sector;
-    std::vector<std::pair<sector_t, const CowOperation*>>& chunk_vec = snapuserd_->GetChunkVec();
-    bool header_response = true;
-    do {
-        size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
-
-        int ret = read_size;
-        header->type = DM_USER_RESP_SUCCESS;
-        chunk_t chunk = SectorToChunk(header->sector);
-
-        // Request to sector 0 is always for kernel
-        // representation of COW header. This IO should be only
-        // once during dm-snapshot device creation. We should
-        // never see multiple IO requests. Additionally this IO
-        // will always be a single 4k.
-        if (header->sector == 0) {
-            if (read_size == BLOCK_SZ) {
-                ConstructKernelCowHeader();
-                SNAP_LOG(DEBUG) << "Kernel header constructed";
-            } else {
-                SNAP_LOG(ERROR) << "Invalid read_size: " << read_size << " for sector 0";
-                header->type = DM_USER_RESP_ERROR;
-            }
-        } else {
-            auto it = std::lower_bound(chunk_vec.begin(), chunk_vec.end(),
-                                       std::make_pair(header->sector, nullptr), Snapuserd::compare);
-            bool not_found = (it == chunk_vec.end() || it->first != header->sector);
-            if (!offset && (read_size == BLOCK_SZ) && not_found) {
-                if (!ReadDiskExceptions(chunk, read_size)) {
-                    SNAP_LOG(ERROR) << "ReadDiskExceptions failed for chunk id: " << chunk
-                                    << "Sector: " << header->sector;
-                    header->type = DM_USER_RESP_ERROR;
-                } else {
-                    SNAP_LOG(DEBUG) << "ReadDiskExceptions success for chunk id: " << chunk
-                                    << "Sector: " << header->sector;
-                }
-            } else {
-                chunk_t num_sectors_read = (offset >> SECTOR_SHIFT);
-
-                ret = ReadData(sector + num_sectors_read, read_size);
-                if (ret < 0) {
-                    SNAP_LOG(ERROR) << "ReadData failed for chunk id: " << chunk
-                                    << " Sector: " << (sector + num_sectors_read)
-                                    << " size: " << read_size << " header-len: " << header->len;
-                    header->type = DM_USER_RESP_ERROR;
-                } else {
-                    SNAP_LOG(DEBUG) << "ReadData success for chunk id: " << chunk
-                                    << "Sector: " << header->sector;
-                }
-            }
-        }
-
-        // Just return the header if it is an error
-        if (header->type == DM_USER_RESP_ERROR) {
-            SNAP_LOG(ERROR) << "IO read request failed...";
-            ret = 0;
-        }
-
-        if (!header_response) {
-            CHECK(header->type == DM_USER_RESP_SUCCESS)
-                    << " failed for sector: " << sector << " header->len: " << header->len
-                    << " remaining_size: " << remaining_size;
-        }
-
-        // Daemon will not be terminated if there is any error. We will
-        // just send the error back to dm-user.
-        if (!WriteDmUserPayload(ret, header_response)) {
-            return false;
-        }
-
-        if (header->type == DM_USER_RESP_ERROR) {
-            break;
-        }
-
-        remaining_size -= ret;
-        offset += ret;
-        header_response = false;
-    } while (remaining_size > 0);
-
-    return true;
-}
-
-void WorkerThread::InitializeBufsink() {
-    // Allocate the buffer which is used to communicate between
-    // daemon and dm-user. The buffer comprises of header and a fixed payload.
-    // If the dm-user requests a big IO, the IO will be broken into chunks
-    // of PAYLOAD_SIZE.
-    size_t buf_size = sizeof(struct dm_user_header) + PAYLOAD_SIZE;
-    bufsink_.Initialize(buf_size);
-}
-
-bool WorkerThread::RunThread() {
-    InitializeBufsink();
-
-    if (!InitializeFds()) {
-        return false;
-    }
-
-    if (!InitReader()) {
-        return false;
-    }
-
-    // Start serving IO
-    while (true) {
-        if (!ProcessIORequest()) {
-            break;
-        }
-    }
-
-    CloseFds();
-    reader_->CloseCowFd();
-
-    return true;
-}
-
-bool WorkerThread::ProcessIORequest() {
-    struct dm_user_header* header = bufsink_.GetHeaderPtr();
-
-    if (!ReadDmUserHeader()) {
-        return false;
-    }
-
-    SNAP_LOG(DEBUG) << "Daemon: msg->seq: " << std::dec << header->seq;
-    SNAP_LOG(DEBUG) << "Daemon: msg->len: " << std::dec << header->len;
-    SNAP_LOG(DEBUG) << "Daemon: msg->sector: " << std::dec << header->sector;
-    SNAP_LOG(DEBUG) << "Daemon: msg->type: " << std::dec << header->type;
-    SNAP_LOG(DEBUG) << "Daemon: msg->flags: " << std::dec << header->flags;
-
-    switch (header->type) {
-        case DM_USER_REQ_MAP_READ: {
-            if (!DmuserReadRequest()) {
-                return false;
-            }
-            break;
-        }
-
-        case DM_USER_REQ_MAP_WRITE: {
-            if (!DmuserWriteRequest()) {
-                return false;
-            }
-            break;
-        }
-    }
-
-    return true;
-}
-
-}  // namespace snapshot
-}  // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
index 36dad33..e28dd47 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp
@@ -34,24 +34,9 @@
 namespace snapshot {
 
 bool Daemon::IsUserspaceSnapshotsEnabled() {
-    const std::string UNKNOWN = "unknown";
-    const std::string vendor_release =
-            android::base::GetProperty("ro.vendor.build.version.release_or_codename", UNKNOWN);
-
-    // No user-space snapshots if vendor partition is on Android 12
-    if (vendor_release.find("12") != std::string::npos) {
-        LOG(INFO) << "Userspace snapshots disabled as vendor partition is on Android: "
-                  << vendor_release;
-        return false;
-    }
-
     return android::base::GetBoolProperty("ro.virtual_ab.userspace.snapshots.enabled", false);
 }
 
-bool Daemon::IsDmSnapshotTestingEnabled() {
-    return android::base::GetBoolProperty("snapuserd.test.dm.snapshots", false);
-}
-
 bool Daemon::StartDaemon(int argc, char** argv) {
     int arg_start = gflags::ParseCommandLineFlags(&argc, &argv, true);
 
@@ -65,16 +50,16 @@
     // stage init and hence use the command line flags to get the information.
     bool user_snapshots = FLAGS_user_snapshot;
     if (!user_snapshots) {
-        user_snapshots = (!IsDmSnapshotTestingEnabled() && IsUserspaceSnapshotsEnabled());
+        user_snapshots = IsUserspaceSnapshotsEnabled();
     }
 
     if (user_snapshots) {
         LOG(INFO) << "Starting daemon for user-space snapshots.....";
         return StartServerForUserspaceSnapshots(arg_start, argc, argv);
     } else {
-        LOG(INFO) << "Starting daemon for dm-snapshots.....";
-        return StartServerForDmSnapshot(arg_start, argc, argv);
+        LOG(ERROR) << "Userspace snapshots not enabled. No support for legacy snapshots";
     }
+    return false;
 }
 
 bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** argv) {
@@ -130,48 +115,6 @@
     return user_server_.WaitForSocket();
 }
 
-bool Daemon::StartServerForDmSnapshot(int arg_start, int argc, char** argv) {
-    sigfillset(&signal_mask_);
-    sigdelset(&signal_mask_, SIGINT);
-    sigdelset(&signal_mask_, SIGTERM);
-    sigdelset(&signal_mask_, SIGUSR1);
-
-    // Masking signals here ensure that after this point, we won't handle INT/TERM
-    // until after we call into ppoll()
-    signal(SIGINT, Daemon::SignalHandler);
-    signal(SIGTERM, Daemon::SignalHandler);
-    signal(SIGPIPE, Daemon::SignalHandler);
-    signal(SIGUSR1, Daemon::SignalHandler);
-
-    MaskAllSignalsExceptIntAndTerm();
-
-    if (FLAGS_socket_handoff) {
-        return server_.RunForSocketHandoff();
-    }
-    if (!FLAGS_no_socket) {
-        if (!server_.Start(FLAGS_socket)) {
-            return false;
-        }
-        return server_.Run();
-    }
-
-    for (int i = arg_start; i < argc; i++) {
-        auto parts = android::base::Split(argv[i], ",");
-        if (parts.size() != 3) {
-            LOG(ERROR) << "Malformed message, expected three sub-arguments.";
-            return false;
-        }
-        auto handler = server_.AddHandler(parts[0], parts[1], parts[2]);
-        if (!handler || !server_.StartHandler(handler)) {
-            return false;
-        }
-    }
-
-    // Skip the accept() call to avoid spurious log spam. The server will still
-    // run until all handlers have completed.
-    return server_.WaitForSocket();
-}
-
 void Daemon::MaskAllSignalsExceptIntAndTerm() {
     sigset_t signal_mask;
     sigfillset(&signal_mask);
@@ -198,16 +141,12 @@
     // and verify it through a temp variable.
     if (user_server_.IsServerRunning()) {
         user_server_.Interrupt();
-    } else {
-        server_.Interrupt();
     }
 }
 
 void Daemon::ReceivedSocketSignal() {
     if (user_server_.IsServerRunning()) {
         user_server_.ReceivedSocketSignal();
-    } else {
-        server_.ReceivedSocketSignal();
     }
 }
 
diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.h b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.h
index cf3b917..303e394 100644
--- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.h
+++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.h
@@ -19,7 +19,6 @@
 #include <string>
 #include <vector>
 
-#include "dm-snapshot-merge/snapuserd_server.h"
 #include "user-space-merge/snapuserd_server.h"
 
 namespace android {
@@ -36,12 +35,10 @@
         return instance;
     }
 
-    bool StartServerForDmSnapshot(int arg_start, int argc, char** argv);
     bool StartServerForUserspaceSnapshots(int arg_start, int argc, char** argv);
     void Interrupt();
     void ReceivedSocketSignal();
     bool IsUserspaceSnapshotsEnabled();
-    bool IsDmSnapshotTestingEnabled();
     bool StartDaemon(int argc, char** argv);
 
   private:
@@ -51,7 +48,6 @@
     Daemon(Daemon const&) = delete;
     void operator=(Daemon const&) = delete;
 
-    SnapuserdServer server_;
     UserSnapshotServer user_server_;
     void MaskAllSignalsExceptIntAndTerm();
     void MaskAllSignals();