Integrate snapuserd with dm-user ABI changes.

Create loopback device to simulate system_a/product_a partitions
to test IO path.

Bug: 168259959
Test: cow_snapuserd_test

Signed-off-by: Akilesh Kailash <akailash@google.com>
Change-Id: I9f2a311d3eccfa20c82d0ebdb3e028ea3323a48d
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index ad592e9..0c5f3ba 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -544,9 +544,11 @@
 	"libsnapshot_snapuserd",
         "libcutils_sockets",
         "libz",
+	"libdm",
     ],
     header_libs: [
         "libstorage_literals_headers",
+        "libfiemap_headers",
     ],
     test_min_api_level: 30,
     auto_gen_config: true,
diff --git a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
index 75e54f7..1d6c104 100644
--- a/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/cow_snapuserd_test.cpp
@@ -12,12 +12,12 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-#include <fcntl.h>
 #include <linux/fs.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 
+#include <chrono>
 #include <iostream>
 #include <memory>
 #include <string_view>
@@ -25,6 +25,7 @@
 #include <android-base/file.h>
 #include <android-base/unique_fd.h>
 #include <gtest/gtest.h>
+#include <libdm/loop_control.h>
 #include <libsnapshot/cow_writer.h>
 #include <libsnapshot/snapuserd_client.h>
 #include <storage_literals/storage_literals.h>
@@ -34,6 +35,8 @@
 
 using namespace android::storage_literals;
 using android::base::unique_fd;
+using LoopDevice = android::dm::LoopDevice;
+using namespace std::chrono_literals;
 
 class SnapuserdTest : public ::testing::Test {
   protected:
@@ -50,6 +53,18 @@
         cow_product_1_ = std::make_unique<TemporaryFile>();
         ASSERT_GE(cow_product_1_->fd, 0) << strerror(errno);
 
+        // Create temp files in the PWD as selinux
+        // allows kernel domin to read from that directory only
+        // on userdebug/eng builds. Creating files under /data/local/tmp
+        // will have selinux denials.
+        std::string path = android::base::GetExecutableDirectory();
+
+        system_a_ = std::make_unique<TemporaryFile>(path);
+        ASSERT_GE(system_a_->fd, 0) << strerror(errno);
+
+        product_a_ = std::make_unique<TemporaryFile>(path);
+        ASSERT_GE(product_a_->fd, 0) << strerror(errno);
+
         size_ = 100_MiB;
     }
 
@@ -61,6 +76,12 @@
         cow_product_1_ = nullptr;
     }
 
+    std::unique_ptr<TemporaryFile> system_a_;
+    std::unique_ptr<TemporaryFile> product_a_;
+
+    std::unique_ptr<LoopDevice> system_a_loop_;
+    std::unique_ptr<LoopDevice> product_a_loop_;
+
     std::unique_ptr<TemporaryFile> cow_system_;
     std::unique_ptr<TemporaryFile> cow_product_;
 
@@ -76,6 +97,9 @@
     std::string system_device_name_;
     std::string product_device_name_;
 
+    std::string system_device_ctrl_name_;
+    std::string product_device_ctrl_name_;
+
     std::unique_ptr<uint8_t[]> random_buffer_1_;
     std::unique_ptr<uint8_t[]> random_buffer_2_;
     std::unique_ptr<uint8_t[]> zero_buffer_;
@@ -86,10 +110,18 @@
     void CreateCowDevice(std::unique_ptr<TemporaryFile>& cow);
     void CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow);
     void CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow);
+    void DeleteDmUser(std::unique_ptr<TemporaryFile>& cow, std::string snapshot_device);
     void StartSnapuserdDaemon();
     void CreateSnapshotDevices();
     void SwitchSnapshotDevices();
 
+    std::string GetSystemControlPath() {
+        return std::string("/dev/dm-user-") + system_device_ctrl_name_;
+    }
+    std::string GetProductControlPath() {
+        return std::string("/dev/dm-user-") + product_device_ctrl_name_;
+    }
+
     void TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>& buffer);
     SnapuserdClient client_;
 };
@@ -97,6 +129,7 @@
 void SnapuserdTest::Init() {
     unique_fd rnd_fd;
     loff_t offset = 0;
+    std::unique_ptr<uint8_t[]> random_buffer = std::make_unique<uint8_t[]>(1_MiB);
 
     rnd_fd.reset(open("/dev/random", O_RDONLY));
     ASSERT_TRUE(rnd_fd > 0);
@@ -118,10 +151,27 @@
         offset += 1_MiB;
     }
 
-    sys_fd_.reset(open("/dev/block/mapper/system_a", O_RDONLY));
+    for (size_t j = 0; j < (800_MiB / 1_MiB); j++) {
+        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
+        ASSERT_EQ(android::base::WriteFully(system_a_->fd, random_buffer.get(), 1_MiB), true);
+    }
+
+    for (size_t j = 0; j < (800_MiB / 1_MiB); j++) {
+        ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer.get(), 1_MiB, 0), true);
+        ASSERT_EQ(android::base::WriteFully(product_a_->fd, random_buffer.get(), 1_MiB), true);
+    }
+
+    // Create loopback devices
+    system_a_loop_ = std::make_unique<LoopDevice>(std::string(system_a_->path), 10s);
+    ASSERT_TRUE(system_a_loop_->valid());
+
+    product_a_loop_ = std::make_unique<LoopDevice>(std::string(product_a_->path), 10s);
+    ASSERT_TRUE(product_a_loop_->valid());
+
+    sys_fd_.reset(open(system_a_loop_->device().c_str(), O_RDONLY));
     ASSERT_TRUE(sys_fd_ > 0);
 
-    product_fd_.reset(open("/dev/block/mapper/product_a", O_RDONLY));
+    product_fd_.reset(open(product_a_loop_->device().c_str(), O_RDONLY));
     ASSERT_TRUE(product_fd_ > 0);
 
     // Read from system partition from offset 0 of size 100MB
@@ -183,47 +233,65 @@
 }
 
 void SnapuserdTest::CreateSystemDmUser(std::unique_ptr<TemporaryFile>& cow) {
-    unique_fd system_a_fd;
     std::string cmd;
     system_device_name_.clear();
+    system_device_ctrl_name_.clear();
 
     // Create a COW device. Number of sectors is chosen random which can
     // hold at least 400MB of data
 
-    system_a_fd.reset(open("/dev/block/mapper/system_a", O_RDONLY));
-    ASSERT_TRUE(system_a_fd > 0);
-
-    int err = ioctl(system_a_fd.get(), BLKGETSIZE, &system_blksize_);
+    int err = ioctl(sys_fd_.get(), BLKGETSIZE, &system_blksize_);
     ASSERT_GE(err, 0);
 
     std::string str(cow->path);
     std::size_t found = str.find_last_of("/\\");
     ASSERT_NE(found, std::string::npos);
     system_device_name_ = str.substr(found + 1);
+
+    // Create a control device
+    system_device_ctrl_name_ = system_device_name_ + "-ctrl";
     cmd = "dmctl create " + system_device_name_ + " user 0 " + std::to_string(system_blksize_);
+    cmd += " " + system_device_ctrl_name_;
+
+    system(cmd.c_str());
+}
+
+void SnapuserdTest::DeleteDmUser(std::unique_ptr<TemporaryFile>& cow, std::string snapshot_device) {
+    std::string cmd;
+
+    cmd = "dmctl delete " + snapshot_device;
+    system(cmd.c_str());
+
+    cmd.clear();
+
+    std::string str(cow->path);
+    std::size_t found = str.find_last_of("/\\");
+    ASSERT_NE(found, std::string::npos);
+    std::string device_name = str.substr(found + 1);
+
+    cmd = "dmctl delete " + device_name;
 
     system(cmd.c_str());
 }
 
 void SnapuserdTest::CreateProductDmUser(std::unique_ptr<TemporaryFile>& cow) {
-    unique_fd product_a_fd;
     std::string cmd;
     product_device_name_.clear();
+    product_device_ctrl_name_.clear();
 
     // Create a COW device. Number of sectors is chosen random which can
     // hold at least 400MB of data
 
-    product_a_fd.reset(open("/dev/block/mapper/product_a", O_RDONLY));
-    ASSERT_TRUE(product_a_fd > 0);
-
-    int err = ioctl(product_a_fd.get(), BLKGETSIZE, &product_blksize_);
+    int err = ioctl(product_fd_.get(), BLKGETSIZE, &product_blksize_);
     ASSERT_GE(err, 0);
 
     std::string str(cow->path);
     std::size_t found = str.find_last_of("/\\");
     ASSERT_NE(found, std::string::npos);
     product_device_name_ = str.substr(found + 1);
+    product_device_ctrl_name_ = product_device_name_ + "-ctrl";
     cmd = "dmctl create " + product_device_name_ + " user 0 " + std::to_string(product_blksize_);
+    cmd += " " + product_device_ctrl_name_;
 
     system(cmd.c_str());
 }
@@ -234,10 +302,12 @@
     ret = client_.StartSnapuserd();
     ASSERT_EQ(ret, 0);
 
-    ret = client_.InitializeSnapuserd(cow_system_->path, "/dev/block/mapper/system_a");
+    ret = client_.InitializeSnapuserd(cow_system_->path, system_a_loop_->device(),
+                                      GetSystemControlPath());
     ASSERT_EQ(ret, 0);
 
-    ret = client_.InitializeSnapuserd(cow_product_->path, "/dev/block/mapper/product_a");
+    ret = client_.InitializeSnapuserd(cow_product_->path, product_a_loop_->device(),
+                                      GetProductControlPath());
     ASSERT_EQ(ret, 0);
 }
 
@@ -245,7 +315,7 @@
     std::string cmd;
 
     cmd = "dmctl create system-snapshot -ro snapshot 0 " + std::to_string(system_blksize_);
-    cmd += " /dev/block/mapper/system_a";
+    cmd += " " + system_a_loop_->device();
     cmd += " /dev/block/mapper/" + system_device_name_;
     cmd += " P 8";
 
@@ -254,7 +324,7 @@
     cmd.clear();
 
     cmd = "dmctl create product-snapshot -ro snapshot 0 " + std::to_string(product_blksize_);
-    cmd += " /dev/block/mapper/product_a";
+    cmd += " " + product_a_loop_->device();
     cmd += " /dev/block/mapper/" + product_device_name_;
     cmd += " P 8";
 
@@ -265,7 +335,7 @@
     std::string cmd;
 
     cmd = "dmctl create system-snapshot-1 -ro snapshot 0 " + std::to_string(system_blksize_);
-    cmd += " /dev/block/mapper/system_a";
+    cmd += " " + system_a_loop_->device();
     cmd += " /dev/block/mapper/" + system_device_name_;
     cmd += " P 8";
 
@@ -274,7 +344,7 @@
     cmd.clear();
 
     cmd = "dmctl create product-snapshot-1 -ro snapshot 0 " + std::to_string(product_blksize_);
-    cmd += " /dev/block/mapper/product_a";
+    cmd += " " + product_a_loop_->device();
     cmd += " /dev/block/mapper/" + product_device_name_;
     cmd += " P 8";
 
@@ -318,7 +388,7 @@
     //
     // IO path:
     //
-    // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_from_system_a_partition
+    // dm-snap->dm-snap-persistent->dm-user->snapuserd->read_from_(system_a/product_a) partition
     // (copy op) -> return
     ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
 
@@ -379,24 +449,33 @@
     ASSERT_TRUE(snapshot_fd > 0);
     TestIO(snapshot_fd, product_buffer_);
 
+    snapshot_fd.reset(-1);
+
     // Sequence of operations for transition
     CreateCowDevice(cow_system_1_);
     CreateCowDevice(cow_product_1_);
 
+    // Create dm-user which creates new control devices
     CreateSystemDmUser(cow_system_1_);
     CreateProductDmUser(cow_product_1_);
 
-    std::vector<std::pair<std::string, std::string>> vec;
-    vec.push_back(std::make_pair(cow_system_1_->path, "/dev/block/mapper/system_a"));
-    vec.push_back(std::make_pair(cow_product_1_->path, "/dev/block/mapper/product_a"));
+    // Send the path information to second stage daemon through vector
+    std::vector<std::vector<std::string>> vec{
+            {cow_system_1_->path, system_a_loop_->device(), GetSystemControlPath()},
+            {cow_product_1_->path, product_a_loop_->device(), GetProductControlPath()}};
 
-    // Start the second stage deamon and send the devices
+    // Start the second stage deamon and send the devices information through
+    // vector.
     ASSERT_EQ(client_.RestartSnapuserd(vec), 0);
 
     // TODO: This is not switching snapshot device but creates a new table;
-    // however, it should serve the testing purpose.
+    // Second stage daemon will be ready to serve the IO request. From now
+    // onwards, we can go ahead and shutdown the first stage daemon
     SwitchSnapshotDevices();
 
+    DeleteDmUser(cow_system_, "system-snapshot");
+    DeleteDmUser(cow_product_, "product-snapshot");
+
     // Stop the first stage daemon
     ASSERT_EQ(client_.StopSnapuserd(true), 0);
 
@@ -409,6 +488,11 @@
     ASSERT_TRUE(snapshot_fd > 0);
     TestIO(snapshot_fd, product_buffer_);
 
+    snapshot_fd.reset(-1);
+
+    DeleteDmUser(cow_system_1_, "system-snapshot-1");
+    DeleteDmUser(cow_product_1_, "product-snapshot-1");
+
     // Stop the second stage daemon
     ASSERT_EQ(client_.StopSnapuserd(false), 0);
 }
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
index d495014..2f727d6 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd.h
@@ -60,9 +60,11 @@
 
 class Snapuserd final {
   public:
-    Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device)
+    Snapuserd(const std::string& in_cow_device, const std::string& in_backing_store_device,
+              const std::string& in_control_device)
         : cow_device_(in_cow_device),
           backing_store_device_(in_backing_store_device),
+          control_device_(in_control_device),
           metadata_read_done_(false) {}
 
     bool Init();
@@ -75,6 +77,8 @@
     int ReadDiskExceptions(chunk_t chunk, size_t size);
     int ReadData(chunk_t chunk, size_t size);
 
+    std::string GetControlDevicePath() { return control_device_; }
+
   private:
     int ProcessReplaceOp(const CowOperation* cow_op);
     int ProcessCopyOp(const CowOperation* cow_op);
@@ -82,6 +86,7 @@
 
     std::string cow_device_;
     std::string backing_store_device_;
+    std::string control_device_;
 
     unique_fd cow_fd_;
     unique_fd backing_store_fd_;
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
index 535e923..ab2149e 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_client.h
@@ -51,8 +51,9 @@
   public:
     int StartSnapuserd();
     int StopSnapuserd(bool firstStageDaemon);
-    int RestartSnapuserd(std::vector<std::pair<std::string, std::string>>& vec);
-    int InitializeSnapuserd(std::string cow_device, std::string backing_device);
+    int RestartSnapuserd(std::vector<std::vector<std::string>>& vec);
+    int InitializeSnapuserd(std::string cow_device, std::string backing_device,
+                            std::string control_device);
 };
 
 }  // namespace snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
index 1a6ba8f..1037c12 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_kernel.h
@@ -80,7 +80,6 @@
     __u64 flags;
     __u64 sector;
     __u64 len;
