From bdc65bf0838c6602f493ab9226a379b70d841ddc Mon Sep 17 00:00:00 2001 From: Alessio Balsini Date: Mon, 29 Jul 2019 19:45:04 +0100 Subject: [PATCH] libdm: suspend and resume devices In some cases it would be required to suspend the device to succesfully complete some operations. An example is the suspension of the origin device that is necessary to avoid data corruption when merging a snapshot. Introduce suspend and resume ioctls in libdm. Bug: 137759376 Test: libdm_test Change-Id: Id2ff34e930a8b32e570cb9f49da9cc3f65cb499c Signed-off-by: Alessio Balsini --- fs_mgr/libdm/dm.cpp | 18 ++++++++++++++++++ fs_mgr/libdm/dm_test.cpp | 28 ++++++++++++++++++++++++++++ fs_mgr/libdm/include/libdm/dm.h | 5 +++++ 3 files changed, 51 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index 0ad8d9db0..1d2683a54 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -162,6 +162,24 @@ DmDeviceState DeviceMapper::GetState(const std::string& name) const { return DmDeviceState::SUSPENDED; } +bool DeviceMapper::ChangeState(const std::string& name, DmDeviceState state) { + if (state != DmDeviceState::SUSPENDED && state != DmDeviceState::ACTIVE) { + return false; + } + + struct dm_ioctl io; + InitIo(&io, name); + + if (state == DmDeviceState::SUSPENDED) io.flags = DM_SUSPEND_FLAG; + + if (ioctl(fd_, DM_DEV_SUSPEND, &io) < 0) { + PLOG(ERROR) << "DM_DEV_SUSPEND " + << (state == DmDeviceState::SUSPENDED ? "suspend" : "resume") << " failed"; + return false; + } + return true; +} + bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table) { std::string ignore_path; if (!CreateDevice(name, table, &ignore_path, 0ms)) { diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index b28a8f2e9..da1c4a9b0 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -166,6 +166,34 @@ TEST(libdm, DmLinear) { ASSERT_TRUE(dev.Destroy()); } +TEST(libdm, DmSuspendResume) { + unique_fd tmp1(CreateTempFile("file_suspend_resume", 512)); + ASSERT_GE(tmp1, 0); + + LoopDevice loop_a(tmp1, 10s); + ASSERT_TRUE(loop_a.valid()); + + DmTable table; + ASSERT_TRUE(table.Emplace(0, 1, loop_a.device(), 0)); + ASSERT_TRUE(table.valid()); + + TempDevice dev("libdm-test-dm-suspend-resume", table); + ASSERT_TRUE(dev.valid()); + ASSERT_FALSE(dev.path().empty()); + + auto& dm = DeviceMapper::Instance(); + + // Test Set and Get status of device. + vector targets; + ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::ACTIVE); + + ASSERT_TRUE(dm.ChangeState(dev.name(), DmDeviceState::SUSPENDED)); + ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::SUSPENDED); + + ASSERT_TRUE(dm.ChangeState(dev.name(), DmDeviceState::ACTIVE)); + ASSERT_EQ(dm.GetState(dev.name()), DmDeviceState::ACTIVE); +} + TEST(libdm, DmVerityArgsAvb2) { std::string device = "/dev/block/platform/soc/1da4000.ufshc/by-name/vendor_a"; std::string algorithm = "sha1"; diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h index 9c0c2f30f..753b8c97d 100644 --- a/fs_mgr/libdm/include/libdm/dm.h +++ b/fs_mgr/libdm/include/libdm/dm.h @@ -79,6 +79,11 @@ class DeviceMapper final { // One of INVALID, SUSPENDED or ACTIVE. DmDeviceState GetState(const std::string& name) const; + // Puts the given device to the specified status, which must be either: + // - SUSPENDED: suspend the device, or + // - ACTIVE: resumes the device. + bool ChangeState(const std::string& name, DmDeviceState state); + // Creates a device, loads the given table, and activates it. If the device // is not able to be activated, it is destroyed, and false is returned. // After creation, |path| contains the result of calling