dmctl: Add verbose 'dmctl list devices'

This adds an option to list device mapper devices including their
current target table. Useful to be included in bugreport to
map the logical partitions metadata with actual device mapper setup.

Bug: 120916687
Test: dmctl list devices -v

Change-Id: I091666506d24372d1e111ffa1c0256c8bbff0c5e
Signed-off-by: Sandeep Patil <sspatil@google.com>
This commit is contained in:
Sandeep Patil 2018-12-18 09:36:53 -08:00
parent 958a669e58
commit 2d04ce3b5a
3 changed files with 49 additions and 7 deletions

View file

@ -203,7 +203,8 @@ bool DeviceMapper::GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets) {
}
next += vers->next;
data_size -= vers->next;
vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) +
next);
}
return true;
@ -288,12 +289,23 @@ bool DeviceMapper::GetDmDevicePathByName(const std::string& name, std::string* p
}
bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInfo>* table) {
return GetTable(name, 0, table);
}
bool DeviceMapper::GetTableInfo(const std::string& name, std::vector<TargetInfo>* table) {
return GetTable(name, DM_STATUS_TABLE_FLAG, table);
}
// private methods of DeviceMapper
bool DeviceMapper::GetTable(const std::string& name, uint32_t flags,
std::vector<TargetInfo>* table) {
char buffer[4096];
struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer);
InitIo(io, name);
io->data_size = sizeof(buffer);
io->data_start = sizeof(*io);
io->flags = flags;
if (ioctl(fd_, DM_TABLE_STATUS, io) < 0) {
PLOG(ERROR) << "DM_TABLE_STATUS failed for " << name;
return false;
@ -327,7 +339,6 @@ bool DeviceMapper::GetTableStatus(const std::string& name, std::vector<TargetInf
return true;
}
// 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));

View file

@ -128,6 +128,10 @@ class DeviceMapper final {
};
bool GetTableStatus(const std::string& name, std::vector<TargetInfo>* table);
// Identical to GetTableStatus, except also retrives the active table for the device
// mapper device from the kernel.
bool GetTableInfo(const std::string& name, std::vector<TargetInfo>* table);
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
@ -140,6 +144,8 @@ class DeviceMapper final {
// limit we are imposing here of 256.
static constexpr uint32_t kMaxPossibleDmDevices = 256;
bool GetTable(const std::string& name, uint32_t flags, std::vector<TargetInfo>* table);
void InitIo(struct dm_ioctl* io, const std::string& name = std::string()) const;
DeviceMapper();

View file

@ -36,6 +36,8 @@
#include <string>
#include <vector>
using namespace std::literals::string_literals;
using DeviceMapper = ::android::dm::DeviceMapper;
using DmTable = ::android::dm::DmTable;
using DmTarget = ::android::dm::DmTarget;
@ -51,7 +53,7 @@ static int Usage(void) {
std::cerr << "commands:" << std::endl;
std::cerr << " create <dm-name> [-ro] <targets...>" << std::endl;
std::cerr << " delete <dm-name>" << std::endl;
std::cerr << " list <devices | targets>" << std::endl;
std::cerr << " list <devices | targets> [-v]" << std::endl;
std::cerr << " getpath <dm-name>" << std::endl;
std::cerr << " table <dm-name>" << std::endl;
std::cerr << " help" << std::endl;
@ -197,7 +199,8 @@ static int DmDeleteCmdHandler(int argc, char** argv) {
return 0;
}
static int DmListTargets(DeviceMapper& dm) {
static int DmListTargets(DeviceMapper& dm, [[maybe_unused]] int argc,
[[maybe_unused]] char** argv) {
std::vector<DmTargetTypeInfo> targets;
if (!dm.GetAvailableTargets(&targets)) {
std::cerr << "Failed to read available device mapper targets" << std::endl;
@ -218,7 +221,7 @@ static int DmListTargets(DeviceMapper& dm) {
return 0;
}
static int DmListDevices(DeviceMapper& dm) {
static int DmListDevices(DeviceMapper& dm, int argc, char** argv) {
std::vector<DmBlockDevice> devices;
if (!dm.GetAvailableDevices(&devices)) {
std::cerr << "Failed to read available device mapper devices" << std::endl;
@ -230,15 +233,37 @@ static int DmListDevices(DeviceMapper& dm) {
return 0;
}
bool verbose = (argc && (argv[0] == "-v"s));
for (const auto& dev : devices) {
std::cout << std::left << std::setw(20) << dev.name() << " : " << dev.Major() << ":"
<< dev.Minor() << std::endl;
if (verbose) {
std::vector<DeviceMapper::TargetInfo> table;
if (!dm.GetTableInfo(dev.name(), &table)) {
std::cerr << "Could not query table status for device \"" << dev.name() << "\"."
<< std::endl;
return -EINVAL;
}
uint32_t target_num = 1;
for (const auto& target : table) {
std::cout << " target#" << target_num << ": ";
std::cout << target.spec.sector_start << "-"
<< (target.spec.sector_start + target.spec.length) << ": "
<< target.spec.target_type;
if (!target.data.empty()) {
std::cout << ", " << target.data;
}
std::cout << std::endl;
target_num++;
}
}
}
return 0;
}
static const std::map<std::string, std::function<int(DeviceMapper&)>> listmap = {
static const std::map<std::string, std::function<int(DeviceMapper&, int, char**)>> listmap = {
{"targets", DmListTargets},
{"devices", DmListDevices},
};
@ -251,7 +276,7 @@ static int DmListCmdHandler(int argc, char** argv) {
DeviceMapper& dm = DeviceMapper::Instance();
for (const auto& l : listmap) {
if (l.first == argv[0]) return l.second(dm);
if (l.first == argv[0]) return l.second(dm, argc - 1, argv + 1);
}
std::cerr << "Invalid argument to \'dmctl list\': " << argv[0] << std::endl;