-    __u64 io_in_progress;
 } __attribute__((packed));
 
 struct dm_user_payload {
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
index 584fe71..a1ebd3a 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapuserd_server.h
@@ -60,7 +60,8 @@
 
     virtual ~Stoppable() {}
 
-    virtual void ThreadStart(std::string cow_device, std::string backing_device) = 0;
+    virtual void ThreadStart(std::string cow_device, std::string backing_device,
+                             std::string control_device) = 0;
 
     bool StopRequested() {
         // checks if value in future object is available
@@ -78,7 +79,8 @@
     bool terminating_;
     std::vector<std::unique_ptr<Client>> clients_vec_;
 
-    void ThreadStart(std::string cow_device, std::string backing_device) override;
+    void ThreadStart(std::string cow_device, std::string backing_device,
+                     std::string control_device) override;
     void ShutdownThreads();
     DaemonOperations Resolveop(std::string& input);
     std::string GetDaemonStatus();
diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp
index 3ed853f..62ef1b0 100644
--- a/fs_mgr/libsnapshot/snapuserd.cpp
+++ b/fs_mgr/libsnapshot/snapuserd.cpp
@@ -34,18 +34,6 @@
 
 static_assert(PAYLOAD_SIZE >= BLOCK_SIZE);
 
-class Target {
-  public:
-    // Represents an already-created Target, which is referenced by UUID.
-    Target(std::string uuid) : uuid_(uuid) {}
-
-    const auto& uuid() { return uuid_; }
-    std::string control_path() { return std::string("/dev/dm-user-") + uuid(); }
-
-  private:
-    const std::string uuid_;
-};
-
 void BufferSink::Initialize(size_t size) {
     buffer_size_ = size;
     buffer_offset_ = 0;
@@ -498,26 +486,13 @@
         return false;
     }
 
-    std::string str(cow_device_);
-    std::size_t found = str.find_last_of("/\\");
-    CHECK(found != std::string::npos);
-    std::string device_name = str.substr(found + 1);
+    std::string control_path = GetControlDevicePath();
 
-    LOG(DEBUG) << "Fetching UUID for: " << device_name;
+    LOG(DEBUG) << "Opening control device " << control_path;
 
-    auto& dm = dm::DeviceMapper::Instance();
-    std::string uuid;
-    if (!dm.GetDmDeviceUuidByName(device_name, &uuid)) {
-        LOG(ERROR) << "Unable to find UUID for " << cow_device_;
-        return false;
-    }
-
-    LOG(DEBUG) << "UUID: " << uuid;
-    Target t(uuid);
-
-    ctrl_fd_.reset(open(t.control_path().c_str(), O_RDWR));
+    ctrl_fd_.reset(open(control_path.c_str(), O_RDWR));
     if (ctrl_fd_ < 0) {
-        LOG(ERROR) << "Unable to open " << t.control_path();
+        LOG(ERROR) << "Unable to open " << control_path;
         return false;
     }
 
@@ -553,7 +528,6 @@
         case DM_USER_MAP_READ: {
             size_t remaining_size = header->len;
             loff_t offset = 0;
-            header->io_in_progress = 0;
             ret = 0;
             do {
                 size_t read_size = std::min(PAYLOAD_SIZE, remaining_size);
@@ -619,7 +593,6 @@
                 if (remaining_size) {
                     LOG(DEBUG) << "Write done ret: " << ret
                                << " remaining size: " << remaining_size;
-                    bufsink_.GetHeaderPtr()->io_in_progress = 1;
                 }
             } while (remaining_size);
 
diff --git a/fs_mgr/libsnapshot/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd_client.cpp
index bef8f5c..78dbada 100644
--- a/fs_mgr/libsnapshot/snapuserd_client.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_client.cpp
@@ -127,24 +127,6 @@
     return msgStr;
 }
 
-#if 0
-std::string SnapuserdClient::Receivemsg() {
-    char msg[PACKET_SIZE];
-    std::string msgStr("fail");
-    int ret;
-
-    ret = TEMP_FAILURE_RETRY(recv(sockfd_, msg, PACKET_SIZE, 0));
-    if (ret <= 0) {
-        LOG(ERROR) << "recv failed " << strerror(errno);
-        return msgStr;
-    }
-
-    msgStr.clear();
-    msgStr = msg;
-    return msgStr;
-}
-#endif
-
 int SnapuserdClient::StopSnapuserd(bool firstStageDaemon) {
     if (firstStageDaemon) {
         sockfd_ = socket_local_client(GetSocketNameFirstStage().c_str(),
@@ -209,7 +191,8 @@
     return 0;
 }
 
-int SnapuserdClient::InitializeSnapuserd(std::string cow_device, std::string backing_device) {
+int SnapuserdClient::InitializeSnapuserd(std::string cow_device, std::string backing_device,
+                                         std::string control_device) {
     int ret = 0;
 
     if (!ConnectToServer()) {
@@ -217,7 +200,7 @@
         return -1;
     }
 
-    std::string msg = "start," + cow_device + "," + backing_device;
+    std::string msg = "start," + cow_device + "," + backing_device + "," + control_device;
 
     ret = Sendmsg(msg.c_str(), msg.size());
     if (ret < 0) {
@@ -270,7 +253,7 @@
  * completely active to serve the IO and merging process.
  *
  */
-int SnapuserdClient::RestartSnapuserd(std::vector<std::pair<std::string, std::string>>& vec) {
+int SnapuserdClient::RestartSnapuserd(std::vector<std::vector<std::string>>& vec) {
     // Connect to first-stage daemon and send a terminate-request control
     // message. This will not terminate the daemon but will mark the daemon as
     // passive.
@@ -306,14 +289,19 @@
 
     LOG(DEBUG) << "Second stage Snapuserd daemon created successfully at socket "
                << GetSocketNameSecondStage();
-    CHECK(vec.size() % 2 == 0);
 
+    // Vector contains all the device information to be passed to the new
+    // daemon. Note that the caller can choose to initialize separately
+    // by calling InitializeSnapuserd() API as well. In that case, vector
+    // should be empty
     for (int i = 0; i < vec.size(); i++) {
-        std::string& cow_device = vec[i].first;
-        std::string& base_device = vec[i].second;
+        std::string& cow_device = vec[i][0];
+        std::string& base_device = vec[i][1];
+        std::string& control_device = vec[i][2];
 
-        InitializeSnapuserd(cow_device, base_device);
-        LOG(DEBUG) << "Daemon initialized with " << cow_device << " and " << base_device;
+        InitializeSnapuserd(cow_device, base_device, control_device);
+        LOG(DEBUG) << "Daemon initialized with " << cow_device << ", " << base_device << " and "
+                   << control_device;
     }
 
     return 0;
diff --git a/fs_mgr/libsnapshot/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd_server.cpp
index 1f8dd63..53101aa 100644
--- a/fs_mgr/libsnapshot/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd_server.cpp
@@ -63,8 +63,9 @@
 }
 
 // new thread
-void SnapuserdServer::ThreadStart(std::string cow_device, std::string backing_device) {
-    Snapuserd snapd(cow_device, backing_device);
+void SnapuserdServer::ThreadStart(std::string cow_device, std::string backing_device,
+                                  std::string control_device) {
+    Snapuserd snapd(cow_device, backing_device, control_device);
     if (!snapd.Init()) {
         PLOG(ERROR) << "Snapuserd: Init failed";
         return;
@@ -73,10 +74,9 @@
     while (StopRequested() == false) {
         int ret = snapd.Run();
 
-        if (ret == -ETIMEDOUT) continue;
-
         if (ret < 0) {
-            PLOG(ERROR) << "snapd.Run() failed..." << ret;
+            LOG(ERROR) << "Snapuserd: Thread terminating as control device is de-registered";
+            break;
         }
     }
 }
@@ -159,12 +159,12 @@
         switch (op) {
             case DaemonOperations::START: {
                 // Message format:
-                // start,<cow_device_path>,<source_device_path>
+                // start,<cow_device_path>,<source_device_path>,<control_device>
                 //
                 // Start the new thread which binds to dm-user misc device
                 newClient = std::make_unique<Client>();
                 newClient->SetThreadHandler(
-                        std::bind(&SnapuserdServer::ThreadStart, this, out[1], out[2]));
+                        std::bind(&SnapuserdServer::ThreadStart, this, out[1], out[2], out[3]));
                 clients_vec_.push_back(std::move(newClient));
                 sprintf(msg, "success");
                 Sendmsg(fd, msg, MAX_PACKET_SIZE);