Support of multiple device partitions by dm-user driver
Add basic support for daemon creation and handle signals Test: Add test case to test system and product COW partitions Bug: 162790322 Signed-off-by: Akilesh Kailash <akailash@google.com> Change-Id: Icf8dbe49d2237cec6f7dbcdd84256eb6c5afa1cd
This commit is contained in:
parent
7dd8fe8e70
commit
516ded7320
5 changed files with 272 additions and 80 deletions
|
|
@ -429,7 +429,7 @@ bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* p
|
|||
|
||||
// Accepts a device mapper device name (like system_a, vendor_b etc) and
|
||||
// returns its UUID.
|
||||
bool DeviceMapper::GetDmDeviceUUIDByName(const std::string& name, std::string* uuid) {
|
||||
bool DeviceMapper::GetDmDeviceUuidByName(const std::string& name, std::string* uuid) {
|
||||
struct dm_ioctl io;
|
||||
InitIo(&io, name);
|
||||
if (ioctl(fd_, DM_DEV_STATUS, &io) < 0) {
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ class DeviceMapper final {
|
|||
//
|
||||
// WaitForFile() should not be used in conjunction with this call, since it
|
||||
// could race with ueventd.
|
||||
bool GetDmDeviceUUIDByName(const std::string& name, std::string* path);
|
||||
bool GetDmDeviceUuidByName(const std::string& name, std::string* path);
|
||||
|
||||
// Returns a device's unique path as generated by ueventd. This will return
|
||||
// true as long as the device has been created, even if ueventd has not
|
||||
|
|
|
|||
|
|
@ -37,52 +37,86 @@ using android::base::unique_fd;
|
|||
class SnapuserdTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override {
|
||||
cow_ = std::make_unique<TemporaryFile>();
|
||||
ASSERT_GE(cow_->fd, 0) << strerror(errno);
|
||||
cow_system_ = std::make_unique<TemporaryFile>();
|
||||
ASSERT_GE(cow_system_->fd, 0) << strerror(errno);
|
||||
|
||||
cow_product_ = std::make_unique<TemporaryFile>();
|
||||
ASSERT_GE(cow_product_->fd, 0) << strerror(errno);
|
||||
|
||||
size_ = 100_MiB;
|
||||
}
|
||||
|
||||
void TearDown() override { cow_ = nullptr; }
|
||||
void TearDown() override {
|
||||
cow_system_ = nullptr;
|
||||
cow_product_ = nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<TemporaryFile> cow_;
|
||||
std::unique_ptr<TemporaryFile> cow_system_;
|
||||
std::unique_ptr<TemporaryFile> cow_product_;
|
||||
|
||||
unique_fd sys_fd_;
|
||||
unique_fd product_fd_;
|
||||
size_t size_;
|
||||
|
||||
int system_blksize_;
|
||||
int product_blksize_;
|
||||
std::string system_device_name_;
|
||||
std::string product_device_name_;
|
||||
|
||||
std::unique_ptr<uint8_t[]> random_buffer_1_;
|
||||
std::unique_ptr<uint8_t[]> random_buffer_2_;
|
||||
std::unique_ptr<uint8_t[]> zero_buffer_;
|
||||
std::unique_ptr<uint8_t[]> system_buffer_;
|
||||
std::unique_ptr<uint8_t[]> product_buffer_;
|
||||
|
||||
void Init();
|
||||
void CreateCowDevice(std::unique_ptr<TemporaryFile>& cow);
|
||||
void CreateSystemDmUser();
|
||||
void CreateProductDmUser();
|
||||
void StartSnapuserdDaemon();
|
||||
void CreateSnapshotDevices();
|
||||
|
||||
void TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>&& buf);
|
||||
};
|
||||
|
||||
TEST_F(SnapuserdTest, ReadWrite) {
|
||||
loff_t offset = 0;
|
||||
size_t size = 100_MiB;
|
||||
void SnapuserdTest::Init() {
|
||||
unique_fd rnd_fd;
|
||||
unique_fd sys_fd;
|
||||
unique_fd snapshot_fd;
|
||||
unique_fd system_a_fd;
|
||||
std::string cmd;
|
||||
loff_t offset = 0;
|
||||
|
||||
rnd_fd.reset(open("/dev/random", O_RDONLY));
|
||||
ASSERT_TRUE(rnd_fd > 0);
|
||||
|
||||
std::unique_ptr<uint8_t[]> random_buffer_1;
|
||||
std::unique_ptr<uint8_t[]> random_buffer_2;
|
||||
std::unique_ptr<uint8_t[]> system_buffer;
|
||||
|
||||
random_buffer_1 = std::make_unique<uint8_t[]>(size);
|
||||
|
||||
random_buffer_2 = std::make_unique<uint8_t[]>(size);
|
||||
|
||||
system_buffer = std::make_unique<uint8_t[]>(size);
|
||||
random_buffer_1_ = std::make_unique<uint8_t[]>(size_);
|
||||
random_buffer_2_ = std::make_unique<uint8_t[]>(size_);
|
||||
system_buffer_ = std::make_unique<uint8_t[]>(size_);
|
||||
product_buffer_ = std::make_unique<uint8_t[]>(size_);
|
||||
zero_buffer_ = 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);
|
||||
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);
|
||||
|
||||
ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_2.get() + offset, 1_MiB, 0), true);
|
||||
ASSERT_EQ(ReadFullyAtOffset(rnd_fd, (char*)random_buffer_2_.get() + offset, 1_MiB, 0),
|
||||
true);
|
||||
|
||||
offset += 1_MiB;
|
||||
}
|
||||
|
||||
sys_fd.reset(open("/dev/block/mapper/system_a", O_RDONLY));
|
||||
ASSERT_TRUE(sys_fd > 0);
|
||||
sys_fd_.reset(open("/dev/block/mapper/system_a", O_RDONLY));
|
||||
ASSERT_TRUE(sys_fd_ > 0);
|
||||
|
||||
product_fd_.reset(open("/dev/block/mapper/product_a", O_RDONLY));
|
||||
ASSERT_TRUE(product_fd_ > 0);
|
||||
|
||||
// Read from system partition from offset 0 of size 100MB
|
||||
ASSERT_EQ(ReadFullyAtOffset(sys_fd, system_buffer.get(), size, 0), true);
|
||||
ASSERT_EQ(ReadFullyAtOffset(sys_fd_, system_buffer_.get(), size_, 0), true);
|
||||
|
||||
// Read from system partition from offset 0 of size 100MB
|
||||
ASSERT_EQ(ReadFullyAtOffset(product_fd_, product_buffer_.get(), size_, 0), true);
|
||||
}
|
||||
|
||||
void SnapuserdTest::CreateCowDevice(std::unique_ptr<TemporaryFile>& cow) {
|
||||
//================Create a COW file with the following operations===========
|
||||
//
|
||||
// Create COW file which is gz compressed
|
||||
|
|
@ -96,12 +130,12 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
options.compression = "gz";
|
||||
CowWriter writer(options);
|
||||
|
||||
ASSERT_TRUE(writer.Initialize(cow_->fd));
|
||||
ASSERT_TRUE(writer.Initialize(cow->fd));
|
||||
|
||||
// Write 100MB random data to COW file which is gz compressed from block 0
|
||||
ASSERT_TRUE(writer.AddRawBlocks(0, random_buffer_1.get(), size));
|
||||
ASSERT_TRUE(writer.AddRawBlocks(0, random_buffer_1_.get(), size_));
|
||||
|
||||
size_t num_blocks = size / options.block_size;
|
||||
size_t num_blocks = size_ / options.block_size;
|
||||
size_t blk_start_copy = num_blocks;
|
||||
size_t blk_end_copy = blk_start_copy + num_blocks;
|
||||
size_t source_blk = 0;
|
||||
|
|
@ -110,7 +144,7 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
// has to read from block 0 in system_a partition
|
||||
//
|
||||
// This initializes copy operation from block 0 of size 100 MB from
|
||||
// /dev/block/mapper/system_a
|
||||
// /dev/block/mapper/system_a or product_a
|
||||
for (size_t i = blk_start_copy; i < blk_end_copy; i++) {
|
||||
ASSERT_TRUE(writer.AddCopy(i, source_blk));
|
||||
source_blk += 1;
|
||||
|
|
@ -125,14 +159,17 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
// Final 100MB filled with random data which is gz compressed
|
||||
size_t blk_random2_replace_start = blk_zero_copy_end;
|
||||
|
||||
ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_2.get(), size));
|
||||
ASSERT_TRUE(writer.AddRawBlocks(blk_random2_replace_start, random_buffer_2_.get(), size_));
|
||||
|
||||
// Flush operations
|
||||
ASSERT_TRUE(writer.Finalize());
|
||||
|
||||
ASSERT_EQ(lseek(cow_->fd, 0, SEEK_SET), 0);
|
||||
ASSERT_EQ(lseek(cow->fd, 0, SEEK_SET), 0);
|
||||
}
|
||||
|
||||
//================Setup dm-snapshot and start snapuserd daemon===========
|
||||
void SnapuserdTest::CreateSystemDmUser() {
|
||||
unique_fd system_a_fd;
|
||||
std::string cmd;
|
||||
|
||||
// Create a COW device. Number of sectors is chosen random which can
|
||||
// hold at least 400MB of data
|
||||
|
|
@ -140,39 +177,77 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
system_a_fd.reset(open("/dev/block/mapper/system_a", O_RDONLY));
|
||||
ASSERT_TRUE(system_a_fd > 0);
|
||||
|
||||
int blksize;
|
||||
int err = ioctl(system_a_fd.get(), BLKGETSIZE, &blksize);
|
||||
if (err < 0) {
|
||||
ASSERT_TRUE(0);
|
||||
}
|
||||
int err = ioctl(system_a_fd.get(), BLKGETSIZE, &system_blksize_);
|
||||
ASSERT_GE(err, 0);
|
||||
|
||||
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);
|
||||
cmd = "dmctl create " + system_device_name_ + " user 0 " + std::to_string(system_blksize_);
|
||||
|
||||
cmd = "dmctl create system_cow user 0 " + std::to_string(blksize);
|
||||
system(cmd.c_str());
|
||||
}
|
||||
|
||||
void SnapuserdTest::CreateProductDmUser() {
|
||||
unique_fd product_a_fd;
|
||||
std::string cmd;
|
||||
|
||||
// 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_);
|
||||
ASSERT_GE(err, 0);
|
||||
|
||||
std::string str(cow_product_->path);
|
||||
std::size_t found = str.find_last_of("/\\");
|
||||
ASSERT_NE(found, std::string::npos);
|
||||
product_device_name_ = str.substr(found + 1);
|
||||
cmd = "dmctl create " + product_device_name_ + " user 0 " + std::to_string(product_blksize_);
|
||||
|
||||
system(cmd.c_str());
|
||||
}
|
||||
|
||||
void SnapuserdTest::StartSnapuserdDaemon() {
|
||||
// Start the snapuserd daemon
|
||||
if (fork() == 0) {
|
||||
const char* argv[] = {"/system/bin/snapuserd", cow_->path, "/dev/block/mapper/system_a",
|
||||
nullptr};
|
||||
const char* argv[] = {"/system/bin/snapuserd", cow_system_->path,
|
||||
"/dev/block/mapper/system_a", cow_product_->path,
|
||||
"/dev/block/mapper/product_a", nullptr};
|
||||
if (execv(argv[0], const_cast<char**>(argv))) {
|
||||
ASSERT_TRUE(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SnapuserdTest::CreateSnapshotDevices() {
|
||||
std::string cmd;
|
||||
|
||||
cmd = "dmctl create system-snapshot -ro snapshot 0 " + std::to_string(system_blksize_);
|
||||
cmd += " /dev/block/mapper/system_a";
|
||||
cmd += " /dev/block/mapper/" + system_device_name_;
|
||||
cmd += " P 8";
|
||||
|
||||
system(cmd.c_str());
|
||||
|
||||
cmd.clear();
|
||||
|
||||
cmd = "dmctl create system-snapshot -ro snapshot 0 " + std::to_string(blksize);
|
||||
cmd += " /dev/block/mapper/system_a /dev/block/mapper/system_cow ";
|
||||
cmd += "P 8";
|
||||
cmd = "dmctl create product-snapshot -ro snapshot 0 " + std::to_string(product_blksize_);
|
||||
cmd += " /dev/block/mapper/product_a";
|
||||
cmd += " /dev/block/mapper/" + product_device_name_;
|
||||
cmd += " P 8";
|
||||
|
||||
system(cmd.c_str());
|
||||
}
|
||||
|
||||
// Wait so that snapshot device is created
|
||||
sleep(5);
|
||||
std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size);
|
||||
void SnapuserdTest::TestIO(unique_fd& snapshot_fd, std::unique_ptr<uint8_t[]>&& buf) {
|
||||
loff_t offset = 0;
|
||||
std::unique_ptr<uint8_t[]> buffer = std::move(buf);
|
||||
|
||||
offset = 0;
|
||||
|
||||
snapshot_fd.reset(open("/dev/block/mapper/system-snapshot", O_RDONLY));
|
||||
ASSERT_TRUE(snapshot_fd > 0);
|
||||
std::unique_ptr<uint8_t[]> snapuserd_buffer = std::make_unique<uint8_t[]>(size_);
|
||||
|
||||
//================Start IO operation on dm-snapshot device=================
|
||||
// This will test the following paths:
|
||||
|
|
@ -189,16 +264,16 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
// dm-snap->dm-snap-persistent->dm-user->snapuserd->read_compressed_cow (replace
|
||||
// op)->decompress_cow->return
|
||||
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size, offset), true);
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
|
||||
|
||||
// Update the offset
|
||||
offset += size;
|
||||
offset += size_;
|
||||
|
||||
// Compare data with random_buffer_1.
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_1.get(), size), 0);
|
||||
// Compare data with random_buffer_1_.
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_1_.get(), size_), 0);
|
||||
|
||||
// Clear the buffer
|
||||
memset(snapuserd_buffer.get(), 0, size);
|
||||
memset(snapuserd_buffer.get(), 0, size_);
|
||||
|
||||
// Read from snapshot device of size 100MB from offset 100MB. This tests the
|
||||
// copy operation.
|
||||
|
|
@ -207,13 +282,13 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
//
|
||||
// dm-snap->dm-snap-persistent->dm-user->snapuserd->read_from_system_a_partition
|
||||
// (copy op) -> return
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size, offset), true);
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
|
||||
|
||||
// Update the offset
|
||||
offset += size;
|
||||
offset += size_;
|
||||
|
||||
// Compare data with system_buffer.
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), system_buffer.get(), size), 0);
|
||||
// Compare data with buffer.
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), buffer.get(), size_), 0);
|
||||
|
||||
// Read from snapshot device of size 100MB from offset 200MB. This tests the
|
||||
// zero operation.
|
||||
|
|
@ -222,16 +297,13 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
//
|
||||
// dm-snap->dm-snap-persistent->dm-user->snapuserd->fill_memory_with_zero
|
||||
// (zero op) -> return
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size, offset), true);
|
||||
|
||||
// Fill the random_buffer_1 with zero as we no longer need it
|
||||
memset(random_buffer_1.get(), 0, size);
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
|
||||
|
||||
// Compare data with zero filled buffer
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_1.get(), size), 0);
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), zero_buffer_.get(), size_), 0);
|
||||
|
||||
// Update the offset
|
||||
offset += size;
|
||||
offset += size_;
|
||||
|
||||
// Read from snapshot device of size 100MB from offset 300MB. This tests the
|
||||
// final replace operation.
|
||||
|
|
@ -240,10 +312,34 @@ TEST_F(SnapuserdTest, ReadWrite) {
|
|||
//
|
||||
// dm-snap->dm-snap-persistent->dm-user->snapuserd->read_compressed_cow (replace
|
||||
// op)->decompress_cow->return
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size, offset), true);
|
||||
ASSERT_EQ(ReadFullyAtOffset(snapshot_fd, snapuserd_buffer.get(), size_, offset), true);
|
||||
|
||||
// Compare data with random_buffer_2.
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_2.get(), size), 0);
|
||||
// Compare data with random_buffer_2_.
|
||||
ASSERT_EQ(memcmp(snapuserd_buffer.get(), random_buffer_2_.get(), size_), 0);
|
||||
}
|
||||
|
||||
TEST_F(SnapuserdTest, ReadWrite) {
|
||||
unique_fd snapshot_fd;
|
||||
|
||||
Init();
|
||||
|
||||
CreateCowDevice(cow_system_);
|
||||
CreateCowDevice(cow_product_);
|
||||
|
||||
CreateSystemDmUser();
|
||||
CreateProductDmUser();
|
||||
|
||||
StartSnapuserdDaemon();
|
||||
|
||||
CreateSnapshotDevices();
|
||||
|
||||
snapshot_fd.reset(open("/dev/block/mapper/system-snapshot", O_RDONLY));
|
||||
ASSERT_TRUE(snapshot_fd > 0);
|
||||
TestIO(snapshot_fd, std::move(system_buffer_));
|
||||
|
||||
snapshot_fd.reset(open("/dev/block/mapper/product-snapshot", O_RDONLY));
|
||||
ASSERT_TRUE(snapshot_fd > 0);
|
||||
TestIO(snapshot_fd, std::move(product_buffer_));
|
||||
}
|
||||
|
||||
} // namespace snapshot
|
||||
|
|
|
|||
|
|
@ -17,10 +17,12 @@
|
|||
#include <linux/types.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <csignal>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
|
@ -35,6 +37,7 @@
|
|||
namespace android {
|
||||
namespace snapshot {
|
||||
|
||||
using namespace android;
|
||||
using namespace android::dm;
|
||||
using android::base::unique_fd;
|
||||
|
||||
|
|
@ -45,6 +48,60 @@ static constexpr size_t PAYLOAD_SIZE = (1UL << 16);
|
|||
|
||||
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_;
|
||||
};
|
||||
|
||||
class Daemon {
|
||||
// The Daemon class is a singleton to avoid
|
||||
// instantiating more than once
|
||||
public:
|
||||
static Daemon& Instance() {
|
||||
static Daemon instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
bool IsRunning();
|
||||
|
||||
private:
|
||||
bool is_running_;
|
||||
|
||||
Daemon();
|
||||
Daemon(Daemon const&) = delete;
|
||||
void operator=(Daemon const&) = delete;
|
||||
|
||||
static void SignalHandler(int signal);
|
||||
};
|
||||
|
||||
Daemon::Daemon() {
|
||||
is_running_ = true;
|
||||
signal(SIGINT, Daemon::SignalHandler);
|
||||
signal(SIGTERM, Daemon::SignalHandler);
|
||||
}
|
||||
|
||||
bool Daemon::IsRunning() {
|
||||
return is_running_;
|
||||
}
|
||||
|
||||
void Daemon::SignalHandler(int signal) {
|
||||
LOG(DEBUG) << "Snapuserd received signal: " << signal;
|
||||
switch (signal) {
|
||||
case SIGINT:
|
||||
case SIGTERM: {
|
||||
Daemon::Instance().is_running_ = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BufferSink : public IByteSink {
|
||||
public:
|
||||
void Initialize(size_t size) {
|
||||
|
|
@ -558,10 +615,26 @@ int Snapuserd::Run() {
|
|||
return 1;
|
||||
}
|
||||
|
||||
// TODO: use UUID to support multiple partitions
|
||||
ctrl_fd_.reset(open("/dev/dm-user", O_RDWR));
|
||||
std::string str(in_cow_device_);
|
||||
std::size_t found = str.find_last_of("/\\");
|
||||
CHECK(found != std::string::npos);
|
||||
std::string device_name = str.substr(found + 1);
|
||||
|
||||
LOG(DEBUG) << "Fetching UUID for: " << device_name;
|
||||
|
||||
auto& dm = dm::DeviceMapper::Instance();
|
||||
std::string uuid;
|
||||
if (!dm.GetDmDeviceUuidByName(device_name, &uuid)) {
|
||||
LOG(ERROR) << "Unable to find UUID for " << in_cow_device_;
|
||||
return 1;
|
||||
}
|
||||
|
||||
LOG(DEBUG) << "UUID: " << uuid;
|
||||
Target t(uuid);
|
||||
|
||||
ctrl_fd_.reset(open(t.control_path().c_str(), O_RDWR));
|
||||
if (ctrl_fd_ < 0) {
|
||||
LOG(ERROR) << "Unable to open /dev/dm-user";
|
||||
LOG(ERROR) << "Unable to open " << t.control_path();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
@ -682,9 +755,30 @@ int Snapuserd::Run() {
|
|||
} // namespace snapshot
|
||||
} // namespace android
|
||||
|
||||
void run_thread(std::string cow_device, std::string backing_device) {
|
||||
android::snapshot::Snapuserd snapd(cow_device, backing_device);
|
||||
snapd.Run();
|
||||
}
|
||||
|
||||
int main([[maybe_unused]] int argc, char** argv) {
|
||||
android::base::InitLogging(argv, &android::base::KernelLogger);
|
||||
android::snapshot::Snapuserd snapd(argv[1], argv[2]);
|
||||
|
||||
return snapd.Run();
|
||||
android::snapshot::Daemon& daemon = android::snapshot::Daemon::Instance();
|
||||
|
||||
while (daemon.IsRunning()) {
|
||||
// TODO: This is hardcoded wherein:
|
||||
// argv[1] = system_cow, argv[2] = /dev/block/mapper/system_a
|
||||
// argv[3] = product_cow, argv[4] = /dev/block/mapper/product_a
|
||||
//
|
||||
// This should be fixed based on some kind of IPC or setup a
|
||||
// command socket and spin up the thread based when a new
|
||||
// partition is visible.
|
||||
std::thread system_a(run_thread, argv[1], argv[2]);
|
||||
std::thread product_a(run_thread, argv[3], argv[4]);
|
||||
|
||||
system_a.join();
|
||||
product_a.join();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@
|
|||
#include <vector>
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
using namespace std::chrono_literals;
|
||||
using namespace android::dm;
|
||||
using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
|
||||
|
||||
|
|
@ -242,8 +243,9 @@ static int DmCreateCmdHandler(int argc, char** argv) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
std::string ignore_path;
|
||||
DeviceMapper& dm = DeviceMapper::Instance();
|
||||
if (!dm.CreateDevice(name, table)) {
|
||||
if (!dm.CreateDevice(name, table, &ignore_path, 5s)) {
|
||||
std::cerr << "Failed to create device-mapper device with name: " << name << std::endl;
|
||||
return -EIO;
|
||||
}
|
||||
|
|
@ -392,7 +394,7 @@ static int GetPathCmdHandler(int argc, char** argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int GetUUIDCmdHandler(int argc, char** argv) {
|
||||
static int GetUuidCmdHandler(int argc, char** argv) {
|
||||
if (argc != 1) {
|
||||
std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
|
||||
return -EINVAL;
|
||||
|
|
@ -400,7 +402,7 @@ static int GetUUIDCmdHandler(int argc, char** argv) {
|
|||
|
||||
DeviceMapper& dm = DeviceMapper::Instance();
|
||||
std::string uuid;
|
||||
if (!dm.GetDmDeviceUUIDByName(argv[0], &uuid)) {
|
||||
if (!dm.GetDmDeviceUuidByName(argv[0], &uuid)) {
|
||||
std::cerr << "Could not query uuid of device \"" << argv[0] << "\"." << std::endl;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
@ -521,7 +523,7 @@ static std::map<std::string, std::function<int(int, char**)>> cmdmap = {
|
|||
{"list", DmListCmdHandler},
|
||||
{"help", HelpCmdHandler},
|
||||
{"getpath", GetPathCmdHandler},
|
||||
{"getuuid", GetUUIDCmdHandler},
|
||||
{"getuuid", GetUuidCmdHandler},
|
||||
{"info", InfoCmdHandler},
|
||||
{"table", TableCmdHandler},
|
||||
{"status", StatusCmdHandler},
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue