Merge "fs_mgr: Use libdm for dm-linear devices."
This commit is contained in:
commit
7a8bed30dd
3 changed files with 58 additions and 122 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue