Loading fs_mgr/libdm/dm.cpp +25 −7 Original line number Diff line number Diff line Loading @@ -170,19 +170,18 @@ static bool IsRecovery() { return access("/system/bin/recovery", F_OK) == 0; } bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path, const std::chrono::milliseconds& timeout_ms) { bool DeviceMapper::CreateEmptyDevice(const std::string& name) { std::string uuid = GenerateUuid(); if (!CreateDevice(name, uuid)) { return false; return CreateDevice(name, uuid); } bool DeviceMapper::WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms, std::string* path) { // We use the unique path for testing whether the device is ready. After // that, it's safe to use the dm-N path which is compatible with callers // that expect it to be formatted as such. std::string unique_path; if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) { if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) { DeleteDevice(name); return false; } Loading @@ -208,6 +207,25 @@ bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, s return true; } bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path, const std::chrono::milliseconds& timeout_ms) { if (!CreateEmptyDevice(name)) { return false; } if (!LoadTableAndActivate(name, table)) { DeleteDevice(name); return false; } if (!WaitForDevice(name, timeout_ms, path)) { DeleteDevice(name); return false; } return true; } bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) { struct dm_ioctl io; InitIo(&io, name); Loading fs_mgr/libdm/dm_test.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <thread> #include <android-base/file.h> #include <android-base/scopeguard.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <gtest/gtest.h> Loading Loading @@ -679,3 +680,17 @@ TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) { ASSERT_NE(0, access(path.c_str(), F_OK)); ASSERT_EQ(ENOENT, errno); } TEST(libdm, CreateEmptyDevice) { DeviceMapper& dm = DeviceMapper::Instance(); ASSERT_TRUE(dm.CreateEmptyDevice("empty-device")); auto guard = android::base::make_scope_guard([&]() { dm.DeleteDevice("empty-device", 5s); }); // Empty device should be in suspended state. ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); std::string path; ASSERT_TRUE(dm.WaitForDevice("empty-device", 5s, &path)); // Path should exist. ASSERT_EQ(0, access(path.c_str(), F_OK)); } fs_mgr/libdm/include/libdm/dm.h +13 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,19 @@ class DeviceMapper final { // - ACTIVE: resumes the device. bool ChangeState(const std::string& name, DmDeviceState state); // Creates empty device. // This supports a use case when a caller doesn't need a device straight away, but instead // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd // to create user space paths. // Callers are expected to then activate their device by calling LoadTableAndActivate function. // To avoid race conditions, callers must still synchronize with ueventd by calling // WaitForDevice function. bool CreateEmptyDevice(const std::string& name); // Waits for device paths to be created in the user space. bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms, std::string* path); // 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 Loading Loading
fs_mgr/libdm/dm.cpp +25 −7 Original line number Diff line number Diff line Loading @@ -170,19 +170,18 @@ static bool IsRecovery() { return access("/system/bin/recovery", F_OK) == 0; } bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path, const std::chrono::milliseconds& timeout_ms) { bool DeviceMapper::CreateEmptyDevice(const std::string& name) { std::string uuid = GenerateUuid(); if (!CreateDevice(name, uuid)) { return false; return CreateDevice(name, uuid); } bool DeviceMapper::WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms, std::string* path) { // We use the unique path for testing whether the device is ready. After // that, it's safe to use the dm-N path which is compatible with callers // that expect it to be formatted as such. std::string unique_path; if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) { if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) { DeleteDevice(name); return false; } Loading @@ -208,6 +207,25 @@ bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, s return true; } bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path, const std::chrono::milliseconds& timeout_ms) { if (!CreateEmptyDevice(name)) { return false; } if (!LoadTableAndActivate(name, table)) { DeleteDevice(name); return false; } if (!WaitForDevice(name, timeout_ms, path)) { DeleteDevice(name); return false; } return true; } bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) { struct dm_ioctl io; InitIo(&io, name); Loading
fs_mgr/libdm/dm_test.cpp +15 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,7 @@ #include <thread> #include <android-base/file.h> #include <android-base/scopeguard.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <gtest/gtest.h> Loading Loading @@ -679,3 +680,17 @@ TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) { ASSERT_NE(0, access(path.c_str(), F_OK)); ASSERT_EQ(ENOENT, errno); } TEST(libdm, CreateEmptyDevice) { DeviceMapper& dm = DeviceMapper::Instance(); ASSERT_TRUE(dm.CreateEmptyDevice("empty-device")); auto guard = android::base::make_scope_guard([&]() { dm.DeleteDevice("empty-device", 5s); }); // Empty device should be in suspended state. ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); std::string path; ASSERT_TRUE(dm.WaitForDevice("empty-device", 5s, &path)); // Path should exist. ASSERT_EQ(0, access(path.c_str(), F_OK)); }
fs_mgr/libdm/include/libdm/dm.h +13 −0 Original line number Diff line number Diff line Loading @@ -115,6 +115,19 @@ class DeviceMapper final { // - ACTIVE: resumes the device. bool ChangeState(const std::string& name, DmDeviceState state); // Creates empty device. // This supports a use case when a caller doesn't need a device straight away, but instead // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd // to create user space paths. // Callers are expected to then activate their device by calling LoadTableAndActivate function. // To avoid race conditions, callers must still synchronize with ueventd by calling // WaitForDevice function. bool CreateEmptyDevice(const std::string& name); // Waits for device paths to be created in the user space. bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms, std::string* path); // 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 Loading