fs_mgr: libdm: Add support to list existing device mapper devices
Test: dmctl create system; dmctl list devices; dmctl delete system; dmctl list devices Bug: 110035986 Change-Id: I4ae5d40041458421068976fa2a99c662c542a9a1 Signed-off-by: Sandeep Patil <sspatil@google.com>
This commit is contained in:
parent
45d94ab683
commit
f603cfdd70
|
@ -182,6 +182,69 @@ bool DeviceMapper::GetAvailableTargets(std::vector<DmTarget>* targets) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool DeviceMapper::GetAvailableDevices(std::vector<DmBlockDevice>* devices) {
|
||||
devices->clear();
|
||||
|
||||
// calculate the space needed to read a maximum of 256 targets, each with
|
||||
// name with maximum length of 16 bytes
|
||||
uint32_t payload_size = sizeof(struct dm_name_list);
|
||||
// 128-bytes for the name
|
||||
payload_size += DM_NAME_LEN;
|
||||
// dm wants every device spec to be aligned at 8-byte boundary
|
||||
payload_size = DM_ALIGN(payload_size);
|
||||
payload_size *= kMaxPossibleDmDevices;
|
||||
uint32_t data_size = sizeof(struct dm_ioctl) + payload_size;
|
||||
auto buffer = std::unique_ptr<void, void (*)(void*)>(calloc(1, data_size), free);
|
||||
if (buffer == nullptr) {
|
||||
LOG(ERROR) << "failed to allocate memory";
|
||||
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());
|
||||
InitIo(io);
|
||||
io->data_size = data_size;
|
||||
io->data_start = sizeof(*io);
|
||||
|
||||
if (ioctl(fd_, DM_LIST_DEVICES, io)) {
|
||||
PLOG(ERROR) << "Failed to get DM_LIST_DEVICES from kernel";
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the provided buffer wasn't enough to list all devices any data
|
||||
// beyond sizeof(*io) must not be read.
|
||||
if (io->flags & DM_BUFFER_FULL_FLAG) {
|
||||
LOG(INFO) << data_size << " is not enough memory to list all dm devices";
|
||||
return false;
|
||||
}
|
||||
|
||||
// if there are no devices created yet, return success with empty vector
|
||||
if (io->data_size == sizeof(*io)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse each device and add a new DmBlockDevice to the vector
|
||||
// created from the kernel data.
|
||||
uint32_t next = sizeof(*io);
|
||||
data_size = io->data_size - next;
|
||||
struct dm_name_list* dm_dev =
|
||||
reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
|
||||
|
||||
while (next && data_size) {
|
||||
devices->emplace_back((dm_dev));
|
||||
if (dm_dev->next == 0) {
|
||||
break;
|
||||
}
|
||||
next += dm_dev->next;
|
||||
data_size -= dm_dev->next;
|
||||
dm_dev = reinterpret_cast<struct dm_name_list*>(static_cast<char*>(buffer.get()) + next);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Accepts a device mapper device name (like system_a, vendor_b etc) and
|
||||
// returns the path to it's device node (or symlink to the device node)
|
||||
std::string DeviceMapper::GetDmDevicePathByName(const std::string& /* name */) {
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <linux/kdev_t.h>
|
||||
#include <sys/sysmacros.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
|
@ -43,6 +45,28 @@ enum class DmDeviceState { INVALID, SUSPENDED, ACTIVE };
|
|||
|
||||
class DeviceMapper final {
|
||||
public:
|
||||
class DmBlockDevice final {
|
||||
public:
|
||||
// only allow creating this with dm_name_list
|
||||
DmBlockDevice() = delete;
|
||||
|
||||
explicit DmBlockDevice(struct dm_name_list* d) : name_(d->name), dev_(d->dev){};
|
||||
|
||||
// Returs device mapper name associated with the block device
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
// Return major number for the block device
|
||||
uint32_t Major() const { return major(dev_); }
|
||||
|
||||
// Return minor number for the block device
|
||||
uint32_t Minor() const { return minor(dev_); }
|
||||
~DmBlockDevice() = default;
|
||||
|
||||
private:
|
||||
std::string name_;
|
||||
uint64_t dev_;
|
||||
};
|
||||
|
||||
// Creates a device mapper device with given name.
|
||||
// Return 'true' on success and 'false' on failure to
|
||||
// create OR if a device mapper device with the same name already
|
||||
|
@ -74,6 +98,12 @@ class DeviceMapper final {
|
|||
// successfully read and stored in 'targets'. Returns 'false' otherwise.
|
||||
bool GetAvailableTargets(std::vector<DmTarget>* targets);
|
||||
|
||||
// Return 'true' if it can successfully read the list of device mapper block devices
|
||||
// currently created. 'devices' will be empty if the kernel interactions
|
||||
// were successful and there are no block devices at the moment. Returns
|
||||
// 'false' in case of any failure along the way.
|
||||
bool GetAvailableDevices(std::vector<DmBlockDevice>* devices);
|
||||
|
||||
// Returns the path to the device mapper device node in '/dev' corresponding to
|
||||
// 'name'.
|
||||
std::string GetDmDevicePathByName(const std::string& name);
|
||||
|
@ -93,6 +123,12 @@ class DeviceMapper final {
|
|||
// a finite amount of memory. This limit is in no way enforced by the kernel.
|
||||
static constexpr uint32_t kMaxPossibleDmTargets = 256;
|
||||
|
||||
// Maximum possible device mapper created block devices. Note that this is restricted by
|
||||
// the minor numbers (that used to be 8 bits) that can be range from 0 to 2^20-1 in newer
|
||||
// kernels. In Android systems however, we never expect these to grow beyond the artificial
|
||||
// limit we are imposing here of 256.
|
||||
static constexpr uint32_t kMaxPossibleDmDevices = 256;
|
||||
|
||||
void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
|
||||
|
||||
DeviceMapper() : fd_(-1) {
|
||||
|
|
|
@ -35,13 +35,14 @@
|
|||
|
||||
using DeviceMapper = ::android::dm::DeviceMapper;
|
||||
using DmTarget = ::android::dm::DmTarget;
|
||||
using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
|
||||
|
||||
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-name>";
|
||||
std::cerr, " list";
|
||||
std::cerr, " list <devices | targets>";
|
||||
std::cerr, " help";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
@ -84,16 +85,14 @@ static int DmDeleteCmdHandler(int argc, char** argv) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int DmListCmdHandler(int /* argc */, char** /* argv */) {
|
||||
std::cout << "Available Device Mapper Targets:" << std::endl;
|
||||
|
||||
DeviceMapper& dm = DeviceMapper::Instance();
|
||||
static int DmListTargets(DeviceMapper& dm) {
|
||||
std::vector<DmTarget> targets;
|
||||
if (!dm.GetAvailableTargets(&targets)) {
|
||||
std::cerr << "Failed to read available device mapper targets" << std::endl;
|
||||
return -errno;
|
||||
}
|
||||
|
||||
std::cout << "Available Device Mapper Targets:" << std::endl;
|
||||
if (targets.empty()) {
|
||||
std::cout << " <empty>" << std::endl;
|
||||
return 0;
|
||||
|
@ -107,6 +106,46 @@ static int DmListCmdHandler(int /* argc */, char** /* argv */) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int DmListDevices(DeviceMapper& dm) {
|
||||
std::vector<DmBlockDevice> devices;
|
||||
if (!dm.GetAvailableDevices(&devices)) {
|
||||
std::cerr << "Failed to read available device mapper devices" << std::endl;
|
||||
return -errno;
|
||||
}
|
||||
std::cout << "Available Device Mapper Devices:" << std::endl;
|
||||
if (devices.empty()) {
|
||||
std::cout << " <empty>" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (const auto& dev : devices) {
|
||||
std::cout << std::left << std::setw(20) << dev.name() << " : " << dev.Major() << ":"
|
||||
<< dev.Minor() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const std::map<std::string, std::function<int(DeviceMapper&)>> listmap = {
|
||||
{"targets", DmListTargets},
|
||||
{"devices", DmListDevices},
|
||||
};
|
||||
|
||||
static int DmListCmdHandler(int argc, char** argv) {
|
||||
if (argc < 1) {
|
||||
std::cerr << "Invalid arguments, see \'dmctl help\'" << std::endl;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
DeviceMapper& dm = DeviceMapper::Instance();
|
||||
for (const auto& l : listmap) {
|
||||
if (l.first == argv[0]) return l.second(dm);
|
||||
}
|
||||
|
||||
std::cerr << "Invalid argument to \'dmctl list\': " << argv[0] << std::endl;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int HelpCmdHandler(int /* argc */, char** /* argv */) {
|
||||
Usage();
|
||||
return 0;
|
||||
|
|
Loading…
Reference in New Issue