diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index 9a2910e2c..c2f732ba1 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -39,14 +40,69 @@ DeviceMapper& DeviceMapper::Instance() { return instance; } // Creates a new device mapper device -bool DeviceMapper::CreateDevice(const std::string& /* name */) { +bool DeviceMapper::CreateDevice(const std::string& name) { + if (name.empty()) { + LOG(ERROR) << "Unnamed device mapper device creation is not supported"; + return false; + } + + if (name.size() >= DM_NAME_LEN) { + LOG(ERROR) << "[" << name << "] is too long to be device mapper name"; + return false; + } + + std::unique_ptr io( + static_cast(malloc(sizeof(struct dm_ioctl))), free); + if (io == nullptr) { + LOG(ERROR) << "Failed to allocate dm_ioctl"; + return false; + } + InitIo(io.get(), name); + + if (ioctl(fd_, DM_DEV_CREATE, io.get())) { + PLOG(ERROR) << "DM_DEV_CREATE failed to create [" << name << "]"; + return false; + } + + // Check to make sure the newly created device doesn't already have targets + // added or opened by someone + CHECK(io->target_count == 0) << "Unexpected targets for newly created [" << name << "] device"; + CHECK(io->open_count == 0) << "Unexpected opens for newly created [" << name << "] device"; + // Creates a new device mapper device with the name passed in - return false; + return true; } -bool DeviceMapper::DeleteDevice(const std::string& /* name */) { - // Destroy device here first - return false; +bool DeviceMapper::DeleteDevice(const std::string& name) { + if (name.empty()) { + LOG(ERROR) << "Unnamed device mapper device creation is not supported"; + return false; + } + + if (name.size() >= DM_NAME_LEN) { + LOG(ERROR) << "[" << name << "] is too long to be device mapper name"; + return false; + } + + std::unique_ptr io( + static_cast(malloc(sizeof(struct dm_ioctl))), free); + if (io == nullptr) { + LOG(ERROR) << "Failed to allocate dm_ioctl"; + return false; + } + InitIo(io.get(), name); + + if (ioctl(fd_, DM_DEV_REMOVE, io.get())) { + PLOG(ERROR) << "DM_DEV_REMOVE failed to create [" << name << "]"; + return false; + } + + // Check to make sure appropriate uevent is generated so ueventd will + // do the right thing and remove the corresponding device node and symlinks. + CHECK(io->flags & DM_UEVENT_GENERATED_FLAG) + << "Didn't generate uevent for [" << name << "] removal"; + + return true; } const std::unique_ptr DeviceMapper::table(const std::string& /* name */) const { @@ -82,12 +138,13 @@ bool DeviceMapper::GetAvailableTargets(std::vector* targets) { return false; } + // Sets appropriate data size and data_start to make sure we tell kernel + // about the total size of the buffer we are passing and where to start + // writing the list of targets. struct dm_ioctl* io = reinterpret_cast(buffer.get()); - io->data_start = sizeof(*io); + InitIo(io); io->data_size = data_size; - io->version[0] = 4; - io->version[1] = 0; - io->version[2] = 0; + io->data_start = sizeof(*io); if (ioctl(fd_, DM_LIST_VERSIONS, io)) { PLOG(ERROR) << "Failed to get DM_LIST_VERSIONS from kernel"; @@ -131,5 +188,20 @@ std::string DeviceMapper::GetDmDevicePathByName(const std::string& /* name */) { return ""; } +// private methods of DeviceMapper +void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const { + CHECK(io != nullptr) << "nullptr passed to dm_ioctl initialization"; + memset(io, 0, sizeof(*io)); + + io->version[0] = DM_VERSION0; + io->version[1] = DM_VERSION1; + io->version[2] = DM_VERSION2; + io->data_size = sizeof(*io); + io->data_start = 0; + if (!name.empty()) { + strlcpy(io->name, name.c_str(), sizeof(io->name)); + } +} + } // namespace dm } // namespace android diff --git a/fs_mgr/libdm/include/dm.h b/fs_mgr/libdm/include/dm.h index 0cd0149bc..d839393ac 100644 --- a/fs_mgr/libdm/include/dm.h +++ b/fs_mgr/libdm/include/dm.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -27,6 +28,11 @@ #include +// The minimum expected device mapper major.minor version +#define DM_VERSION0 (4) +#define DM_VERSION1 (0) +#define DM_VERSION2 (0) + #define DM_ALIGN_MASK (7) #define DM_ALIGN(x) ((x + DM_ALIGN_MASK) & ~DM_ALIGN_MASK) @@ -87,6 +93,8 @@ class DeviceMapper final { // a finite amount of memory. This limit is in no way enforced by the kernel. static constexpr uint32_t kMaxPossibleDmTargets = 256; + void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const; + DeviceMapper() : fd_(-1) { fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC)); if (fd_ < 0) { diff --git a/fs_mgr/tools/dmctl.cpp b/fs_mgr/tools/dmctl.cpp index 27e2a5825..c12383011 100644 --- a/fs_mgr/tools/dmctl.cpp +++ b/fs_mgr/tools/dmctl.cpp @@ -39,50 +39,46 @@ using DmTarget = ::android::dm::DmTarget; static int Usage(void) { std::cerr << "usage: dmctl [command options]"; std::cerr << "commands:"; - std::cerr << " create [-lo ] "; - std::cerr, " delete "; + std::cerr << " create [dm-target> [-lo ] ]"; + std::cerr, " delete "; std::cerr, " list"; std::cerr, " help"; return -EINVAL; } static int DmCreateCmdHandler(int argc, char** argv) { - if (argc <= 1) { - std::cerr << "DmCreateCmdHandler: Invalid arguments"; - if (argc > 0) std::cerr << " args: " << argv[0]; + if (argc < 1) { + std::cerr << "DmCreateCmdHandler: atleast 'name' MUST be provided for target device"; return -EINVAL; } - // Parse Everything first to make sure we have everything we need. - std::string devname = argv[0]; + std::string name = argv[0]; DeviceMapper& dm = DeviceMapper::Instance(); - std::vector targets; - if (!dm.GetAvailableTargets(&targets)) { - std::cerr << "Failed to read available device mapper targets"; - return -errno; + if (!dm.CreateDevice(name)) { + std::cerr << "DmCreateCmdHandler: Failed to create " << name << " device"; + return -EIO; } - if (targets.empty()) { - std::cerr << "zero device mapper targets available"; - return -EEXIST; + // if we also have target specified + if (argc > 1) { + // fall through for now. This will eventually create a DmTarget() based on the target name + // passing it the table that is specified at the command line } - for (const auto& target : targets) { - if (target.name() == argv[1]) { - // TODO(b/110035986) : Create the target here, return success for now. - return 0; - } - } - - std::cerr << "Invalid or non-existing target : " << argv[1]; - return -EINVAL; + return 0; } static int DmDeleteCmdHandler(int argc, char** argv) { - std::cout << "DmDeleteCmdHandler:" << std::endl; - std::cout << " args:" << std::endl; - for (int i = 0; i < argc; i++) { - std::cout << " " << argv[i] << std::endl; + if (argc < 1) { + std::cerr << "DmCreateCmdHandler: atleast 'name' MUST be provided for target device"; + return -EINVAL; + } + + std::string name = argv[0]; + DeviceMapper& dm = DeviceMapper::Instance(); + if (!dm.DeleteDevice(name)) { + std::cerr << "DmCreateCmdHandler: Failed to create " << name << " device"; + return -EIO; } return 0; @@ -94,7 +90,7 @@ static int DmListCmdHandler(int /* argc */, char** /* argv */) { DeviceMapper& dm = DeviceMapper::Instance(); std::vector targets; if (!dm.GetAvailableTargets(&targets)) { - std::cerr << "Failed to read available device mapper targets"; + std::cerr << "Failed to read available device mapper targets" << std::endl; return -errno; }