libdm: Add DmTargetTypeInfo and a unit test.

This change refactors DmTarget. It was satisfying two separate use cases
that have no overlap: (1) as a container for informational queries, and
(2) for specifying table targets.

The kernel's nomenclature for the former is a "target type," so the new
class is named DmTargetTypeInfo.

In addition, this change adds a unit test for
DeviceMapper::GetAvailableTargets that ensures the device has at least a
linear target type (with more TBD).

Bug: 110035986
Test: libdm_test gtest
Change-Id: Icb87976801e8a1e6ec79e48b1d58c308d36279e5
This commit is contained in:
David Anderson 2018-06-20 13:15:31 -07:00
parent d41a1f9add
commit c7def6849a
6 changed files with 83 additions and 27 deletions

View file

@ -16,6 +16,7 @@
cc_library_static {
name: "libdm",
defaults: ["fs_mgr_defaults"],
recovery_available: true,
export_include_dirs: ["include"],
@ -35,3 +36,16 @@ cc_library_static {
"liblog_headers",
],
}
cc_test {
name: "libdm_test",
defaults: ["fs_mgr_defaults"],
static_libs: [
"libdm",
"libbase",
"liblog",
],
srcs: [
"dm_test.cpp",
]
}

View file

@ -129,7 +129,7 @@ bool DeviceMapper::LoadTableAndActivate(const std::string& name, const DmTable&
// Reads all the available device mapper targets and their corresponding
// versions from the kernel and returns in a vector
bool DeviceMapper::GetAvailableTargets(std::vector<DmTarget>* targets) {
bool DeviceMapper::GetAvailableTargets(std::vector<DmTargetTypeInfo>* targets) {
targets->clear();
// calculate the space needed to read a maximum of kMaxPossibleDmTargets
@ -178,7 +178,7 @@ bool DeviceMapper::GetAvailableTargets(std::vector<DmTarget>* targets) {
struct dm_target_versions* vers =
reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
while (next && data_size) {
targets->emplace_back((vers));
targets->emplace_back(vers);
if (vers->next == 0) {
break;
}

37
fs_mgr/libdm/dm_test.cpp Normal file
View file

@ -0,0 +1,37 @@
/*
* Copyright (C) 2018 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <map>
#include <gtest/gtest.h>
#include <libdm/dm.h>
using namespace std;
using namespace android::dm;
TEST(libdm, HasMinimumTargets) {
DeviceMapper& dm = DeviceMapper::Instance();
vector<DmTargetTypeInfo> targets;
ASSERT_TRUE(dm.GetAvailableTargets(&targets));
map<string, DmTargetTypeInfo> by_name;
for (const auto& target : targets) {
by_name[target.name()] = target;
}
auto iter = by_name.find("linear");
EXPECT_NE(iter, by_name.end());
}

View file

@ -95,7 +95,7 @@ class DeviceMapper final {
// Returns true if a list of available device mapper targets registered in the kernel was
// successfully read and stored in 'targets'. Returns 'false' otherwise.
bool GetAvailableTargets(std::vector<DmTarget>* targets);
bool GetAvailableTargets(std::vector<DmTargetTypeInfo>* 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

View file

@ -27,45 +27,49 @@
namespace android {
namespace dm {
class DmTargetTypeInfo {
public:
DmTargetTypeInfo() : major_(0), minor_(0), patch_(0) {}
DmTargetTypeInfo(const struct dm_target_versions* info)
: name_(info->name),
major_(info->version[0]),
minor_(info->version[1]),
patch_(info->version[2]) {}
const std::string& name() const { return name_; }
std::string version() const {
return std::to_string(major_) + "." + std::to_string(minor_) + "." + std::to_string(patch_);
}
private:
std::string name_;
uint32_t major_;
uint32_t minor_;
uint32_t patch_;
};
class DmTarget {
public:
DmTarget(const std::string& name, uint64_t start = 0, uint64_t length = 0)
: name_(name), v0_(0), v1_(0), v2_(0), start_(start), length_(length){};
// Creates a DmTarget object from dm_target_version as read from kernel
// with DM_LIST_VERSION ioctl.
DmTarget(const struct dm_target_versions* vers) : start_(0), length_(0) {
CHECK(vers != nullptr) << "Can't create DmTarget with dm_target_versions set to nullptr";
v0_ = vers->version[0];
v1_ = vers->version[1];
v2_ = vers->version[2];
name_ = vers->name;
}
DmTarget(uint64_t start, uint64_t length) : start_(start), length_(length) {}
virtual ~DmTarget() = default;
// Returns name of the target.
const std::string& name() const { return name_; }
virtual const std::string& name() const = 0;
// Return the first logical sector represented by this target.
uint64_t start() const { return start_; }
// Returns size in number of sectors when this target is part of
// a DmTable, return 0 otherwise.
uint64_t size() const { return length_; }
// Return string representation of the device mapper target version.
std::string version() const {
return std::to_string(v0_) + "." + std::to_string(v1_) + "." + std::to_string(v2_);
}
// Function that converts this object to a string of arguments that can
// be passed to the kernel for adding this target in a table. Each target (e.g. verity, linear)
// must implement this, for it to be used on a device.
virtual std::string Serialize() const { return ""; }
virtual std::string Serialize() const = 0;
private:
// Name of the target.
std::string name_;
// Target version.
uint32_t v0_, v1_, v2_;
// logical sector number start and total length (in terms of 512-byte sectors) represented
// by this target within a DmTable.
uint64_t start_, length_;

View file

@ -36,6 +36,7 @@
using DeviceMapper = ::android::dm::DeviceMapper;
using DmTable = ::android::dm::DmTable;
using DmTarget = ::android::dm::DmTarget;
using DmTargetTypeInfo = ::android::dm::DmTargetTypeInfo;
using DmBlockDevice = ::android::dm::DeviceMapper::DmBlockDevice;
static int Usage(void) {
@ -89,7 +90,7 @@ static int DmDeleteCmdHandler(int argc, char** argv) {
}
static int DmListTargets(DeviceMapper& dm) {
std::vector<DmTarget> targets;
std::vector<DmTargetTypeInfo> targets;
if (!dm.GetAvailableTargets(&targets)) {
std::cerr << "Failed to read available device mapper targets" << std::endl;
return -errno;