Merge "liblp: Allow the super partition to span multiple block devices."
This commit is contained in:
commit
2cda71c9f6
|
@ -75,14 +75,9 @@ static bool CreateDmTable(const LpMetadata& metadata, const LpMetadataPartition&
|
|||
target = std::make_unique<DmTargetZero>(sector, extent.num_sectors);
|
||||
break;
|
||||
case LP_TARGET_TYPE_LINEAR: {
|
||||
auto block_device = GetMetadataSuperBlockDevice(metadata);
|
||||
if (!block_device) {
|
||||
LOG(ERROR) << "Could not identify the super block device";
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& block_device = metadata.block_devices[extent.target_source];
|
||||
std::string path;
|
||||
if (!GetPhysicalPartitionDevicePath(*block_device, &path)) {
|
||||
if (!GetPhysicalPartitionDevicePath(block_device, &path)) {
|
||||
LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -29,12 +29,19 @@
|
|||
namespace android {
|
||||
namespace fs_mgr {
|
||||
|
||||
void LinearExtent::AddTo(LpMetadata* out) const {
|
||||
out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_});
|
||||
bool LinearExtent::AddTo(LpMetadata* out) const {
|
||||
if (device_index_ >= out->block_devices.size()) {
|
||||
LERROR << "Extent references unknown block device.";
|
||||
return false;
|
||||
}
|
||||
out->extents.emplace_back(
|
||||
LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_, device_index_});
|
||||
return true;
|
||||
}
|
||||
|
||||
void ZeroExtent::AddTo(LpMetadata* out) const {
|
||||
out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0});
|
||||
bool ZeroExtent::AddTo(LpMetadata* out) const {
|
||||
out->extents.emplace_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0, 0});
|
||||
return true;
|
||||
}
|
||||
|
||||
Partition::Partition(const std::string& name, const std::string& group_name, uint32_t attributes)
|
||||
|
@ -44,15 +51,17 @@ void Partition::AddExtent(std::unique_ptr<Extent>&& extent) {
|
|||
size_ += extent->num_sectors() * LP_SECTOR_SIZE;
|
||||
|
||||
if (LinearExtent* new_extent = extent->AsLinearExtent()) {
|
||||
if (!extents_.empty() && extents_.back()->AsLinearExtent() &&
|
||||
extents_.back()->AsLinearExtent()->end_sector() == new_extent->physical_sector()) {
|
||||
// If the previous extent can be merged into this new one, do so
|
||||
// to avoid creating unnecessary extents.
|
||||
if (!extents_.empty() && extents_.back()->AsLinearExtent()) {
|
||||
LinearExtent* prev_extent = extents_.back()->AsLinearExtent();
|
||||
extent = std::make_unique<LinearExtent>(
|
||||
prev_extent->num_sectors() + new_extent->num_sectors(),
|
||||
prev_extent->physical_sector());
|
||||
extents_.pop_back();
|
||||
if (prev_extent->end_sector() == new_extent->physical_sector() &&
|
||||
prev_extent->device_index() == new_extent->device_index()) {
|
||||
// If the previous extent can be merged into this new one, do so
|
||||
// to avoid creating unnecessary extents.
|
||||
extent = std::make_unique<LinearExtent>(
|
||||
prev_extent->num_sectors() + new_extent->num_sectors(),
|
||||
prev_extent->device_index(), prev_extent->physical_sector());
|
||||
extents_.pop_back();
|
||||
}
|
||||
}
|
||||
}
|
||||
extents_.push_back(std::move(extent));
|
||||
|
@ -108,9 +117,12 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const IPartitionOpener& op
|
|||
if (!builder) {
|
||||
return nullptr;
|
||||
}
|
||||
BlockDeviceInfo device_info;
|
||||
if (opener.GetInfo(super_partition, &device_info)) {
|
||||
builder->UpdateBlockDeviceInfo(device_info);
|
||||
for (size_t i = 0; i < builder->block_devices_.size(); i++) {
|
||||
std::string partition_name = GetBlockDevicePartitionName(builder->block_devices_[i]);
|
||||
BlockDeviceInfo device_info;
|
||||
if (opener.GetInfo(partition_name, &device_info)) {
|
||||
builder->UpdateBlockDeviceInfo(i, device_info);
|
||||
}
|
||||
}
|
||||
return builder;
|
||||
}
|
||||
|
@ -120,11 +132,11 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& super_p
|
|||
return New(PartitionOpener(), super_partition, slot_number);
|
||||
}
|
||||
|
||||
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const BlockDeviceInfo& device_info,
|
||||
uint32_t metadata_max_size,
|
||||
uint32_t metadata_slot_count) {
|
||||
std::unique_ptr<MetadataBuilder> MetadataBuilder::New(
|
||||
const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition,
|
||||
uint32_t metadata_max_size, uint32_t metadata_slot_count) {
|
||||
std::unique_ptr<MetadataBuilder> builder(new MetadataBuilder());
|
||||
if (!builder->Init(device_info, metadata_max_size, metadata_slot_count)) {
|
||||
if (!builder->Init(block_devices, super_partition, metadata_max_size, metadata_slot_count)) {
|
||||
return nullptr;
|
||||
}
|
||||
return builder;
|
||||
|
@ -156,6 +168,7 @@ MetadataBuilder::MetadataBuilder() {
|
|||
|
||||
bool MetadataBuilder::Init(const LpMetadata& metadata) {
|
||||
geometry_ = metadata.geometry;
|
||||
block_devices_ = metadata.block_devices;
|
||||
|
||||
for (const auto& group : metadata.groups) {
|
||||
std::string group_name = GetPartitionGroupName(group);
|
||||
|
@ -164,10 +177,6 @@ bool MetadataBuilder::Init(const LpMetadata& metadata) {
|
|||
}
|
||||
}
|
||||
|
||||
for (const auto& block_device : metadata.block_devices) {
|
||||
block_devices_.push_back(block_device);
|
||||
}
|
||||
|
||||
for (const auto& partition : metadata.partitions) {
|
||||
std::string group_name = GetPartitionGroupName(metadata.groups[partition.group_index]);
|
||||
Partition* builder =
|
||||
|
@ -179,7 +188,8 @@ bool MetadataBuilder::Init(const LpMetadata& metadata) {
|
|||
for (size_t i = 0; i < partition.num_extents; i++) {
|
||||
const LpMetadataExtent& extent = metadata.extents[partition.first_extent_index + i];
|
||||
if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
|
||||
auto copy = std::make_unique<LinearExtent>(extent.num_sectors, extent.target_data);
|
||||
auto copy = std::make_unique<LinearExtent>(extent.num_sectors, extent.target_source,
|
||||
extent.target_data);
|
||||
builder->AddExtent(std::move(copy));
|
||||
} else if (extent.target_type == LP_TARGET_TYPE_ZERO) {
|
||||
auto copy = std::make_unique<ZeroExtent>(extent.num_sectors);
|
||||
|
@ -190,7 +200,37 @@ bool MetadataBuilder::Init(const LpMetadata& metadata) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata_max_size,
|
||||
static bool VerifyDeviceProperties(const BlockDeviceInfo& device_info) {
|
||||
if (device_info.logical_block_size % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Block device " << device_info.partition_name
|
||||
<< " logical block size must be a multiple of 512.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.size % device_info.logical_block_size != 0) {
|
||||
LERROR << "Block device " << device_info.partition_name
|
||||
<< " size must be a multiple of its block size.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.alignment_offset % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Block device " << device_info.partition_name
|
||||
<< " alignment offset is not sector-aligned.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.alignment % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Block device " << device_info.partition_name
|
||||
<< " partition alignment is not sector-aligned.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.alignment_offset > device_info.alignment) {
|
||||
LERROR << "Block device " << device_info.partition_name
|
||||
<< " partition alignment offset is greater than its alignment.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetadataBuilder::Init(const std::vector<BlockDeviceInfo>& block_devices,
|
||||
const std::string& super_partition, uint32_t metadata_max_size,
|
||||
uint32_t metadata_slot_count) {
|
||||
if (metadata_max_size < sizeof(LpMetadataHeader)) {
|
||||
LERROR << "Invalid metadata maximum size.";
|
||||
|
@ -200,70 +240,102 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
|
|||
LERROR << "Invalid metadata slot count.";
|
||||
return false;
|
||||
}
|
||||
if (block_devices.empty()) {
|
||||
LERROR << "No block devices were specified.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Align the metadata size up to the nearest sector.
|
||||
metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
|
||||
|
||||
// Check that device properties are sane.
|
||||
if (device_info.size % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Block device size must be a multiple of 512.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.logical_block_size % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Logical block size must be a multiple of 512.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.alignment_offset % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Alignment offset is not sector-aligned.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.alignment % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Partition alignment is not sector-aligned.";
|
||||
return false;
|
||||
}
|
||||
if (device_info.alignment_offset > device_info.alignment) {
|
||||
LERROR << "Partition alignment offset is greater than its alignment.";
|
||||
// Validate and build the block device list.
|
||||
uint32_t logical_block_size = 0;
|
||||
for (const auto& device_info : block_devices) {
|
||||
if (!VerifyDeviceProperties(device_info)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!logical_block_size) {
|
||||
logical_block_size = device_info.logical_block_size;
|
||||
}
|
||||
if (logical_block_size != device_info.logical_block_size) {
|
||||
LERROR << "All partitions must have the same logical block size.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LpMetadataBlockDevice out = {};
|
||||
out.alignment = device_info.alignment;
|
||||
out.alignment_offset = device_info.alignment_offset;
|
||||
out.size = device_info.size;
|
||||
if (device_info.partition_name.size() >= sizeof(out.partition_name)) {
|
||||
LERROR << "Partition name " << device_info.partition_name << " exceeds maximum length.";
|
||||
return false;
|
||||
}
|
||||
strncpy(out.partition_name, device_info.partition_name.c_str(), sizeof(out.partition_name));
|
||||
|
||||
// In the case of the super partition, this field will be adjusted
|
||||
// later. For all partitions, the first 512 bytes are considered
|
||||
// untouched to be compatible code that looks for an MBR. Thus we
|
||||
// start counting free sectors at sector 1, not 0.
|
||||
uint64_t free_area_start = LP_SECTOR_SIZE;
|
||||
if (out.alignment || out.alignment_offset) {
|
||||
free_area_start = AlignTo(free_area_start, out.alignment, out.alignment_offset);
|
||||
} else {
|
||||
free_area_start = AlignTo(free_area_start, logical_block_size);
|
||||
}
|
||||
out.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
|
||||
|
||||
// There must be one logical block of space available.
|
||||
uint64_t minimum_size = out.first_logical_sector * LP_SECTOR_SIZE + logical_block_size;
|
||||
if (device_info.size < minimum_size) {
|
||||
LERROR << "Block device " << device_info.partition_name
|
||||
<< " is too small to hold any logical partitions.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// The "root" of the super partition is always listed first.
|
||||
if (device_info.partition_name == super_partition) {
|
||||
block_devices_.emplace(block_devices_.begin(), out);
|
||||
} else {
|
||||
block_devices_.emplace_back(out);
|
||||
}
|
||||
}
|
||||
if (GetBlockDevicePartitionName(block_devices_[0]) != super_partition) {
|
||||
LERROR << "No super partition was specified.";
|
||||
return false;
|
||||
}
|
||||
|
||||
LpMetadataBlockDevice& super = block_devices_[0];
|
||||
|
||||
// We reserve a geometry block (4KB) plus space for each copy of the
|
||||
// maximum size of a metadata blob. Then, we double that space since
|
||||
// we store a backup copy of everything.
|
||||
uint64_t total_reserved = GetTotalMetadataSize(metadata_max_size, metadata_slot_count);
|
||||
if (device_info.size < total_reserved) {
|
||||
if (super.size < total_reserved) {
|
||||
LERROR << "Attempting to create metadata on a block device that is too small.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compute the first free sector, factoring in alignment.
|
||||
uint64_t free_area_start = total_reserved;
|
||||
if (device_info.alignment || device_info.alignment_offset) {
|
||||
free_area_start =
|
||||
AlignTo(free_area_start, device_info.alignment, device_info.alignment_offset);
|
||||
if (super.alignment || super.alignment_offset) {
|
||||
free_area_start = AlignTo(free_area_start, super.alignment, super.alignment_offset);
|
||||
} else {
|
||||
free_area_start = AlignTo(free_area_start, device_info.logical_block_size);
|
||||
free_area_start = AlignTo(free_area_start, logical_block_size);
|
||||
}
|
||||
uint64_t first_sector = free_area_start / LP_SECTOR_SIZE;
|
||||
super.first_logical_sector = free_area_start / LP_SECTOR_SIZE;
|
||||
|
||||
// There must be one logical block of free space remaining (enough for one partition).
|
||||
uint64_t minimum_disk_size = (first_sector * LP_SECTOR_SIZE) + device_info.logical_block_size;
|
||||
if (device_info.size < minimum_disk_size) {
|
||||
uint64_t minimum_disk_size = (super.first_logical_sector * LP_SECTOR_SIZE) + logical_block_size;
|
||||
if (super.size < minimum_disk_size) {
|
||||
LERROR << "Device must be at least " << minimum_disk_size << " bytes, only has "
|
||||
<< device_info.size;
|
||||
<< super.size;
|
||||
return false;
|
||||
}
|
||||
|
||||
block_devices_.push_back(LpMetadataBlockDevice{
|
||||
first_sector,
|
||||
device_info.alignment,
|
||||
device_info.alignment_offset,
|
||||
device_info.size,
|
||||
"super",
|
||||
});
|
||||
|
||||
geometry_.metadata_max_size = metadata_max_size;
|
||||
geometry_.metadata_slot_count = metadata_slot_count;
|
||||
geometry_.logical_block_size = device_info.logical_block_size;
|
||||
geometry_.logical_block_size = logical_block_size;
|
||||
|
||||
if (!AddGroup("default", 0)) {
|
||||
return false;
|
||||
|
@ -347,8 +419,9 @@ void MetadataBuilder::ExtentsToFreeList(const std::vector<Interval>& extents,
|
|||
for (size_t i = 1; i < extents.size(); i++) {
|
||||
const Interval& previous = extents[i - 1];
|
||||
const Interval& current = extents[i];
|
||||
DCHECK(previous.device_index == current.device_index);
|
||||
|
||||
uint64_t aligned = AlignSector(previous.end);
|
||||
uint64_t aligned = AlignSector(block_devices_[current.device_index], previous.end);
|
||||
if (aligned >= current.start) {
|
||||
// There is no gap between these two extents, try the next one.
|
||||
// Note that we check with >= instead of >, since alignment may
|
||||
|
@ -358,37 +431,43 @@ void MetadataBuilder::ExtentsToFreeList(const std::vector<Interval>& extents,
|
|||
|
||||
// The new interval represents the free space starting at the end of
|
||||
// the previous interval, and ending at the start of the next interval.
|
||||
free_regions->emplace_back(aligned, current.start);
|
||||
free_regions->emplace_back(current.device_index, aligned, current.start);
|
||||
}
|
||||
}
|
||||
|
||||
auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> {
|
||||
std::vector<Interval> free_regions;
|
||||
|
||||
// Collect all extents in the partition table, then sort them by starting
|
||||
// sector.
|
||||
std::vector<Interval> extents;
|
||||
// Collect all extents in the partition table, per-device, then sort them
|
||||
// by starting sector.
|
||||
std::vector<std::vector<Interval>> device_extents(block_devices_.size());
|
||||
for (const auto& partition : partitions_) {
|
||||
for (const auto& extent : partition->extents()) {
|
||||
LinearExtent* linear = extent->AsLinearExtent();
|
||||
if (!linear) {
|
||||
continue;
|
||||
}
|
||||
extents.emplace_back(linear->physical_sector(),
|
||||
CHECK(linear->device_index() < device_extents.size());
|
||||
auto& extents = device_extents[linear->device_index()];
|
||||
extents.emplace_back(linear->device_index(), linear->physical_sector(),
|
||||
linear->physical_sector() + extent->num_sectors());
|
||||
}
|
||||
}
|
||||
|
||||
// Add 0-length intervals for the first and last sectors. This will cause
|
||||
// ExtentToFreeList() to treat the space in between as available.
|
||||
uint64_t first_sector = super_device().first_logical_sector;
|
||||
uint64_t last_sector = super_device().size / LP_SECTOR_SIZE;
|
||||
extents.emplace_back(first_sector, first_sector);
|
||||
extents.emplace_back(last_sector, last_sector);
|
||||
for (size_t i = 0; i < device_extents.size(); i++) {
|
||||
auto& extents = device_extents[i];
|
||||
const auto& block_device = block_devices_[i];
|
||||
|
||||
std::sort(extents.begin(), extents.end());
|
||||
uint64_t first_sector = block_device.first_logical_sector;
|
||||
uint64_t last_sector = block_device.size / LP_SECTOR_SIZE;
|
||||
extents.emplace_back(i, first_sector, first_sector);
|
||||
extents.emplace_back(i, last_sector, last_sector);
|
||||
|
||||
ExtentsToFreeList(extents, &free_regions);
|
||||
std::sort(extents.begin(), extents.end());
|
||||
ExtentsToFreeList(extents, &free_regions);
|
||||
}
|
||||
return free_regions;
|
||||
}
|
||||
|
||||
|
@ -443,7 +522,7 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
|
|||
uint64_t sectors = std::min(sectors_needed, region.length());
|
||||
CHECK(sectors % sectors_per_block == 0);
|
||||
|
||||
auto extent = std::make_unique<LinearExtent>(sectors, region.start);
|
||||
auto extent = std::make_unique<LinearExtent>(sectors, region.device_index, region.start);
|
||||
new_extents.push_back(std::move(extent));
|
||||
sectors_needed -= sectors;
|
||||
if (!sectors_needed) {
|
||||
|
@ -471,6 +550,9 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
|
|||
metadata->header = header_;
|
||||
metadata->geometry = geometry_;
|
||||
|
||||
// Assign this early so the extent table can read it.
|
||||
metadata->block_devices = block_devices_;
|
||||
|
||||
std::map<std::string, size_t> group_indices;
|
||||
for (const auto& group : groups_) {
|
||||
LpMetadataPartitionGroup out = {};
|
||||
|
@ -515,13 +597,13 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
|
|||
part.group_index = iter->second;
|
||||
|
||||
for (const auto& extent : partition->extents()) {
|
||||
extent->AddTo(metadata.get());
|
||||
if (!extent->AddTo(metadata.get())) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
metadata->partitions.push_back(part);
|
||||
}
|
||||
|
||||
metadata->block_devices = block_devices_;
|
||||
|
||||
metadata->header.partitions.num_entries = static_cast<uint32_t>(metadata->partitions.size());
|
||||
metadata->header.extents.num_entries = static_cast<uint32_t>(metadata->extents.size());
|
||||
metadata->header.groups.num_entries = static_cast<uint32_t>(metadata->groups.size());
|
||||
|
@ -531,7 +613,11 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
|
|||
}
|
||||
|
||||
uint64_t MetadataBuilder::AllocatableSpace() const {
|
||||
return super_device().size - (super_device().first_logical_sector * LP_SECTOR_SIZE);
|
||||
uint64_t total_size = 0;
|
||||
for (const auto& block_device : block_devices_) {
|
||||
total_size += block_device.size - (block_device.first_logical_sector * LP_SECTOR_SIZE);
|
||||
}
|
||||
return total_size;
|
||||
}
|
||||
|
||||
uint64_t MetadataBuilder::UsedSpace() const {
|
||||
|
@ -542,26 +628,58 @@ uint64_t MetadataBuilder::UsedSpace() const {
|
|||
return size;
|
||||
}
|
||||
|
||||
uint64_t MetadataBuilder::AlignSector(uint64_t sector) const {
|
||||
uint64_t MetadataBuilder::AlignSector(const LpMetadataBlockDevice& block_device,
|
||||
uint64_t sector) const {
|
||||
// Note: when reading alignment info from the Kernel, we don't assume it
|
||||
// is aligned to the sector size, so we round up to the nearest sector.
|
||||
uint64_t lba = sector * LP_SECTOR_SIZE;
|
||||
uint64_t aligned = AlignTo(lba, super_device().alignment, super_device().alignment_offset);
|
||||
uint64_t aligned = AlignTo(lba, block_device.alignment, block_device.alignment_offset);
|
||||
return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
bool MetadataBuilder::GetBlockDeviceInfo(BlockDeviceInfo* info) const {
|
||||
info->size = super_device().size;
|
||||
info->alignment = super_device().alignment;
|
||||
info->alignment_offset = super_device().alignment_offset;
|
||||
bool MetadataBuilder::FindBlockDeviceByName(const std::string& partition_name,
|
||||
uint32_t* index) const {
|
||||
for (size_t i = 0; i < block_devices_.size(); i++) {
|
||||
if (GetBlockDevicePartitionName(block_devices_[i]) == partition_name) {
|
||||
*index = i;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MetadataBuilder::GetBlockDeviceInfo(const std::string& partition_name,
|
||||
BlockDeviceInfo* info) const {
|
||||
uint32_t index;
|
||||
if (!FindBlockDeviceByName(partition_name, &index)) {
|
||||
LERROR << "No device named " << partition_name;
|
||||
return false;
|
||||
}
|
||||
info->size = block_devices_[index].size;
|
||||
info->alignment = block_devices_[index].alignment;
|
||||
info->alignment_offset = block_devices_[index].alignment_offset;
|
||||
info->logical_block_size = geometry_.logical_block_size;
|
||||
info->partition_name = partition_name;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) {
|
||||
if (device_info.size != super_device().size) {
|
||||
bool MetadataBuilder::UpdateBlockDeviceInfo(const std::string& partition_name,
|
||||
const BlockDeviceInfo& device_info) {
|
||||
uint32_t index;
|
||||
if (!FindBlockDeviceByName(partition_name, &index)) {
|
||||
LERROR << "No device named " << partition_name;
|
||||
return false;
|
||||
}
|
||||
return UpdateBlockDeviceInfo(index, device_info);
|
||||
}
|
||||
|
||||
bool MetadataBuilder::UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& device_info) {
|
||||
CHECK(index < block_devices_.size());
|
||||
|
||||
LpMetadataBlockDevice& block_device = block_devices_[index];
|
||||
if (device_info.size != block_device.size) {
|
||||
LERROR << "Device size does not match (got " << device_info.size << ", expected "
|
||||
<< super_device().size << ")";
|
||||
<< block_device.size << ")";
|
||||
return false;
|
||||
}
|
||||
if (device_info.logical_block_size != geometry_.logical_block_size) {
|
||||
|
@ -573,10 +691,10 @@ bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info)
|
|||
// The kernel does not guarantee these values are present, so we only
|
||||
// replace existing values if the new values are non-zero.
|
||||
if (device_info.alignment) {
|
||||
super_device().alignment = device_info.alignment;
|
||||
block_device.alignment = device_info.alignment;
|
||||
}
|
||||
if (device_info.alignment_offset) {
|
||||
super_device().alignment_offset = device_info.alignment_offset;
|
||||
block_device.alignment_offset = device_info.alignment_offset;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ using ::testing::ElementsAre;
|
|||
|
||||
TEST(liblp, BuildBasic) {
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
Partition* partition = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
|
||||
ASSERT_NE(partition, nullptr);
|
||||
|
@ -41,6 +42,7 @@ TEST(liblp, BuildBasic) {
|
|||
|
||||
TEST(liblp, ResizePartition) {
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
|
||||
ASSERT_NE(system, nullptr);
|
||||
|
@ -94,6 +96,7 @@ TEST(liblp, ResizePartition) {
|
|||
|
||||
TEST(liblp, PartitionAlignment) {
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1024, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
// Test that we align up to one sector.
|
||||
Partition* system = builder->AddPartition("system", LP_PARTITION_ATTR_READONLY);
|
||||
|
@ -120,6 +123,7 @@ TEST(liblp, DiskAlignment) {
|
|||
TEST(liblp, MetadataAlignment) {
|
||||
// Make sure metadata sizes get aligned up.
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(1024 * 1024, 1000, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
EXPECT_EQ(exported->geometry.metadata_max_size, 1024);
|
||||
|
@ -127,7 +131,7 @@ TEST(liblp, MetadataAlignment) {
|
|||
|
||||
TEST(liblp, InternalAlignment) {
|
||||
// Test the metadata fitting within alignment.
|
||||
BlockDeviceInfo device_info(1024 * 1024, 768 * 1024, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 768 * 1024, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
|
@ -174,7 +178,7 @@ TEST(liblp, InternalAlignment) {
|
|||
}
|
||||
|
||||
TEST(liblp, InternalPartitionAlignment) {
|
||||
BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664, 4096);
|
||||
BlockDeviceInfo device_info("super", 512 * 1024 * 1024, 768 * 1024, 753664, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
|
||||
|
||||
Partition* a = builder->AddPartition("a", 0);
|
||||
|
@ -394,7 +398,7 @@ TEST(liblp, MetadataTooLarge) {
|
|||
static const size_t kMetadataSize = 64 * 1024;
|
||||
|
||||
// No space to store metadata + geometry.
|
||||
BlockDeviceInfo device_info(kDiskSize, 0, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", kDiskSize, 0, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
|
||||
EXPECT_EQ(builder, nullptr);
|
||||
|
||||
|
@ -441,12 +445,12 @@ TEST(liblp, block_device_info) {
|
|||
}
|
||||
|
||||
TEST(liblp, UpdateBlockDeviceInfo) {
|
||||
BlockDeviceInfo device_info(1024 * 1024, 4096, 1024, 4096);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 4096, 1024, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
BlockDeviceInfo new_info;
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
|
||||
|
||||
EXPECT_EQ(new_info.size, device_info.size);
|
||||
EXPECT_EQ(new_info.alignment, device_info.alignment);
|
||||
|
@ -455,37 +459,37 @@ TEST(liblp, UpdateBlockDeviceInfo) {
|
|||
|
||||
device_info.alignment = 0;
|
||||
device_info.alignment_offset = 2048;
|
||||
ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
|
||||
ASSERT_TRUE(builder->UpdateBlockDeviceInfo("super", device_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
|
||||
EXPECT_EQ(new_info.alignment, 4096);
|
||||
EXPECT_EQ(new_info.alignment_offset, device_info.alignment_offset);
|
||||
|
||||
device_info.alignment = 8192;
|
||||
device_info.alignment_offset = 0;
|
||||
ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
|
||||
ASSERT_TRUE(builder->UpdateBlockDeviceInfo("super", device_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
|
||||
EXPECT_EQ(new_info.alignment, 8192);
|
||||
EXPECT_EQ(new_info.alignment_offset, 2048);
|
||||
|
||||
new_info.size += 4096;
|
||||
ASSERT_FALSE(builder->UpdateBlockDeviceInfo(new_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
|
||||
ASSERT_FALSE(builder->UpdateBlockDeviceInfo("super", new_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
|
||||
EXPECT_EQ(new_info.size, 1024 * 1024);
|
||||
|
||||
new_info.logical_block_size = 512;
|
||||
ASSERT_FALSE(builder->UpdateBlockDeviceInfo(new_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
|
||||
ASSERT_FALSE(builder->UpdateBlockDeviceInfo("super", new_info));
|
||||
ASSERT_TRUE(builder->GetBlockDeviceInfo("super", &new_info));
|
||||
EXPECT_EQ(new_info.logical_block_size, 4096);
|
||||
}
|
||||
|
||||
TEST(liblp, InvalidBlockSize) {
|
||||
BlockDeviceInfo device_info(1024 * 1024, 0, 0, 513);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 513);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
|
||||
EXPECT_EQ(builder, nullptr);
|
||||
}
|
||||
|
||||
TEST(liblp, AlignedExtentSize) {
|
||||
BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
|
@ -497,13 +501,13 @@ TEST(liblp, AlignedExtentSize) {
|
|||
|
||||
TEST(liblp, AlignedFreeSpace) {
|
||||
// Only one sector free - at least one block is required.
|
||||
BlockDeviceInfo device_info(10240, 0, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", 10240, 0, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 512, 1);
|
||||
ASSERT_EQ(builder, nullptr);
|
||||
}
|
||||
|
||||
TEST(liblp, HasDefaultGroup) {
|
||||
BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
|
@ -511,7 +515,7 @@ TEST(liblp, HasDefaultGroup) {
|
|||
}
|
||||
|
||||
TEST(liblp, GroupSizeLimits) {
|
||||
BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
|
@ -530,6 +534,9 @@ TEST(liblp, GroupSizeLimits) {
|
|||
constexpr unsigned long long operator"" _GiB(unsigned long long x) { // NOLINT
|
||||
return x << 30;
|
||||
}
|
||||
constexpr unsigned long long operator"" _MiB(unsigned long long x) { // NOLINT
|
||||
return x << 20;
|
||||
}
|
||||
|
||||
TEST(liblp, RemoveAndAddFirstPartition) {
|
||||
auto builder = MetadataBuilder::New(10_GiB, 65536, 2);
|
||||
|
@ -555,7 +562,7 @@ TEST(liblp, RemoveAndAddFirstPartition) {
|
|||
}
|
||||
|
||||
TEST(liblp, ListGroups) {
|
||||
BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
ASSERT_TRUE(builder->AddGroup("example", 0));
|
||||
|
@ -565,7 +572,7 @@ TEST(liblp, ListGroups) {
|
|||
}
|
||||
|
||||
TEST(liblp, RemoveGroupAndPartitions) {
|
||||
BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
|
||||
BlockDeviceInfo device_info("super", 1024 * 1024, 0, 0, 4096);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
ASSERT_TRUE(builder->AddGroup("example", 0));
|
||||
|
@ -580,3 +587,48 @@ TEST(liblp, RemoveGroupAndPartitions) {
|
|||
builder->RemoveGroupAndPartitions("default");
|
||||
ASSERT_NE(builder->FindPartition("system"), nullptr);
|
||||
}
|
||||
|
||||
TEST(liblp, MultipleBlockDevices) {
|
||||
std::vector<BlockDeviceInfo> partitions = {
|
||||
BlockDeviceInfo("system_a", 256_MiB, 786432, 229376, 4096),
|
||||
BlockDeviceInfo("vendor_a", 128_MiB, 786432, 753664, 4096),
|
||||
BlockDeviceInfo("product_a", 64_MiB, 786432, 753664, 4096),
|
||||
};
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(partitions, "system_a", 65536, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
EXPECT_EQ(builder->AllocatableSpace(), 467238912);
|
||||
|
||||
// Create a partition that spans 3 devices.
|
||||
Partition* p = builder->AddPartition("system_a", 0);
|
||||
ASSERT_NE(p, nullptr);
|
||||
ASSERT_TRUE(builder->ResizePartition(p, 466976768));
|
||||
|
||||
unique_ptr<LpMetadata> metadata = builder->Export();
|
||||
ASSERT_NE(metadata, nullptr);
|
||||
ASSERT_EQ(metadata->block_devices.size(), 3);
|
||||
EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[0]), "system_a");
|
||||
EXPECT_EQ(metadata->block_devices[0].size, 256_MiB);
|
||||
EXPECT_EQ(metadata->block_devices[0].alignment, 786432);
|
||||
EXPECT_EQ(metadata->block_devices[0].alignment_offset, 229376);
|
||||
EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[1]), "vendor_a");
|
||||
EXPECT_EQ(metadata->block_devices[1].size, 128_MiB);
|
||||
EXPECT_EQ(metadata->block_devices[1].alignment, 786432);
|
||||
EXPECT_EQ(metadata->block_devices[1].alignment_offset, 753664);
|
||||
EXPECT_EQ(GetBlockDevicePartitionName(metadata->block_devices[2]), "product_a");
|
||||
EXPECT_EQ(metadata->block_devices[2].size, 64_MiB);
|
||||
EXPECT_EQ(metadata->block_devices[2].alignment, 786432);
|
||||
EXPECT_EQ(metadata->block_devices[2].alignment_offset, 753664);
|
||||
ASSERT_EQ(metadata->extents.size(), 3);
|
||||
EXPECT_EQ(metadata->extents[0].num_sectors, 522304);
|
||||
EXPECT_EQ(metadata->extents[0].target_type, LP_TARGET_TYPE_LINEAR);
|
||||
EXPECT_EQ(metadata->extents[0].target_data, 1984);
|
||||
EXPECT_EQ(metadata->extents[0].target_source, 0);
|
||||
EXPECT_EQ(metadata->extents[1].num_sectors, 260672);
|
||||
EXPECT_EQ(metadata->extents[1].target_type, LP_TARGET_TYPE_LINEAR);
|
||||
EXPECT_EQ(metadata->extents[1].target_data, 1472);
|
||||
EXPECT_EQ(metadata->extents[1].target_source, 1);
|
||||
EXPECT_EQ(metadata->extents[2].num_sectors, 129088);
|
||||
EXPECT_EQ(metadata->extents[2].target_type, LP_TARGET_TYPE_LINEAR);
|
||||
EXPECT_EQ(metadata->extents[2].target_data, 1472);
|
||||
EXPECT_EQ(metadata->extents[2].target_source, 2);
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ class Extent {
|
|||
explicit Extent(uint64_t num_sectors) : num_sectors_(num_sectors) {}
|
||||
virtual ~Extent() {}
|
||||
|
||||
virtual void AddTo(LpMetadata* out) const = 0;
|
||||
virtual bool AddTo(LpMetadata* out) const = 0;
|
||||
virtual LinearExtent* AsLinearExtent() { return nullptr; }
|
||||
|
||||
uint64_t num_sectors() const { return num_sectors_; }
|
||||
|
@ -54,16 +54,18 @@ class Extent {
|
|||
// This corresponds to a dm-linear target.
|
||||
class LinearExtent final : public Extent {
|
||||
public:
|
||||
LinearExtent(uint64_t num_sectors, uint64_t physical_sector)
|
||||
: Extent(num_sectors), physical_sector_(physical_sector) {}
|
||||
LinearExtent(uint64_t num_sectors, uint32_t device_index, uint64_t physical_sector)
|
||||
: Extent(num_sectors), device_index_(device_index), physical_sector_(physical_sector) {}
|
||||
|
||||
void AddTo(LpMetadata* metadata) const override;
|
||||
bool AddTo(LpMetadata* metadata) const override;
|
||||
LinearExtent* AsLinearExtent() override { return this; }
|
||||
|
||||
uint64_t physical_sector() const { return physical_sector_; }
|
||||
uint64_t end_sector() const { return physical_sector_ + num_sectors_; }
|
||||
uint32_t device_index() const { return device_index_; }
|
||||
|
||||
private:
|
||||
uint32_t device_index_;
|
||||
uint64_t physical_sector_;
|
||||
};
|
||||
|
||||
|
@ -72,7 +74,7 @@ class ZeroExtent final : public Extent {
|
|||
public:
|
||||
explicit ZeroExtent(uint64_t num_sectors) : Extent(num_sectors) {}
|
||||
|
||||
void AddTo(LpMetadata* out) const override;
|
||||
bool AddTo(LpMetadata* out) const override;
|
||||
};
|
||||
|
||||
class PartitionGroup final {
|
||||
|
@ -122,15 +124,17 @@ class Partition final {
|
|||
|
||||
class MetadataBuilder {
|
||||
public:
|
||||
// Construct an empty logical partition table builder. The block device size
|
||||
// and maximum metadata size must be specified, as this will determine which
|
||||
// areas of the physical partition can be flashed for metadata vs for logical
|
||||
// partitions.
|
||||
// Construct an empty logical partition table builder given the specified
|
||||
// map of partitions that are available for storing logical partitions.
|
||||
//
|
||||
// At least one partition in the list must be the "super" device, where
|
||||
// metadata will be stored.
|
||||
//
|
||||
// If the parameters would yield invalid metadata, nullptr is returned. This
|
||||
// could happen if the block device size is too small to store the metadata
|
||||
// and backup copies.
|
||||
static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
|
||||
// could happen if the super device is too small to store all required
|
||||
// metadata.
|
||||
static std::unique_ptr<MetadataBuilder> New(const std::vector<BlockDeviceInfo>& block_devices,
|
||||
const std::string& super_partition,
|
||||
uint32_t metadata_max_size,
|
||||
uint32_t metadata_slot_count);
|
||||
|
||||
|
@ -150,11 +154,20 @@ class MetadataBuilder {
|
|||
// This method is for testing or changing off-line tables.
|
||||
static std::unique_ptr<MetadataBuilder> New(const LpMetadata& metadata);
|
||||
|
||||
// Helper function for a single super partition, for tests.
|
||||
static std::unique_ptr<MetadataBuilder> New(const BlockDeviceInfo& device_info,
|
||||
uint32_t metadata_max_size,
|
||||
uint32_t metadata_slot_count) {
|
||||
return New({device_info}, device_info.partition_name, metadata_max_size,
|
||||
metadata_slot_count);
|
||||
}
|
||||
|
||||
// Wrapper around New() with a BlockDeviceInfo that only specifies a device
|
||||
// size. This is a convenience method for tests.
|
||||
static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size,
|
||||
uint32_t metadata_slot_count) {
|
||||
BlockDeviceInfo device_info(blockdev_size, 0, 0, kDefaultBlockSize);
|
||||
BlockDeviceInfo device_info(LP_METADATA_DEFAULT_PARTITION_NAME, blockdev_size, 0, 0,
|
||||
kDefaultBlockSize);
|
||||
return New(device_info, metadata_max_size, metadata_slot_count);
|
||||
}
|
||||
|
||||
|
@ -209,8 +222,8 @@ class MetadataBuilder {
|
|||
// Remove all partitions belonging to a group, then remove the group.
|
||||
void RemoveGroupAndPartitions(const std::string& group_name);
|
||||
|
||||
bool GetBlockDeviceInfo(BlockDeviceInfo* info) const;
|
||||
bool UpdateBlockDeviceInfo(const BlockDeviceInfo& info);
|
||||
bool GetBlockDeviceInfo(const std::string& partition_name, BlockDeviceInfo* info) const;
|
||||
bool UpdateBlockDeviceInfo(const std::string& partition_name, const BlockDeviceInfo& info);
|
||||
|
||||
private:
|
||||
MetadataBuilder();
|
||||
|
@ -218,19 +231,27 @@ class MetadataBuilder {
|
|||
MetadataBuilder(MetadataBuilder&&) = delete;
|
||||
MetadataBuilder& operator=(const MetadataBuilder&) = delete;
|
||||
MetadataBuilder& operator=(MetadataBuilder&&) = delete;
|
||||
bool Init(const BlockDeviceInfo& info, uint32_t metadata_max_size, uint32_t metadata_slot_count);
|
||||
bool Init(const std::vector<BlockDeviceInfo>& block_devices, const std::string& super_partition,
|
||||
uint32_t metadata_max_size, uint32_t metadata_slot_count);
|
||||
bool Init(const LpMetadata& metadata);
|
||||
bool GrowPartition(Partition* partition, uint64_t aligned_size);
|
||||
void ShrinkPartition(Partition* partition, uint64_t aligned_size);
|
||||
uint64_t AlignSector(uint64_t sector) const;
|
||||
uint64_t AlignSector(const LpMetadataBlockDevice& device, uint64_t sector) const;
|
||||
uint64_t TotalSizeOfGroup(PartitionGroup* group) const;
|
||||
bool UpdateBlockDeviceInfo(size_t index, const BlockDeviceInfo& info);
|
||||
bool FindBlockDeviceByName(const std::string& partition_name, uint32_t* index) const;
|
||||
|
||||
struct Interval {
|
||||
uint32_t device_index;
|
||||
uint64_t start;
|
||||
uint64_t end;
|
||||
|
||||
Interval(uint64_t start, uint64_t end) : start(start), end(end) {}
|
||||
Interval(uint32_t device_index, uint64_t start, uint64_t end)
|
||||
: device_index(device_index), start(start), end(end) {}
|
||||
uint64_t length() const { return end - start; }
|
||||
|
||||
// Note: the device index is not included in sorting (intervals are
|
||||
// sorted in per-device lists).
|
||||
bool operator<(const Interval& other) const {
|
||||
return (start == other.start) ? end < other.end : start < other.start;
|
||||
}
|
||||
|
@ -239,9 +260,6 @@ class MetadataBuilder {
|
|||
void ExtentsToFreeList(const std::vector<Interval>& extents,
|
||||
std::vector<Interval>* free_regions) const;
|
||||
|
||||
const LpMetadataBlockDevice& super_device() const { return block_devices_[0]; }
|
||||
LpMetadataBlockDevice& super_device() { return block_devices_[0]; }
|
||||
|
||||
LpMetadataGeometry geometry_;
|
||||
LpMetadataHeader header_;
|
||||
std::vector<std::unique_ptr<Partition>> partitions_;
|
||||
|
|
|
@ -38,7 +38,7 @@ extern "C" {
|
|||
#define LP_METADATA_HEADER_MAGIC 0x414C5030
|
||||
|
||||
/* Current metadata version. */
|
||||
#define LP_METADATA_MAJOR_VERSION 7
|
||||
#define LP_METADATA_MAJOR_VERSION 8
|
||||
#define LP_METADATA_MINOR_VERSION 0
|
||||
|
||||
/* Attributes for the LpMetadataPartition::attributes field.
|
||||
|
@ -240,6 +240,13 @@ typedef struct LpMetadataExtent {
|
|||
* ZERO: This field must be 0.
|
||||
*/
|
||||
uint64_t target_data;
|
||||
|
||||
/* 20: Contents depends on target_type.
|
||||
*
|
||||
* LINEAR: Must be an index into the block devices table.
|
||||
* ZERO: This field must be 0.
|
||||
*/
|
||||
uint32_t target_source;
|
||||
} __attribute__((packed)) LpMetadataExtent;
|
||||
|
||||
/* This struct defines an entry in the groups table. Each group has a maximum
|
||||
|
@ -255,8 +262,9 @@ typedef struct LpMetadataPartitionGroup {
|
|||
uint64_t maximum_size;
|
||||
} LpMetadataPartitionGroup;
|
||||
|
||||
/* This struct defines an entry in the block_devices table. There must be
|
||||
* exactly one device, corresponding to the super partition.
|
||||
/* This struct defines an entry in the block_devices table. There must be at
|
||||
* least one device, and the first device must represent the partition holding
|
||||
* the super metadata.
|
||||
*/
|
||||
typedef struct LpMetadataBlockDevice {
|
||||
/* 0: First usable sector for allocating logical partitions. this will be
|
||||
|
|
|
@ -27,12 +27,13 @@ namespace fs_mgr {
|
|||
|
||||
struct BlockDeviceInfo {
|
||||
BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0), logical_block_size(0) {}
|
||||
BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset,
|
||||
uint32_t logical_block_size)
|
||||
BlockDeviceInfo(const std::string& partition_name, uint64_t size, uint32_t alignment,
|
||||
uint32_t alignment_offset, uint32_t logical_block_size)
|
||||
: size(size),
|
||||
alignment(alignment),
|
||||
alignment_offset(alignment_offset),
|
||||
logical_block_size(logical_block_size) {}
|
||||
logical_block_size(logical_block_size),
|
||||
partition_name(partition_name) {}
|
||||
// Size of the block device, in bytes.
|
||||
uint64_t size;
|
||||
// Optimal target alignment, in bytes. Partition extents will be aligned to
|
||||
|
@ -44,6 +45,9 @@ struct BlockDeviceInfo {
|
|||
uint32_t alignment_offset;
|
||||
// Block size, for aligning extent sizes and partition sizes.
|
||||
uint32_t logical_block_size;
|
||||
// The physical partition name for this block device, as it would appear in
|
||||
// the GPT or under /dev/block/by-name.
|
||||
std::string partition_name;
|
||||
};
|
||||
|
||||
// Test-friendly interface for interacting with partitions.
|
||||
|
|
|
@ -128,7 +128,7 @@ TEST(liblp, CreateFakeDisk) {
|
|||
// Flashing metadata should not work if the metadata was created for a larger
|
||||
// disk than the destination disk.
|
||||
TEST(liblp, ExportDiskTooSmall) {
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize + 1024, 512, 2);
|
||||
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(kDiskSize + 4096, 512, 2);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
|
@ -581,7 +581,7 @@ TEST(liblp, FlashSparseImage) {
|
|||
unique_fd fd = CreateFakeDisk();
|
||||
ASSERT_GE(fd, 0);
|
||||
|
||||
BlockDeviceInfo device_info(kDiskSize, 0, 0, 512);
|
||||
BlockDeviceInfo device_info("super", kDiskSize, 0, 0, 512);
|
||||
unique_ptr<MetadataBuilder> builder =
|
||||
MetadataBuilder::New(device_info, kMetadataSize, kMetadataSlots);
|
||||
ASSERT_NE(builder, nullptr);
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
||||
#include "utility.h"
|
||||
|
||||
namespace android {
|
||||
|
@ -68,6 +70,7 @@ bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device
|
|||
|
||||
device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
|
||||
device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
|
||||
device_info->partition_name = android::base::Basename(block_device);
|
||||
return true;
|
||||
#else
|
||||
(void)block_device;
|
||||
|
|
|
@ -274,6 +274,12 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
|
|||
memcpy(&extent, cursor, sizeof(extent));
|
||||
cursor += header.extents.entry_size;
|
||||
|
||||
if (extent.target_type == LP_TARGET_TYPE_LINEAR &&
|
||||
extent.target_source >= header.block_devices.num_entries) {
|
||||
LERROR << "Logical partition extent has invalid block device.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
metadata->extents.push_back(extent);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue