summaryrefslogtreecommitdiffstats
path: root/fs_mgr/libdm
diff options
context:
space:
mode:
authorSandeep Patil <sspatil@google.com>2018-06-13 12:09:58 -0700
committerSandeep Patil <sspatil@google.com>2018-06-13 13:50:21 -0700
commitf603cfdd70ddd961218834a95012c327b85ee4c8 (patch)
tree37c8d62d22941e4baf4c0ddc02f38fc824a17998 /fs_mgr/libdm
parent45d94ab683d88a2d0532b382cffb9ce0c7b5444f (diff)
downloadsystem_core-f603cfdd70ddd961218834a95012c327b85ee4c8.tar.gz
system_core-f603cfdd70ddd961218834a95012c327b85ee4c8.tar.bz2
system_core-f603cfdd70ddd961218834a95012c327b85ee4c8.zip
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>
Diffstat (limited to 'fs_mgr/libdm')
-rw-r--r--fs_mgr/libdm/dm.cpp63
-rw-r--r--fs_mgr/libdm/include/dm.h36
2 files changed, 99 insertions, 0 deletions
diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp
index c2f732ba1..57c127081 100644
--- a/fs_mgr/libdm/dm.cpp
+++ b/fs_mgr/libdm/dm.cpp
@@ -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 */) {
diff --git a/fs_mgr/libdm/include/dm.h b/fs_mgr/libdm/include/dm.h
index d839393ac..52a9a111a 100644
--- a/fs_mgr/libdm/include/dm.h
+++ b/fs_mgr/libdm/include/dm.h
@@ -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) {