Merge changes from topic "libdm"
am: b066bbebd1
Change-Id: I2e7c1c71c9c7e25797a79702ceeafe756f457d26
This commit is contained in:
commit
ee888fe1d3
10 changed files with 903 additions and 0 deletions
|
|
@ -56,12 +56,15 @@ cc_library_static {
|
|||
"libselinux",
|
||||
"libavb",
|
||||
"libfstab",
|
||||
"libdm",
|
||||
],
|
||||
export_static_lib_headers: [
|
||||
"libfstab",
|
||||
"libdm",
|
||||
],
|
||||
whole_static_libs: [
|
||||
"liblogwrap",
|
||||
"libdm",
|
||||
"libfstab",
|
||||
],
|
||||
cppflags: [
|
||||
|
|
|
|||
37
fs_mgr/libdm/Android.bp
Normal file
37
fs_mgr/libdm/Android.bp
Normal 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.
|
||||
//
|
||||
|
||||
cc_library_static {
|
||||
name: "libdm",
|
||||
recovery_available: true,
|
||||
|
||||
export_include_dirs: ["include"],
|
||||
cflags: [
|
||||
// TODO(b/110035986): Allows us to create a skeleton of required classes
|
||||
"-Wno-unused-private-field",
|
||||
],
|
||||
|
||||
srcs: [
|
||||
"dm_table.cpp",
|
||||
"dm_target.cpp",
|
||||
"dm.cpp"
|
||||
],
|
||||
|
||||
header_libs: [
|
||||
"libbase_headers",
|
||||
"liblog_headers",
|
||||
],
|
||||
}
|
||||
270
fs_mgr/libdm/dm.cpp
Normal file
270
fs_mgr/libdm/dm.cpp
Normal file
|
|
@ -0,0 +1,270 @@
|
|||
/*
|
||||
* 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/macros.h>
|
||||
#include <android-base/unique_fd.h>
|
||||
|
||||
#include "dm.h"
|
||||
|
||||
namespace android {
|
||||
namespace dm {
|
||||
|
||||
DeviceMapper& DeviceMapper::Instance() {
|
||||
static DeviceMapper instance;
|
||||
return instance;
|
||||
}
|
||||
// Creates a new device mapper device
|
||||
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 true;
|
||||
}
|
||||
|
||||
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 {
|
||||
// TODO(b/110035986): Return the table, as read from the kernel instead
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DmDeviceState DeviceMapper::state(const std::string& /* name */) const {
|
||||
// TODO(b/110035986): Return the state, as read from the kernel instead
|
||||
return DmDeviceState::INVALID;
|
||||
}
|
||||
|
||||
bool DeviceMapper::LoadTableAndActivate(const std::string& /* name */, const DmTable& /* table */) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
targets->clear();
|
||||
|
||||
// calculate the space needed to read a maximum of kMaxPossibleDmTargets
|
||||
uint32_t payload_size = sizeof(struct dm_target_versions);
|
||||
payload_size += DM_MAX_TYPE_NAME;
|
||||
// device mapper wants every target spec to be aligned at 8-byte boundary
|
||||
payload_size = DM_ALIGN(payload_size);
|
||||
payload_size *= kMaxPossibleDmTargets;
|
||||
|
||||
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_VERSIONS, io)) {
|
||||
PLOG(ERROR) << "Failed to get DM_LIST_VERSIONS from kernel";
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the provided buffer wasn't enough to list all targets, note that
|
||||
// any data beyond sizeof(*io) must not be read in this case
|
||||
if (io->flags & DM_BUFFER_FULL_FLAG) {
|
||||
LOG(INFO) << data_size << " is not enough memory to list all dm targets";
|
||||
return false;
|
||||
}
|
||||
|
||||
// if there are no targets registered, return success with empty vector
|
||||
if (io->data_size == sizeof(*io)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Parse each target and list the name and version
|
||||
// TODO(b/110035986): Templatize this
|
||||
uint32_t next = sizeof(*io);
|
||||
data_size = io->data_size - next;
|
||||
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));
|
||||
if (vers->next == 0) {
|
||||
break;
|
||||
}
|
||||
next += vers->next;
|
||||
data_size -= vers->next;
|
||||
vers = reinterpret_cast<struct dm_target_versions*>(static_cast<char*>(buffer.get()) + next);
|
||||
}
|
||||
|
||||
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 */) {
|
||||
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
|
||||
55
fs_mgr/libdm/dm_table.cpp
Normal file
55
fs_mgr/libdm/dm_table.cpp
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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 <android-base/logging.h>
|
||||
#include <android-base/macros.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "dm_table.h"
|
||||
|
||||
namespace android {
|
||||
namespace dm {
|
||||
|
||||
bool DmTable::AddTarget(std::unique_ptr<DmTarget>&& /* target */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DmTable::RemoveTarget(std::unique_ptr<DmTarget>&& /* target */) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DmTable::valid() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
uint64_t DmTable::size() const {
|
||||
return valid() ? size_ : 0;
|
||||
}
|
||||
|
||||
// Returns a string represnetation of the table that is ready to be passed
|
||||
// down to the kernel for loading
|
||||
//
|
||||
// Implementation must verify there are no gaps in the table, table starts
|
||||
// with sector == 0, and iterate over each target to get its table
|
||||
// serialized.
|
||||
std::string DmTable::Serialize() const {
|
||||
return "";
|
||||
}
|
||||
|
||||
} // namespace dm
|
||||
} // namespace android
|
||||
29
fs_mgr/libdm/dm_target.cpp
Normal file
29
fs_mgr/libdm/dm_target.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* 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 <android-base/logging.h>
|
||||
#include <android-base/macros.h>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "dm_target.h"
|
||||
|
||||
namespace android {
|
||||
namespace dm {} // namespace dm
|
||||
} // namespace android
|
||||
152
fs_mgr/libdm/include/dm.h
Normal file
152
fs_mgr/libdm/include/dm.h
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
* Copyright 2018 Google, Inc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBDM_DM_H_
|
||||
#define _LIBDM_DM_H_
|
||||
|
||||
#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>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#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)
|
||||
|
||||
namespace android {
|
||||
namespace dm {
|
||||
|
||||
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
|
||||
// exists.
|
||||
// TODO(b/110035986): Make this method private and to be only
|
||||
// called through LoadTableAndActivate() below.
|
||||
bool CreateDevice(const std::string& name);
|
||||
|
||||
// Removes a device mapper device with the given name.
|
||||
// Returns 'true' on success, false otherwise.
|
||||
bool DeleteDevice(const std::string& name);
|
||||
|
||||
// Reads the device mapper table from the device with given anme and
|
||||
// returns it in a DmTable object.
|
||||
const std::unique_ptr<DmTable> table(const std::string& name) const;
|
||||
|
||||
// Returns the current state of the underlying device mapper device
|
||||
// with given name.
|
||||
// One of INVALID, SUSPENDED or ACTIVE.
|
||||
DmDeviceState state(const std::string& name) const;
|
||||
|
||||
// Loads the device mapper table from parameter into the underlying
|
||||
// device mapper device with given name and activate / resumes the device in the process.
|
||||
// If a device mapper device with the 'name', doesn't exist, it will be created.
|
||||
// Returns 'true' on success, false otherwise.
|
||||
bool LoadTableAndActivate(const std::string& name, const DmTable& table);
|
||||
|
||||
// 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);
|
||||
|
||||
// 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);
|
||||
|
||||
// The only way to create a DeviceMapper object.
|
||||
static DeviceMapper& Instance();
|
||||
|
||||
~DeviceMapper() {
|
||||
if (fd_ != -1) {
|
||||
::close(fd_);
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// 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) {
|
||||
fd_ = TEMP_FAILURE_RETRY(open("/dev/device-mapper", O_RDWR | O_CLOEXEC));
|
||||
if (fd_ < 0) {
|
||||
PLOG(ERROR) << "Failed to open device-mapper";
|
||||
}
|
||||
}
|
||||
|
||||
int fd_;
|
||||
// Non-copyable & Non-movable
|
||||
DeviceMapper(const DeviceMapper&) = delete;
|
||||
DeviceMapper& operator=(const DeviceMapper&) = delete;
|
||||
DeviceMapper& operator=(DeviceMapper&&) = delete;
|
||||
DeviceMapper(DeviceMapper&&) = delete;
|
||||
};
|
||||
|
||||
} // namespace dm
|
||||
} // namespace android
|
||||
|
||||
#endif /* _LIBDM_DM_H_ */
|
||||
75
fs_mgr/libdm/include/dm_table.h
Normal file
75
fs_mgr/libdm/include/dm_table.h
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* Copyright 2018 Google, Inc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBDM_DMTABLE_H_
|
||||
#define _LIBDM_DMTABLE_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "dm_target.h"
|
||||
|
||||
namespace android {
|
||||
namespace dm {
|
||||
|
||||
class DmTable {
|
||||
public:
|
||||
DmTable() : size_(0){};
|
||||
|
||||
// Adds a target to the device mapper table for a range specified in the target object.
|
||||
// The function will return 'true' if the target was successfully added and doesn't overlap with
|
||||
// any of the existing targets in the table. Gaps are allowed. The final check, including
|
||||
// overlaps and gaps are done before loading the table. Returns 'false' on failure.
|
||||
bool AddTarget(std::unique_ptr<DmTarget>&& target);
|
||||
|
||||
// Removes a target from the table for the range specified in the target object. Returns 'false'
|
||||
// if the target name doesn't match with the one in the table. Returns 'true' if target is
|
||||
// successfully removed.
|
||||
bool RemoveTarget(std::unique_ptr<DmTarget>&& target);
|
||||
|
||||
// Checks the table to make sure it is valid. i.e. Checks for range overlaps, range gaps
|
||||
// and returns 'true' if the table is ready to be loaded into kernel. Returns 'false' if the
|
||||
// table is malformed.
|
||||
bool valid() const;
|
||||
|
||||
// Returns the total size represented by the table in terms of number of 512-byte sectors.
|
||||
// NOTE: This function will overlook if there are any gaps in the targets added in the table.
|
||||
uint64_t size() const;
|
||||
|
||||
// Returns the string represntation of the table that is ready to be passed into the kernel
|
||||
// as part of the DM_TABLE_LOAD ioctl.
|
||||
std::string Serialize() const;
|
||||
|
||||
~DmTable() = default;
|
||||
|
||||
private:
|
||||
// list of targets defined in this table sorted by
|
||||
// their start and end sectors.
|
||||
// Note: Overlapping targets MUST never be added in this list.
|
||||
std::vector<std::unique_ptr<DmTarget>> targets_;
|
||||
|
||||
// Total size in terms of # of sectors, as calculated by looking at the last and the first
|
||||
// target in 'target_'.
|
||||
uint64_t size_;
|
||||
};
|
||||
|
||||
} // namespace dm
|
||||
} // namespace android
|
||||
|
||||
#endif /* _LIBDM_DMTABLE_H_ */
|
||||
77
fs_mgr/libdm/include/dm_target.h
Normal file
77
fs_mgr/libdm/include/dm_target.h
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2018 Google, Inc
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _LIBDM_DMTARGET_H_
|
||||
#define _LIBDM_DMTARGET_H_
|
||||
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace android {
|
||||
namespace dm {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
virtual ~DmTarget() = default;
|
||||
|
||||
// Returns name of the target.
|
||||
const std::string& name() const { return name_; }
|
||||
|
||||
// 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 ""; }
|
||||
|
||||
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_;
|
||||
};
|
||||
|
||||
} // namespace dm
|
||||
} // namespace android
|
||||
|
||||
#endif /* _LIBDM_DMTARGET_H_ */
|
||||
31
fs_mgr/tools/Android.bp
Normal file
31
fs_mgr/tools/Android.bp
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// 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.
|
||||
//
|
||||
|
||||
cc_binary {
|
||||
name: "dmctl",
|
||||
srcs: ["dmctl.cpp"],
|
||||
|
||||
static_libs: [
|
||||
"libfs_mgr",
|
||||
],
|
||||
|
||||
shared_libs: [
|
||||
"libbase",
|
||||
"liblog",
|
||||
],
|
||||
|
||||
cflags: ["-Werror"],
|
||||
}
|
||||
174
fs_mgr/tools/dmctl.cpp
Normal file
174
fs_mgr/tools/dmctl.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
/*
|
||||
* 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 <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <linux/dm-ioctl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/unique_fd.h>
|
||||
#include <dm.h>
|
||||
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <ios>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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 <devices | targets>";
|
||||
std::cerr, " help";
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int DmCreateCmdHandler(int argc, char** argv) {
|
||||
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.CreateDevice(name)) {
|
||||
std::cerr << "DmCreateCmdHandler: Failed to create " << name << " device";
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int DmDeleteCmdHandler(int argc, char** argv) {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
for (const auto& target : targets) {
|
||||
std::cout << std::left << std::setw(20) << target.name() << " : " << target.version()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static std::map<std::string, std::function<int(int, char**)>> cmdmap = {
|
||||
{"create", DmCreateCmdHandler},
|
||||
{"delete", DmDeleteCmdHandler},
|
||||
{"list", DmListCmdHandler},
|
||||
{"help", HelpCmdHandler},
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
android::base::InitLogging(argv, &android::base::StderrLogger);
|
||||
if (argc < 2) {
|
||||
return Usage();
|
||||
}
|
||||
|
||||
for (const auto& cmd : cmdmap) {
|
||||
if (cmd.first == argv[1]) {
|
||||
return cmd.second(argc - 2, argv + 2);
|
||||
}
|
||||
}
|
||||
|
||||
return Usage();
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue