Merge "fs_mgr: Use libdm for dm-linear devices."

This commit is contained in:
Treehugger Robot 2018-06-26 00:00:10 +00:00 committed by Gerrit Code Review
commit 7a8bed30dd
3 changed files with 58 additions and 122 deletions

View file

@ -40,93 +40,32 @@
#include <liblp/reader.h>
#include "fs_mgr_priv.h"
#include "fs_mgr_priv_dm_ioctl.h"
namespace android {
namespace fs_mgr {
std::string LogicalPartitionExtent::Serialize() const {
// Note: we need to include an explicit null-terminator.
std::string argv =
android::base::StringPrintf("%s %" PRIu64, block_device_.c_str(), first_sector_);
argv.push_back(0);
using DeviceMapper = android::dm::DeviceMapper;
using DmTable = android::dm::DmTable;
using DmTarget = android::dm::DmTarget;
using DmTargetZero = android::dm::DmTargetZero;
using DmTargetLinear = android::dm::DmTargetLinear;
// The kernel expects each target to be aligned.
size_t spec_bytes = sizeof(struct dm_target_spec) + argv.size();
size_t padding = ((spec_bytes + 7) & ~7) - spec_bytes;
for (size_t i = 0; i < padding; i++) {
argv.push_back(0);
}
struct dm_target_spec spec;
spec.sector_start = logical_sector_;
spec.length = num_sectors_;
spec.status = 0;
strcpy(spec.target_type, "linear");
spec.next = sizeof(struct dm_target_spec) + argv.size();
return std::string((char*)&spec, sizeof(spec)) + argv;
}
static bool LoadDmTable(int dm_fd, const LogicalPartition& partition) {
// Combine all dm_target_spec buffers together.
std::string target_string;
static bool CreateDmDeviceForPartition(DeviceMapper& dm, const LogicalPartition& partition) {
DmTable table;
for (const auto& extent : partition.extents) {
target_string += extent.Serialize();
table.AddTarget(std::make_unique<DmTargetLinear>(extent));
}
// Allocate the ioctl buffer.
size_t buffer_size = sizeof(struct dm_ioctl) + target_string.size();
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(buffer_size);
// Initialize the ioctl buffer header, then copy our target specs in.
struct dm_ioctl* io = reinterpret_cast<struct dm_ioctl*>(buffer.get());
fs_mgr_dm_ioctl_init(io, buffer_size, partition.name);
io->target_count = partition.extents.size();
if (partition.attributes & kPartitionReadonly) {
io->flags |= DM_READONLY_FLAG;
}
memcpy(io + 1, target_string.c_str(), target_string.size());
if (ioctl(dm_fd, DM_TABLE_LOAD, io)) {
PERROR << "Failed ioctl() on DM_TABLE_LOAD, partition " << partition.name;
if (!dm.CreateDevice(partition.name, table)) {
return false;
}
return true;
}
static bool LoadTablesAndActivate(int dm_fd, const LogicalPartition& partition) {
if (!LoadDmTable(dm_fd, partition)) {
return false;
}
struct dm_ioctl io;
return fs_mgr_dm_resume_table(&io, partition.name, dm_fd);
}
static bool CreateDmDeviceForPartition(int dm_fd, const LogicalPartition& partition) {
struct dm_ioctl io;
if (!fs_mgr_dm_create_device(&io, partition.name, dm_fd)) {
return false;
}
if (!LoadTablesAndActivate(dm_fd, partition)) {
// Remove the device rather than leave it in an inactive state.
fs_mgr_dm_destroy_device(&io, partition.name, dm_fd);
return false;
}
LINFO << "Created device-mapper device: " << partition.name;
return true;
}
bool CreateLogicalPartitions(const LogicalPartitionTable& table) {
android::base::unique_fd dm_fd(open("/dev/device-mapper", O_RDWR));
if (dm_fd < 0) {
PLOG(ERROR) << "failed to open /dev/device-mapper";
return false;
}
DeviceMapper& dm = DeviceMapper::Instance();
for (const auto& partition : table.partitions) {
if (!CreateDmDeviceForPartition(dm_fd, partition)) {
if (!CreateDmDeviceForPartition(dm, partition)) {
LOG(ERROR) << "could not create dm-linear device for partition: " << partition.name;
return false;
}
@ -138,6 +77,35 @@ std::unique_ptr<LogicalPartitionTable> LoadPartitionsFromDeviceTree() {
return nullptr;
}
static bool CreateDmTable(const std::string& block_device, const LpMetadata& metadata,
const LpMetadataPartition& partition, DmTable* table) {
uint64_t sector = 0;
for (size_t i = 0; i < partition.num_extents; i++) {
const auto& extent = metadata.extents[partition.first_extent_index + i];
std::unique_ptr<DmTarget> target;
switch (extent.target_type) {
case LP_TARGET_TYPE_ZERO:
target = std::make_unique<DmTargetZero>(sector, extent.num_sectors);
break;
case LP_TARGET_TYPE_LINEAR:
target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, block_device,
extent.target_data);
break;
default:
LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type;
return false;
}
if (!table->AddTarget(std::move(target))) {
return false;
}
sector += extent.num_sectors;
}
if (partition.attributes & LP_PARTITION_ATTR_READONLY) {
table->set_readonly(true);
}
return true;
}
bool CreateLogicalPartitions(const std::string& block_device) {
uint32_t slot = SlotNumberForSlotSuffix(fs_mgr_get_slot_suffix());
auto metadata = ReadMetadata(block_device.c_str(), slot);
@ -146,21 +114,21 @@ bool CreateLogicalPartitions(const std::string& block_device) {
return true;
}
LogicalPartitionTable table;
DeviceMapper& dm = DeviceMapper::Instance();
for (const auto& partition : metadata->partitions) {
LogicalPartition new_partition;
new_partition.name = GetPartitionName(partition);
new_partition.attributes = partition.attributes;
for (size_t i = 0; i < partition.num_extents; i++) {
const auto& extent = metadata->extents[partition.first_extent_index + i];
new_partition.extents.emplace_back(new_partition.num_sectors, extent.target_data,
extent.num_sectors, block_device.c_str());
new_partition.num_sectors += extent.num_sectors;
DmTable table;
if (!CreateDmTable(block_device, *metadata.get(), partition, &table)) {
return false;
}
table.partitions.push_back(new_partition);
std::string name = GetPartitionName(partition);
if (!dm.CreateDevice(name, table)) {
return false;
}
std::string path;
dm.GetDmDevicePathByName(partition.name, &path);
LINFO << "Created logical partition " << name << " on device " << path;
}
return CreateLogicalPartitions(table);
return true;
}
} // namespace fs_mgr

View file

@ -26,53 +26,20 @@
#define __CORE_FS_MGR_DM_LINEAR_H
#include <stdint.h>
#include <memory>
#include <string>
#include <vector>
#include <libdm/dm.h>
#include <liblp/metadata_format.h>
namespace android {
namespace fs_mgr {
static const uint32_t kPartitionReadonly = 0x1;
class LogicalPartitionExtent {
public:
LogicalPartitionExtent() : logical_sector_(0), first_sector_(0), num_sectors_(0) {}
LogicalPartitionExtent(uint64_t logical_sector, uint64_t first_sector, uint64_t num_sectors,
const std::string& block_device)
: logical_sector_(logical_sector),
first_sector_(first_sector),
num_sectors_(num_sectors),
block_device_(block_device) {}
// Return a string containing the dm_target_spec buffer needed to use this
// extent in a device-mapper table.
std::string Serialize() const;
const std::string& block_device() const { return block_device_; }
private:
// Logical sector this extent represents in the presented block device.
// This is equal to the previous extent's logical sector plus the number
// of sectors in that extent. The first extent always starts at 0.
uint64_t logical_sector_;
// First 512-byte sector of this extent, on the source block device.
uint64_t first_sector_;
// Number of 512-byte sectors.
uint64_t num_sectors_;
// Target block device.
std::string block_device_;
};
struct LogicalPartition {
LogicalPartition() : attributes(0), num_sectors(0) {}
std::string name;
uint32_t attributes;
// Number of 512-byte sectors total.
uint64_t num_sectors;
// List of extents.
std::vector<LogicalPartitionExtent> extents;
std::vector<android::dm::DmTargetLinear> extents;
};
struct LogicalPartitionTable {

View file

@ -96,6 +96,7 @@ class DmTargetLinear final : public DmTarget {
std::string name() const override { return "linear"; }
std::string GetParameterString() const override;
const std::string& block_device() const { return block_device_; }
private:
std::string block_device_;