Loading fs_mgr/libdm/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ cc_defaults { "libbase", "liblog", ], header_libs: [ "libstorage_literals_headers", ], srcs: [":libdm_test_srcs"], auto_gen_config: true, require_root: true, Loading fs_mgr/libdm/dm.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -769,5 +769,25 @@ bool DeviceMapper::CreatePlaceholderDevice(const std::string& name) { return true; } bool DeviceMapper::SendMessage(const std::string& name, uint64_t sector, const std::string& message) { std::string ioctl_buffer(sizeof(struct dm_ioctl) + sizeof(struct dm_target_msg), 0); ioctl_buffer += message; ioctl_buffer.push_back('\0'); struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]); InitIo(io, name); io->data_size = ioctl_buffer.size(); io->data_start = sizeof(struct dm_ioctl); struct dm_target_msg* msg = reinterpret_cast<struct dm_target_msg*>(&ioctl_buffer[sizeof(struct dm_ioctl)]); msg->sector = sector; if (ioctl(fd_, DM_TARGET_MSG, io)) { PLOG(ERROR) << "DM_TARGET_MSG failed"; return false; } return true; } } // namespace dm } // namespace android fs_mgr/libdm/dm_target.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -298,5 +298,43 @@ std::string DmTargetUser::GetParameterString() const { return android::base::Join(argv, " "); } DmTargetThinPool::DmTargetThinPool(uint64_t start, uint64_t length, const std::string& metadata_dev, const std::string& data_dev, uint64_t data_block_size, uint64_t low_water_mark) : DmTarget(start, length), metadata_dev_(metadata_dev), data_dev_(data_dev), data_block_size_(data_block_size), low_water_mark_(low_water_mark) {} std::string DmTargetThinPool::GetParameterString() const { std::vector<std::string> args{ metadata_dev_, data_dev_, std::to_string(data_block_size_), std::to_string(low_water_mark_), }; return android::base::Join(args, " "); } bool DmTargetThinPool::Valid() const { // data_block_size: must be between 128 (64KB) and 2097152 (1GB) and a multiple of 128 (64KB) if (data_block_size_ < 128 || data_block_size_ > 2097152) return false; if (data_block_size_ % 128) return false; return true; } DmTargetThin::DmTargetThin(uint64_t start, uint64_t length, const std::string& pool_dev, uint64_t dev_id) : DmTarget(start, length), pool_dev_(pool_dev), dev_id_(dev_id) {} std::string DmTargetThin::GetParameterString() const { std::vector<std::string> args{ pool_dev_, std::to_string(dev_id_), }; return android::base::Join(args, " "); } } // namespace dm } // namespace android fs_mgr/libdm/dm_test.cpp +41 −0 Original line number Diff line number Diff line Loading @@ -37,12 +37,14 @@ #include <gtest/gtest.h> #include <libdm/dm.h> #include <libdm/loop_control.h> #include <storage_literals/storage_literals.h> #include "test_util.h" #include "utility.h" using namespace std; using namespace std::chrono_literals; using namespace android::dm; using namespace android::storage_literals; using android::base::make_scope_guard; using android::base::unique_fd; Loading Loading @@ -773,3 +775,42 @@ TEST_F(DmTest, GetNameAndUuid) { ASSERT_EQ(name, test_name_); ASSERT_FALSE(uuid.empty()); } TEST_F(DmTest, ThinProvisioning) { if (!DeviceMapper::Instance().GetTargetByName("thin-pool", nullptr)) GTEST_SKIP(); constexpr uint64_t MetaSize = 2_MiB; constexpr uint64_t DataSize = 64_MiB; constexpr uint64_t ThinSize = 1_TiB; // Prepare two loop devices for meta and data devices. TemporaryFile meta; ASSERT_GE(meta.fd, 0); ASSERT_EQ(0, ftruncate64(meta.fd, MetaSize)); TemporaryFile data; ASSERT_GE(data.fd, 0); ASSERT_EQ(0, ftruncate64(data.fd, DataSize)); LoopDevice loop_meta(meta.fd, 10s); ASSERT_TRUE(loop_meta.valid()); LoopDevice loop_data(data.fd, 10s); ASSERT_TRUE(loop_data.valid()); // Create a thin-pool DmTable poolTable; poolTable.Emplace<DmTargetThinPool>(0, DataSize / kSectorSize, loop_meta.device(), loop_data.device(), 128, 0); TempDevice pool("pool", poolTable); ASSERT_TRUE(pool.valid()); // Create a thin volume uint64_t thin_volume_id = 0; ASSERT_TRUE(DeviceMapper::Instance().SendMessage( "pool", 0, "create_thin " + std::to_string(thin_volume_id))); // Use a thin volume to create a 1T device DmTable thinTable; thinTable.Emplace<DmTargetThin>(0, ThinSize / kSectorSize, pool.path(), thin_volume_id); TempDevice thin("thin", thinTable); ASSERT_TRUE(thin.valid()); } fs_mgr/libdm/include/libdm/dm.h +3 −0 Original line number Diff line number Diff line Loading @@ -307,6 +307,9 @@ class DeviceMapper final : public IDeviceMapper { bool GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid); // Send |message| to target, pointed by |name| and |sector|. Use 0 if |sector| is not needed. bool SendMessage(const std::string& name, uint64_t sector, const std::string& message); private: // Maximum possible device mapper targets registered in the kernel. // This is only used to read the list of targets from kernel so we allocate Loading Loading
fs_mgr/libdm/Android.bp +3 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,9 @@ cc_defaults { "libbase", "liblog", ], header_libs: [ "libstorage_literals_headers", ], srcs: [":libdm_test_srcs"], auto_gen_config: true, require_root: true, Loading
fs_mgr/libdm/dm.cpp +20 −0 Original line number Diff line number Diff line Loading @@ -769,5 +769,25 @@ bool DeviceMapper::CreatePlaceholderDevice(const std::string& name) { return true; } bool DeviceMapper::SendMessage(const std::string& name, uint64_t sector, const std::string& message) { std::string ioctl_buffer(sizeof(struct dm_ioctl) + sizeof(struct dm_target_msg), 0); ioctl_buffer += message; ioctl_buffer.push_back('\0'); struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(&ioctl_buffer[0]); InitIo(io, name); io->data_size = ioctl_buffer.size(); io->data_start = sizeof(struct dm_ioctl); struct dm_target_msg* msg = reinterpret_cast<struct dm_target_msg*>(&ioctl_buffer[sizeof(struct dm_ioctl)]); msg->sector = sector; if (ioctl(fd_, DM_TARGET_MSG, io)) { PLOG(ERROR) << "DM_TARGET_MSG failed"; return false; } return true; } } // namespace dm } // namespace android
fs_mgr/libdm/dm_target.cpp +38 −0 Original line number Diff line number Diff line Loading @@ -298,5 +298,43 @@ std::string DmTargetUser::GetParameterString() const { return android::base::Join(argv, " "); } DmTargetThinPool::DmTargetThinPool(uint64_t start, uint64_t length, const std::string& metadata_dev, const std::string& data_dev, uint64_t data_block_size, uint64_t low_water_mark) : DmTarget(start, length), metadata_dev_(metadata_dev), data_dev_(data_dev), data_block_size_(data_block_size), low_water_mark_(low_water_mark) {} std::string DmTargetThinPool::GetParameterString() const { std::vector<std::string> args{ metadata_dev_, data_dev_, std::to_string(data_block_size_), std::to_string(low_water_mark_), }; return android::base::Join(args, " "); } bool DmTargetThinPool::Valid() const { // data_block_size: must be between 128 (64KB) and 2097152 (1GB) and a multiple of 128 (64KB) if (data_block_size_ < 128 || data_block_size_ > 2097152) return false; if (data_block_size_ % 128) return false; return true; } DmTargetThin::DmTargetThin(uint64_t start, uint64_t length, const std::string& pool_dev, uint64_t dev_id) : DmTarget(start, length), pool_dev_(pool_dev), dev_id_(dev_id) {} std::string DmTargetThin::GetParameterString() const { std::vector<std::string> args{ pool_dev_, std::to_string(dev_id_), }; return android::base::Join(args, " "); } } // namespace dm } // namespace android
fs_mgr/libdm/dm_test.cpp +41 −0 Original line number Diff line number Diff line Loading @@ -37,12 +37,14 @@ #include <gtest/gtest.h> #include <libdm/dm.h> #include <libdm/loop_control.h> #include <storage_literals/storage_literals.h> #include "test_util.h" #include "utility.h" using namespace std; using namespace std::chrono_literals; using namespace android::dm; using namespace android::storage_literals; using android::base::make_scope_guard; using android::base::unique_fd; Loading Loading @@ -773,3 +775,42 @@ TEST_F(DmTest, GetNameAndUuid) { ASSERT_EQ(name, test_name_); ASSERT_FALSE(uuid.empty()); } TEST_F(DmTest, ThinProvisioning) { if (!DeviceMapper::Instance().GetTargetByName("thin-pool", nullptr)) GTEST_SKIP(); constexpr uint64_t MetaSize = 2_MiB; constexpr uint64_t DataSize = 64_MiB; constexpr uint64_t ThinSize = 1_TiB; // Prepare two loop devices for meta and data devices. TemporaryFile meta; ASSERT_GE(meta.fd, 0); ASSERT_EQ(0, ftruncate64(meta.fd, MetaSize)); TemporaryFile data; ASSERT_GE(data.fd, 0); ASSERT_EQ(0, ftruncate64(data.fd, DataSize)); LoopDevice loop_meta(meta.fd, 10s); ASSERT_TRUE(loop_meta.valid()); LoopDevice loop_data(data.fd, 10s); ASSERT_TRUE(loop_data.valid()); // Create a thin-pool DmTable poolTable; poolTable.Emplace<DmTargetThinPool>(0, DataSize / kSectorSize, loop_meta.device(), loop_data.device(), 128, 0); TempDevice pool("pool", poolTable); ASSERT_TRUE(pool.valid()); // Create a thin volume uint64_t thin_volume_id = 0; ASSERT_TRUE(DeviceMapper::Instance().SendMessage( "pool", 0, "create_thin " + std::to_string(thin_volume_id))); // Use a thin volume to create a 1T device DmTable thinTable; thinTable.Emplace<DmTargetThin>(0, ThinSize / kSectorSize, pool.path(), thin_volume_id); TempDevice thin("thin", thinTable); ASSERT_TRUE(thin.valid()); }
fs_mgr/libdm/include/libdm/dm.h +3 −0 Original line number Diff line number Diff line Loading @@ -307,6 +307,9 @@ class DeviceMapper final : public IDeviceMapper { bool GetDeviceNameAndUuid(dev_t dev, std::string* name, std::string* uuid); // Send |message| to target, pointed by |name| and |sector|. Use 0 if |sector| is not needed. bool SendMessage(const std::string& name, uint64_t sector, const std::string& message); private: // Maximum possible device mapper targets registered in the kernel. // This is only used to read the list of targets from kernel so we allocate Loading