fs_mgr: libdm: add support to create and delete device mapper devices.
Test: dmctl create system; dmctl delete system Test: verify that ueventd creates /dev/block/dm-X and verify the dm device name from /sys/block/dm-X/dm/name Bug: 110035986 Change-Id: I2a08e2ea7007c0c13fe64d444f0d6618784edae7 Signed-off-by: Sandeep Patil <sspatil@google.com>
This commit is contained in:
parent
59f04ee74c
commit
45d94ab683
|
@ -22,6 +22,7 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
@ -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<struct dm_ioctl, decltype(&free)> io(
|
||||
static_cast<struct dm_ioctl*>(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<struct dm_ioctl, decltype(&free)> io(
|
||||
static_cast<struct dm_ioctl*>(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<DmTable> DeviceMapper::table(const std::string& /* name */) const {
|
||||
|
@ -82,12 +138,13 @@ bool DeviceMapper::GetAvailableTargets(std::vector<DmTarget>* 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<struct dm_ioctl*>(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
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
|
@ -27,6 +28,11 @@
|
|||
|
||||
#include <dm_table.h>
|
||||
|
||||
// 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) {
|
||||
|
|
|
@ -39,50 +39,46 @@ using DmTarget = ::android::dm::DmTarget;
|
|||
static int Usage(void) {
|
||||
std::cerr << "usage: dmctl <command> [command options]";
|
||||
std::cerr << "commands:";
|
||||
std::cerr << " create <dm-name> <dm-target> [-lo <filename>] <dm-target-args>";
|
||||
std::cerr, " delete <dm-device>";
|
||||
std::cerr << " create <dm-name> [dm-target> [-lo <filename>] <dm-target-args>]";
|
||||
std::cerr, " delete <dm-name>";
|
||||
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<DmTarget> 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<DmTarget> 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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue