Merge "liblp: Store device information in a new block device table."
This commit is contained in:
commit
13e160e09f
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <sstream>
|
||||
|
||||
#include <android-base/file.h>
|
||||
#include <android-base/logging.h>
|
||||
#include <android-base/stringprintf.h>
|
||||
#include <android-base/strings.h>
|
||||
|
@ -50,8 +51,21 @@ using DmTarget = android::dm::DmTarget;
|
|||
using DmTargetZero = android::dm::DmTargetZero;
|
||||
using DmTargetLinear = android::dm::DmTargetLinear;
|
||||
|
||||
static bool CreateDmTable(const std::string& block_device, const LpMetadata& metadata,
|
||||
const LpMetadataPartition& partition, DmTable* table) {
|
||||
bool GetPhysicalPartitionDevicePath(const LpMetadataBlockDevice& block_device,
|
||||
std::string* result) {
|
||||
// Note: device-mapper will not accept symlinks, so we must use realpath
|
||||
// here.
|
||||
std::string name = GetBlockDevicePartitionName(block_device);
|
||||
std::string path = "/dev/block/by-name/" + name;
|
||||
if (!android::base::Realpath(path, result)) {
|
||||
PERROR << "realpath: " << path;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool CreateDmTable(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];
|
||||
|
@ -60,10 +74,22 @@ static bool CreateDmTable(const std::string& block_device, const LpMetadata& met
|
|||
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,
|
||||
case LP_TARGET_TYPE_LINEAR: {
|
||||
auto block_device = GetMetadataSuperBlockDevice(metadata);
|
||||
if (!block_device) {
|
||||
LOG(ERROR) << "Could not identify the super block device";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string path;
|
||||
if (!GetPhysicalPartitionDevicePath(*block_device, &path)) {
|
||||
LOG(ERROR) << "Unable to complete device-mapper table, unknown block device";
|
||||
return false;
|
||||
}
|
||||
target = std::make_unique<DmTargetLinear>(sector, extent.num_sectors, path,
|
||||
extent.target_data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(ERROR) << "Unknown target type in metadata: " << extent.target_type;
|
||||
return false;
|
||||
|
@ -79,13 +105,13 @@ static bool CreateDmTable(const std::string& block_device, const LpMetadata& met
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool CreateLogicalPartition(const std::string& block_device, const LpMetadata& metadata,
|
||||
const LpMetadataPartition& partition, bool force_writable,
|
||||
const std::chrono::milliseconds& timeout_ms, std::string* path) {
|
||||
static bool CreateLogicalPartition(const LpMetadata& metadata, const LpMetadataPartition& partition,
|
||||
bool force_writable, const std::chrono::milliseconds& timeout_ms,
|
||||
std::string* path) {
|
||||
DeviceMapper& dm = DeviceMapper::Instance();
|
||||
|
||||
DmTable table;
|
||||
if (!CreateDmTable(block_device, metadata, partition, &table)) {
|
||||
if (!CreateDmTable(metadata, partition, &table)) {
|
||||
return false;
|
||||
}
|
||||
if (force_writable) {
|
||||
|
@ -122,7 +148,7 @@ bool CreateLogicalPartitions(const std::string& block_device) {
|
|||
continue;
|
||||
}
|
||||
std::string path;
|
||||
if (!CreateLogicalPartition(block_device, *metadata.get(), partition, false, {}, &path)) {
|
||||
if (!CreateLogicalPartition(*metadata.get(), partition, false, {}, &path)) {
|
||||
LERROR << "Could not create logical partition: " << GetPartitionName(partition);
|
||||
return false;
|
||||
}
|
||||
|
@ -140,8 +166,8 @@ bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_s
|
|||
}
|
||||
for (const auto& partition : metadata->partitions) {
|
||||
if (GetPartitionName(partition) == partition_name) {
|
||||
return CreateLogicalPartition(block_device, *metadata.get(), partition, force_writable,
|
||||
timeout_ms, path);
|
||||
return CreateLogicalPartition(*metadata.get(), partition, force_writable, timeout_ms,
|
||||
path);
|
||||
}
|
||||
}
|
||||
LERROR << "Could not find any partition with name: " << partition_name;
|
||||
|
|
|
@ -186,6 +186,7 @@ MetadataBuilder::MetadataBuilder() {
|
|||
header_.partitions.entry_size = sizeof(LpMetadataPartition);
|
||||
header_.extents.entry_size = sizeof(LpMetadataExtent);
|
||||
header_.groups.entry_size = sizeof(LpMetadataPartitionGroup);
|
||||
header_.block_devices.entry_size = sizeof(LpMetadataBlockDevice);
|
||||
}
|
||||
|
||||
bool MetadataBuilder::Init(const LpMetadata& metadata) {
|
||||
|
@ -198,6 +199,10 @@ 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 =
|
||||
|
@ -259,9 +264,7 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
|
|||
// 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 reserved =
|
||||
LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
|
||||
uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved * 2;
|
||||
uint64_t total_reserved = GetTotalMetadataSize(metadata_max_size, metadata_slot_count);
|
||||
if (device_info.size < total_reserved) {
|
||||
LERROR << "Attempting to create metadata on a block device that is too small.";
|
||||
return false;
|
||||
|
@ -285,12 +288,16 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
|
|||
return false;
|
||||
}
|
||||
|
||||
geometry_.first_logical_sector = first_sector;
|
||||
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_.alignment = device_info.alignment;
|
||||
geometry_.alignment_offset = device_info.alignment_offset;
|
||||
geometry_.block_device_size = device_info.size;
|
||||
geometry_.logical_block_size = device_info.logical_block_size;
|
||||
|
||||
if (!AddGroup("default", 0)) {
|
||||
|
@ -408,9 +415,10 @@ auto MetadataBuilder::GetFreeRegions() const -> std::vector<Interval> {
|
|||
}
|
||||
|
||||
// Add 0-length intervals for the first and last sectors. This will cause
|
||||
// ExtentsToFreeList() to treat the space in between as available.
|
||||
uint64_t last_sector = geometry_.block_device_size / LP_SECTOR_SIZE;
|
||||
extents.emplace_back(geometry_.first_logical_sector, geometry_.first_logical_sector);
|
||||
// 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);
|
||||
|
||||
std::sort(extents.begin(), extents.end());
|
||||
|
@ -547,14 +555,18 @@ std::unique_ptr<LpMetadata> MetadataBuilder::Export() {
|
|||
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());
|
||||
metadata->header.block_devices.num_entries =
|
||||
static_cast<uint32_t>(metadata->block_devices.size());
|
||||
return metadata;
|
||||
}
|
||||
|
||||
uint64_t MetadataBuilder::AllocatableSpace() const {
|
||||
return geometry_.block_device_size - (geometry_.first_logical_sector * LP_SECTOR_SIZE);
|
||||
return super_device().size - (super_device().first_logical_sector * LP_SECTOR_SIZE);
|
||||
}
|
||||
|
||||
uint64_t MetadataBuilder::UsedSpace() const {
|
||||
|
@ -569,22 +581,22 @@ uint64_t MetadataBuilder::AlignSector(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, geometry_.alignment, geometry_.alignment_offset);
|
||||
uint64_t aligned = AlignTo(lba, super_device().alignment, super_device().alignment_offset);
|
||||
return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
|
||||
}
|
||||
|
||||
bool MetadataBuilder::GetBlockDeviceInfo(BlockDeviceInfo* info) const {
|
||||
info->size = geometry_.block_device_size;
|
||||
info->alignment = geometry_.alignment;
|
||||
info->alignment_offset = geometry_.alignment_offset;
|
||||
info->size = super_device().size;
|
||||
info->alignment = super_device().alignment;
|
||||
info->alignment_offset = super_device().alignment_offset;
|
||||
info->logical_block_size = geometry_.logical_block_size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) {
|
||||
if (device_info.size != geometry_.block_device_size) {
|
||||
if (device_info.size != super_device().size) {
|
||||
LERROR << "Device size does not match (got " << device_info.size << ", expected "
|
||||
<< geometry_.block_device_size << ")";
|
||||
<< super_device().size << ")";
|
||||
return false;
|
||||
}
|
||||
if (device_info.logical_block_size != geometry_.logical_block_size) {
|
||||
|
@ -596,10 +608,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) {
|
||||
geometry_.alignment = device_info.alignment;
|
||||
super_device().alignment = device_info.alignment;
|
||||
}
|
||||
if (device_info.alignment_offset) {
|
||||
geometry_.alignment_offset = device_info.alignment_offset;
|
||||
super_device().alignment_offset = device_info.alignment_offset;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -132,7 +132,9 @@ TEST(liblp, InternalAlignment) {
|
|||
ASSERT_NE(builder, nullptr);
|
||||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
|
||||
auto super_device = GetMetadataSuperBlockDevice(*exported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
EXPECT_EQ(super_device->first_logical_sector, 1536);
|
||||
|
||||
// Test a large alignment offset thrown in.
|
||||
device_info.alignment_offset = 753664;
|
||||
|
@ -140,7 +142,9 @@ TEST(liblp, InternalAlignment) {
|
|||
ASSERT_NE(builder, nullptr);
|
||||
exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
|
||||
super_device = GetMetadataSuperBlockDevice(*exported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
EXPECT_EQ(super_device->first_logical_sector, 1472);
|
||||
|
||||
// Alignment offset without alignment doesn't mean anything.
|
||||
device_info.alignment = 0;
|
||||
|
@ -154,7 +158,9 @@ TEST(liblp, InternalAlignment) {
|
|||
ASSERT_NE(builder, nullptr);
|
||||
exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
EXPECT_EQ(exported->geometry.first_logical_sector, 174);
|
||||
super_device = GetMetadataSuperBlockDevice(*exported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
EXPECT_EQ(super_device->first_logical_sector, 174);
|
||||
|
||||
// Test a small alignment with no alignment offset.
|
||||
device_info.alignment = 11 * 1024;
|
||||
|
@ -162,7 +168,9 @@ TEST(liblp, InternalAlignment) {
|
|||
ASSERT_NE(builder, nullptr);
|
||||
exported = builder->Export();
|
||||
ASSERT_NE(exported, nullptr);
|
||||
EXPECT_EQ(exported->geometry.first_logical_sector, 160);
|
||||
super_device = GetMetadataSuperBlockDevice(*exported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
EXPECT_EQ(super_device->first_logical_sector, 160);
|
||||
}
|
||||
|
||||
TEST(liblp, InternalPartitionAlignment) {
|
||||
|
@ -292,6 +300,9 @@ TEST(liblp, BuilderExport) {
|
|||
unique_ptr<LpMetadata> exported = builder->Export();
|
||||
EXPECT_NE(exported, nullptr);
|
||||
|
||||
auto super_device = GetMetadataSuperBlockDevice(*exported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
|
||||
// Verify geometry. Some details of this may change if we change the
|
||||
// metadata structures. So in addition to checking the exact values, we
|
||||
// also check that they are internally consistent after.
|
||||
|
@ -300,11 +311,11 @@ TEST(liblp, BuilderExport) {
|
|||
EXPECT_EQ(geometry.struct_size, sizeof(geometry));
|
||||
EXPECT_EQ(geometry.metadata_max_size, 1024);
|
||||
EXPECT_EQ(geometry.metadata_slot_count, 2);
|
||||
EXPECT_EQ(geometry.first_logical_sector, 32);
|
||||
EXPECT_EQ(super_device->first_logical_sector, 32);
|
||||
|
||||
static const size_t kMetadataSpace =
|
||||
((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
|
||||
EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace);
|
||||
EXPECT_GE(super_device->first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace);
|
||||
|
||||
// Verify header.
|
||||
const LpMetadataHeader& header = exported->header;
|
||||
|
|
|
@ -99,11 +99,12 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
|
|||
block_size_(block_size),
|
||||
file_(nullptr, sparse_file_destroy),
|
||||
images_(images) {
|
||||
uint64_t total_size = GetTotalSuperPartitionSize(metadata);
|
||||
if (block_size % LP_SECTOR_SIZE != 0) {
|
||||
LERROR << "Block size must be a multiple of the sector size, " << LP_SECTOR_SIZE;
|
||||
return;
|
||||
}
|
||||
if (metadata.geometry.block_device_size % block_size != 0) {
|
||||
if (total_size % block_size != 0) {
|
||||
LERROR << "Device size must be a multiple of the block size, " << block_size;
|
||||
return;
|
||||
}
|
||||
|
@ -120,7 +121,7 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
|
|||
return;
|
||||
}
|
||||
|
||||
uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
|
||||
uint64_t num_blocks = total_size % block_size;
|
||||
if (num_blocks >= UINT_MAX) {
|
||||
// libsparse counts blocks in unsigned 32-bit integers, so we check to
|
||||
// make sure we're not going to overflow.
|
||||
|
@ -128,7 +129,10 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
|
|||
return;
|
||||
}
|
||||
|
||||
file_.reset(sparse_file_new(block_size_, geometry_.block_device_size));
|
||||
file_.reset(sparse_file_new(block_size_, total_size));
|
||||
if (!file_) {
|
||||
LERROR << "Could not allocate sparse file of size " << total_size;
|
||||
}
|
||||
}
|
||||
|
||||
bool SparseBuilder::Export(const char* file) {
|
||||
|
@ -333,14 +337,7 @@ int SparseBuilder::OpenImageFile(const std::string& file) {
|
|||
bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size,
|
||||
const std::map<std::string, std::string>& images) {
|
||||
SparseBuilder builder(metadata, block_size, images);
|
||||
if (!builder.IsValid()) {
|
||||
LERROR << "Could not allocate sparse file of size " << metadata.geometry.block_device_size;
|
||||
return false;
|
||||
}
|
||||
if (!builder.Build()) {
|
||||
return false;
|
||||
}
|
||||
return builder.Export(file);
|
||||
return builder.IsValid() && builder.Build() && builder.Export(file);
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
|
|
|
@ -254,10 +254,14 @@ 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_;
|
||||
std::vector<std::unique_ptr<PartitionGroup>> groups_;
|
||||
std::vector<LpMetadataBlockDevice> block_devices_;
|
||||
};
|
||||
|
||||
// Read BlockDeviceInfo for a given block device. This always returns false
|
||||
|
|
|
@ -37,6 +37,7 @@ struct LpMetadata {
|
|||
std::vector<LpMetadataPartition> partitions;
|
||||
std::vector<LpMetadataExtent> extents;
|
||||
std::vector<LpMetadataPartitionGroup> groups;
|
||||
std::vector<LpMetadataBlockDevice> block_devices;
|
||||
};
|
||||
|
||||
// Place an initial partition table on the device. This will overwrite the
|
||||
|
@ -69,6 +70,14 @@ std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes);
|
|||
// Helper to extract safe C++ strings from partition info.
|
||||
std::string GetPartitionName(const LpMetadataPartition& partition);
|
||||
std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group);
|
||||
std::string GetBlockDevicePartitionName(const LpMetadataBlockDevice& block_device);
|
||||
|
||||
// Return the block device that houses the super partition metadata; returns
|
||||
// null on failure.
|
||||
const LpMetadataBlockDevice* GetMetadataSuperBlockDevice(const LpMetadata& metadata);
|
||||
|
||||
// Return the total size of all partitions comprising the super partition.
|
||||
uint64_t GetTotalSuperPartitionSize(const LpMetadata& metadata);
|
||||
|
||||
// Helper to return a slot number for a slot suffix.
|
||||
uint32_t SlotNumberForSlotSuffix(const std::string& suffix);
|
||||
|
|
|
@ -38,7 +38,7 @@ extern "C" {
|
|||
#define LP_METADATA_HEADER_MAGIC 0x414C5030
|
||||
|
||||
/* Current metadata version. */
|
||||
#define LP_METADATA_MAJOR_VERSION 6
|
||||
#define LP_METADATA_MAJOR_VERSION 7
|
||||
#define LP_METADATA_MINOR_VERSION 0
|
||||
|
||||
/* Attributes for the LpMetadataPartition::attributes field.
|
||||
|
@ -103,42 +103,10 @@ typedef struct LpMetadataGeometry {
|
|||
*/
|
||||
uint32_t metadata_slot_count;
|
||||
|
||||
/* 48: First usable sector for allocating logical partitions. this will be
|
||||
* the first sector after the initial geometry blocks, followed by the
|
||||
* space consumed by metadata_max_size*metadata_slot_count*2.
|
||||
*/
|
||||
uint64_t first_logical_sector;
|
||||
|
||||
/* 64: Alignment for defining partitions or partition extents. For example,
|
||||
* an alignment of 1MiB will require that all partitions have a size evenly
|
||||
* divisible by 1MiB, and that the smallest unit the partition can grow by
|
||||
* is 1MiB.
|
||||
*
|
||||
* Alignment is normally determined at runtime when growing or adding
|
||||
* partitions. If for some reason the alignment cannot be determined, then
|
||||
* this predefined alignment in the geometry is used instead. By default
|
||||
* it is set to 1MiB.
|
||||
*/
|
||||
uint32_t alignment;
|
||||
|
||||
/* 68: Alignment offset for "stacked" devices. For example, if the "super"
|
||||
* partition itself is not aligned within the parent block device's
|
||||
* partition table, then we adjust for this in deciding where to place
|
||||
* |first_logical_sector|.
|
||||
*
|
||||
* Similar to |alignment|, this will be derived from the operating system.
|
||||
* If it cannot be determined, it is assumed to be 0.
|
||||
*/
|
||||
uint32_t alignment_offset;
|
||||
|
||||
/* 72: Block device size, as specified when the metadata was created. This
|
||||
* can be used to verify the geometry against a target device.
|
||||
*/
|
||||
uint64_t block_device_size;
|
||||
|
||||
/* 76: Logical block size of the super partition block device. This is the
|
||||
* minimal alignment for partition and extent sizes, and it must be a
|
||||
* multiple of LP_SECTOR_SIZE.
|
||||
/* 48: Logical block size. This is the minimal alignment for partition and
|
||||
* extent sizes, and it must be a multiple of LP_SECTOR_SIZE. Note that
|
||||
* this must be equal across all LUNs that comprise the super partition,
|
||||
* and thus this field is stored in the geometry, not per-device.
|
||||
*/
|
||||
uint32_t logical_block_size;
|
||||
} __attribute__((packed)) LpMetadataGeometry;
|
||||
|
@ -217,6 +185,8 @@ typedef struct LpMetadataHeader {
|
|||
LpMetadataTableDescriptor extents;
|
||||
/* 104: Updateable group descriptor. */
|
||||
LpMetadataTableDescriptor groups;
|
||||
/* 116: Block device table. */
|
||||
LpMetadataTableDescriptor block_devices;
|
||||
} __attribute__((packed)) LpMetadataHeader;
|
||||
|
||||
/* This struct defines a logical partition entry, similar to what would be
|
||||
|
@ -285,6 +255,47 @@ 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.
|
||||
*/
|
||||
typedef struct LpMetadataBlockDevice {
|
||||
/* 0: First usable sector for allocating logical partitions. this will be
|
||||
* the first sector after the initial geometry blocks, followed by the
|
||||
* space consumed by metadata_max_size*metadata_slot_count*2.
|
||||
*/
|
||||
uint64_t first_logical_sector;
|
||||
|
||||
/* 8: Alignment for defining partitions or partition extents. For example,
|
||||
* an alignment of 1MiB will require that all partitions have a size evenly
|
||||
* divisible by 1MiB, and that the smallest unit the partition can grow by
|
||||
* is 1MiB.
|
||||
*
|
||||
* Alignment is normally determined at runtime when growing or adding
|
||||
* partitions. If for some reason the alignment cannot be determined, then
|
||||
* this predefined alignment in the geometry is used instead. By default
|
||||
* it is set to 1MiB.
|
||||
*/
|
||||
uint32_t alignment;
|
||||
|
||||
/* 12: Alignment offset for "stacked" devices. For example, if the "super"
|
||||
* partition itself is not aligned within the parent block device's
|
||||
* partition table, then we adjust for this in deciding where to place
|
||||
* |first_logical_sector|.
|
||||
*
|
||||
* Similar to |alignment|, this will be derived from the operating system.
|
||||
* If it cannot be determined, it is assumed to be 0.
|
||||
*/
|
||||
uint32_t alignment_offset;
|
||||
|
||||
/* 16: Block device size, as specified when the metadata was created. This
|
||||
* can be used to verify the geometry against a target device.
|
||||
*/
|
||||
uint64_t size;
|
||||
|
||||
/* 24: Partition name in the GPT. Any unused characters must be 0. */
|
||||
char partition_name[36];
|
||||
} LpMetadataBlockDevice;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
|
|
@ -160,7 +160,6 @@ TEST(liblp, FlashAndReadback) {
|
|||
// Check geometry and header.
|
||||
EXPECT_EQ(exported->geometry.metadata_max_size, imported->geometry.metadata_max_size);
|
||||
EXPECT_EQ(exported->geometry.metadata_slot_count, imported->geometry.metadata_slot_count);
|
||||
EXPECT_EQ(exported->geometry.first_logical_sector, imported->geometry.first_logical_sector);
|
||||
EXPECT_EQ(exported->header.major_version, imported->header.major_version);
|
||||
EXPECT_EQ(exported->header.minor_version, imported->header.minor_version);
|
||||
EXPECT_EQ(exported->header.header_size, imported->header.header_size);
|
||||
|
@ -178,6 +177,11 @@ TEST(liblp, FlashAndReadback) {
|
|||
EXPECT_EQ(exported->extents[0].num_sectors, imported->extents[0].num_sectors);
|
||||
EXPECT_EQ(exported->extents[0].target_type, imported->extents[0].target_type);
|
||||
EXPECT_EQ(exported->extents[0].target_data, imported->extents[0].target_data);
|
||||
|
||||
// Check block devices table.
|
||||
ASSERT_EQ(exported->block_devices.size(), imported->block_devices.size());
|
||||
EXPECT_EQ(exported->block_devices[0].first_logical_sector,
|
||||
imported->block_devices[0].first_logical_sector);
|
||||
}
|
||||
|
||||
// Test that we can update metadata slots without disturbing others.
|
||||
|
@ -206,14 +210,17 @@ TEST(liblp, UpdateAnyMetadataSlot) {
|
|||
ASSERT_EQ(imported->partitions.size(), 1);
|
||||
EXPECT_EQ(GetPartitionName(imported->partitions[0]), "vendor");
|
||||
|
||||
uint64_t last_sector = imported->geometry.block_device_size / LP_SECTOR_SIZE;
|
||||
auto super_device = GetMetadataSuperBlockDevice(*imported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
|
||||
uint64_t last_sector = super_device->size / LP_SECTOR_SIZE;
|
||||
|
||||
// Verify that we didn't overwrite anything in the logical paritition area.
|
||||
// We expect the disk to be filled with 0xcc on creation so we can read
|
||||
// this back and compare it.
|
||||
char expected[LP_SECTOR_SIZE];
|
||||
memset(expected, 0xcc, sizeof(expected));
|
||||
for (uint64_t i = imported->geometry.first_logical_sector; i < last_sector; i++) {
|
||||
for (uint64_t i = super_device->first_logical_sector; i < last_sector; i++) {
|
||||
char buffer[LP_SECTOR_SIZE];
|
||||
ASSERT_GE(lseek(fd, i * LP_SECTOR_SIZE, SEEK_SET), 0);
|
||||
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
|
||||
|
@ -256,7 +263,8 @@ TEST(liblp, NoChangingGeometry) {
|
|||
|
||||
imported = ReadMetadata(fd, 0);
|
||||
ASSERT_NE(imported, nullptr);
|
||||
imported->geometry.first_logical_sector++;
|
||||
ASSERT_EQ(imported->block_devices.size(), 1);
|
||||
imported->block_devices[0].first_logical_sector++;
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *imported.get(), 1));
|
||||
|
||||
imported = ReadMetadata(fd, 0);
|
||||
|
@ -329,9 +337,11 @@ TEST(liblp, TooManyPartitions) {
|
|||
ASSERT_NE(builder, nullptr);
|
||||
|
||||
// Compute the maximum number of partitions we can fit in 512 bytes of
|
||||
// metadata. By default there is the header, and one partition group.
|
||||
static const size_t kMaxPartitionTableSize =
|
||||
kMetadataSize - sizeof(LpMetadataHeader) - sizeof(LpMetadataPartitionGroup);
|
||||
// metadata. By default there is the header, one partition group, and a
|
||||
// block device entry.
|
||||
static const size_t kMaxPartitionTableSize = kMetadataSize - sizeof(LpMetadataHeader) -
|
||||
sizeof(LpMetadataPartitionGroup) -
|
||||
sizeof(LpMetadataBlockDevice);
|
||||
size_t max_partitions = kMaxPartitionTableSize / sizeof(LpMetadataPartition);
|
||||
|
||||
// Add this number of partitions.
|
||||
|
@ -360,12 +370,15 @@ TEST(liblp, TooManyPartitions) {
|
|||
// The new table should be too large to be written.
|
||||
ASSERT_FALSE(UpdatePartitionTable(fd, *exported.get(), 1));
|
||||
|
||||
auto super_device = GetMetadataSuperBlockDevice(*exported.get());
|
||||
ASSERT_NE(super_device, nullptr);
|
||||
|
||||
// Check that the first and last logical sectors weren't touched when we
|
||||
// wrote this almost-full metadata.
|
||||
char expected[LP_SECTOR_SIZE];
|
||||
memset(expected, 0xcc, sizeof(expected));
|
||||
char buffer[LP_SECTOR_SIZE];
|
||||
ASSERT_GE(lseek(fd, exported->geometry.first_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
|
||||
ASSERT_GE(lseek(fd, super_device->first_logical_sector * LP_SECTOR_SIZE, SEEK_SET), 0);
|
||||
ASSERT_TRUE(android::base::ReadFully(fd, buffer, sizeof(buffer)));
|
||||
EXPECT_EQ(memcmp(expected, buffer, LP_SECTOR_SIZE), 0);
|
||||
}
|
||||
|
|
|
@ -108,15 +108,6 @@ bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
|
|||
LERROR << "Metadata max size is not sector-aligned.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that the metadata area and logical partition areas don't overlap.
|
||||
int64_t end_of_metadata =
|
||||
GetPrimaryMetadataOffset(*geometry, geometry->metadata_slot_count - 1) +
|
||||
geometry->metadata_max_size;
|
||||
if (uint64_t(end_of_metadata) > geometry->first_logical_sector * LP_SECTOR_SIZE) {
|
||||
LERROR << "Logical partition metadata overlaps with logical partition contents.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -195,7 +186,8 @@ static bool ValidateMetadataHeader(const LpMetadataHeader& header) {
|
|||
}
|
||||
if (!ValidateTableBounds(header, header.partitions) ||
|
||||
!ValidateTableBounds(header, header.extents) ||
|
||||
!ValidateTableBounds(header, header.groups)) {
|
||||
!ValidateTableBounds(header, header.groups) ||
|
||||
!ValidateTableBounds(header, header.block_devices)) {
|
||||
LERROR << "Logical partition metadata has invalid table bounds.";
|
||||
return false;
|
||||
}
|
||||
|
@ -294,6 +286,28 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
|
|||
metadata->groups.push_back(group);
|
||||
}
|
||||
|
||||
cursor = buffer.get() + header.block_devices.offset;
|
||||
for (size_t i = 0; i < header.block_devices.num_entries; i++) {
|
||||
LpMetadataBlockDevice device = {};
|
||||
memcpy(&device, cursor, sizeof(device));
|
||||
cursor += header.block_devices.entry_size;
|
||||
|
||||
metadata->block_devices.push_back(device);
|
||||
}
|
||||
|
||||
const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(*metadata.get());
|
||||
if (!super_device) {
|
||||
LERROR << "Metadata does not specify a super device.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Check that the metadata area and logical partition areas don't overlap.
|
||||
uint64_t metadata_region =
|
||||
GetTotalMetadataSize(geometry.metadata_max_size, geometry.metadata_slot_count);
|
||||
if (metadata_region > super_device->first_logical_sector * LP_SECTOR_SIZE) {
|
||||
LERROR << "Logical partition metadata overlaps with logical partition contents.";
|
||||
return nullptr;
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
|
@ -374,5 +388,9 @@ std::string GetPartitionGroupName(const LpMetadataPartitionGroup& group) {
|
|||
return NameFromFixedArray(group.name, sizeof(group.name));
|
||||
}
|
||||
|
||||
std::string GetBlockDevicePartitionName(const LpMetadataBlockDevice& block_device) {
|
||||
return NameFromFixedArray(block_device.partition_name, sizeof(block_device.partition_name));
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
|
|
@ -66,11 +66,8 @@ int64_t GetBackupGeometryOffset() {
|
|||
|
||||
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
|
||||
CHECK(slot_number < geometry.metadata_slot_count);
|
||||
|
||||
int64_t offset = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
|
||||
geometry.metadata_max_size * slot_number;
|
||||
CHECK(offset + geometry.metadata_max_size <=
|
||||
int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE));
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
@ -81,6 +78,18 @@ int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slo
|
|||
return start + int64_t(geometry.metadata_max_size * slot_number);
|
||||
}
|
||||
|
||||
uint64_t GetTotalMetadataSize(uint32_t metadata_max_size, uint32_t max_slots) {
|
||||
return LP_PARTITION_RESERVED_BYTES +
|
||||
(LP_METADATA_GEOMETRY_SIZE + metadata_max_size * max_slots) * 2;
|
||||
}
|
||||
|
||||
const LpMetadataBlockDevice* GetMetadataSuperBlockDevice(const LpMetadata& metadata) {
|
||||
if (metadata.block_devices.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
return &metadata.block_devices[0];
|
||||
}
|
||||
|
||||
void SHA256(const void* data, size_t length, uint8_t out[32]) {
|
||||
SHA256_CTX c;
|
||||
SHA256_Init(&c);
|
||||
|
@ -100,5 +109,13 @@ uint32_t SlotNumberForSlotSuffix(const std::string& suffix) {
|
|||
return suffix[1] - 'a';
|
||||
}
|
||||
|
||||
uint64_t GetTotalSuperPartitionSize(const LpMetadata& metadata) {
|
||||
uint64_t size = 0;
|
||||
for (const auto& block_device : metadata.block_devices) {
|
||||
size += block_device.size;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
} // namespace fs_mgr
|
||||
} // namespace android
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
#include <android-base/logging.h>
|
||||
|
||||
#include "liblp/metadata_format.h"
|
||||
#include "liblp/liblp.h"
|
||||
|
||||
#define LP_TAG "[liblp]"
|
||||
#define LWARN LOG(WARNING) << LP_TAG
|
||||
|
@ -50,6 +50,10 @@ int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t sl
|
|||
// device.
|
||||
int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number);
|
||||
|
||||
// Return the total space at the start of the super partition that must be set
|
||||
// aside from headers/metadata and backups.
|
||||
uint64_t GetTotalMetadataSize(uint32_t metadata_max_size, uint32_t max_slots);
|
||||
|
||||
// Cross-platform helper for lseek64().
|
||||
int64_t SeekFile64(int fd, int64_t offset, int whence);
|
||||
|
||||
|
|
|
@ -36,10 +36,6 @@ TEST(liblp, GetMetadataOffset) {
|
|||
{0},
|
||||
16384,
|
||||
4,
|
||||
10000,
|
||||
0,
|
||||
0,
|
||||
1024 * 1024,
|
||||
4096};
|
||||
static const uint64_t start = LP_PARTITION_RESERVED_BYTES;
|
||||
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), start + 8192);
|
||||
|
|
|
@ -43,9 +43,7 @@ std::string SerializeGeometry(const LpMetadataGeometry& input) {
|
|||
static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) {
|
||||
return g1.metadata_max_size == g2.metadata_max_size &&
|
||||
g1.metadata_slot_count == g2.metadata_slot_count &&
|
||||
g1.block_device_size == g2.block_device_size &&
|
||||
g1.logical_block_size == g2.logical_block_size &&
|
||||
g1.first_logical_sector == g2.first_logical_sector;
|
||||
g1.logical_block_size == g2.logical_block_size;
|
||||
}
|
||||
|
||||
std::string SerializeMetadata(const LpMetadata& input) {
|
||||
|
@ -59,15 +57,18 @@ std::string SerializeMetadata(const LpMetadata& input) {
|
|||
metadata.extents.size() * sizeof(LpMetadataExtent));
|
||||
std::string groups(reinterpret_cast<const char*>(metadata.groups.data()),
|
||||
metadata.groups.size() * sizeof(LpMetadataPartitionGroup));
|
||||
std::string block_devices(reinterpret_cast<const char*>(metadata.block_devices.data()),
|
||||
metadata.block_devices.size() * sizeof(LpMetadataBlockDevice));
|
||||
|
||||
// Compute positions of tables.
|
||||
header.partitions.offset = 0;
|
||||
header.extents.offset = header.partitions.offset + partitions.size();
|
||||
header.groups.offset = header.extents.offset + extents.size();
|
||||
header.tables_size = header.groups.offset + groups.size();
|
||||
header.block_devices.offset = header.groups.offset + groups.size();
|
||||
header.tables_size = header.block_devices.offset + block_devices.size();
|
||||
|
||||
// Compute payload checksum.
|
||||
std::string tables = partitions + extents + groups;
|
||||
std::string tables = partitions + extents + groups + block_devices;
|
||||
SHA256(tables.data(), tables.size(), header.tables_checksum);
|
||||
|
||||
// Compute header checksum.
|
||||
|
@ -105,14 +106,20 @@ static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std
|
|||
uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
|
||||
uint64_t total_reserved = reserved_size * 2;
|
||||
|
||||
const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(metadata);
|
||||
if (!super_device) {
|
||||
LERROR << "Logical partition metadata does not have a super block device.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (total_reserved > blockdevice_size ||
|
||||
total_reserved > geometry.first_logical_sector * LP_SECTOR_SIZE) {
|
||||
total_reserved > super_device->first_logical_sector * LP_SECTOR_SIZE) {
|
||||
LERROR << "Not enough space to store all logical partition metadata slots.";
|
||||
return false;
|
||||
}
|
||||
if (blockdevice_size != metadata.geometry.block_device_size) {
|
||||
if (blockdevice_size != super_device->size) {
|
||||
LERROR << "Block device size " << blockdevice_size
|
||||
<< " does not match metadata requested size " << metadata.geometry.block_device_size;
|
||||
<< " does not match metadata requested size " << super_device->size;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -125,11 +132,11 @@ static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std
|
|||
}
|
||||
|
||||
// Make sure all linear extents have a valid range.
|
||||
uint64_t last_sector = geometry.block_device_size / LP_SECTOR_SIZE;
|
||||
uint64_t last_sector = super_device->size / LP_SECTOR_SIZE;
|
||||
for (const auto& extent : metadata.extents) {
|
||||
if (extent.target_type == LP_TARGET_TYPE_LINEAR) {
|
||||
uint64_t physical_sector = extent.target_data;
|
||||
if (physical_sector < geometry.first_logical_sector ||
|
||||
if (physical_sector < super_device->first_logical_sector ||
|
||||
physical_sector + extent.num_sectors > last_sector) {
|
||||
LERROR << "Extent table entry is out of bounds.";
|
||||
return false;
|
||||
|
@ -139,10 +146,28 @@ static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool WritePrimaryMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
|
||||
// Check that the given region is within metadata bounds.
|
||||
static bool ValidateMetadataRegion(const LpMetadata& metadata, uint64_t start, size_t size) {
|
||||
const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(metadata);
|
||||
if (!super_device) {
|
||||
LERROR << __PRETTY_FUNCTION__ << " could not locate super block device in metadata";
|
||||
return false;
|
||||
}
|
||||
if (start + size >= super_device->first_logical_sector * LP_SECTOR_SIZE) {
|
||||
LERROR << __PRETTY_FUNCTION__ << " write of " << size << " bytes at " << start
|
||||
<< " overlaps with logical partition contents";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool WritePrimaryMetadata(int fd, const LpMetadata& metadata, uint32_t slot_number,
|
||||
const std::string& blob,
|
||||
const std::function<bool(int, const std::string&)>& writer) {
|
||||
int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number);
|
||||
int64_t primary_offset = GetPrimaryMetadataOffset(metadata.geometry, slot_number);
|
||||
if (!ValidateMetadataRegion(metadata, primary_offset, blob.size())) {
|
||||
return false;
|
||||
}
|
||||
if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << primary_offset;
|
||||
return false;
|
||||
|
@ -154,18 +179,15 @@ static bool WritePrimaryMetadata(int fd, const LpMetadataGeometry& geometry, uin
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool WriteBackupMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
|
||||
static bool WriteBackupMetadata(int fd, const LpMetadata& metadata, uint32_t slot_number,
|
||||
const std::string& blob,
|
||||
const std::function<bool(int, const std::string&)>& writer) {
|
||||
int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
|
||||
int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET);
|
||||
if (abs_offset == (int64_t)-1) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << backup_offset;
|
||||
int64_t backup_offset = GetBackupMetadataOffset(metadata.geometry, slot_number);
|
||||
if (!ValidateMetadataRegion(metadata, backup_offset, blob.size())) {
|
||||
return false;
|
||||
}
|
||||
if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " backup offset " << abs_offset
|
||||
<< " is within logical partition bounds, sector " << geometry.first_logical_sector;
|
||||
if (SeekFile64(fd, backup_offset, SEEK_SET) < 0) {
|
||||
PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << backup_offset;
|
||||
return false;
|
||||
}
|
||||
if (!writer(fd, blob)) {
|
||||
|
@ -175,18 +197,18 @@ static bool WriteBackupMetadata(int fd, const LpMetadataGeometry& geometry, uint
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool WriteMetadata(int fd, const LpMetadataGeometry& geometry, uint32_t slot_number,
|
||||
static bool WriteMetadata(int fd, const LpMetadata& metadata, uint32_t slot_number,
|
||||
const std::string& blob,
|
||||
const std::function<bool(int, const std::string&)>& writer) {
|
||||
// Make sure we're writing to a valid metadata slot.
|
||||
if (slot_number >= geometry.metadata_slot_count) {
|
||||
if (slot_number >= metadata.geometry.metadata_slot_count) {
|
||||
LERROR << "Invalid logical partition metadata slot number.";
|
||||
return false;
|
||||
}
|
||||
if (!WritePrimaryMetadata(fd, geometry, slot_number, blob, writer)) {
|
||||
if (!WritePrimaryMetadata(fd, metadata, slot_number, blob, writer)) {
|
||||
return false;
|
||||
}
|
||||
if (!WriteBackupMetadata(fd, geometry, slot_number, blob, writer)) {
|
||||
if (!WriteBackupMetadata(fd, metadata, slot_number, blob, writer)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -237,7 +259,7 @@ bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
|
|||
|
||||
bool ok = true;
|
||||
for (size_t i = 0; i < metadata.geometry.metadata_slot_count; i++) {
|
||||
ok &= WriteMetadata(fd, metadata.geometry, i, metadata_blob, DefaultWriter);
|
||||
ok &= WriteMetadata(fd, metadata, i, metadata_blob, DefaultWriter);
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
@ -289,7 +311,7 @@ bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_numb
|
|||
LERROR << "Error serializing primary metadata to repair corrupted backup";
|
||||
return false;
|
||||
}
|
||||
if (!WriteBackupMetadata(fd, geometry, slot_number, old_blob, writer)) {
|
||||
if (!WriteBackupMetadata(fd, metadata, slot_number, old_blob, writer)) {
|
||||
LERROR << "Error writing primary metadata to repair corrupted backup";
|
||||
return false;
|
||||
}
|
||||
|
@ -301,14 +323,14 @@ bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_numb
|
|||
LERROR << "Error serializing primary metadata to repair corrupted backup";
|
||||
return false;
|
||||
}
|
||||
if (!WritePrimaryMetadata(fd, geometry, slot_number, old_blob, writer)) {
|
||||
if (!WritePrimaryMetadata(fd, metadata, slot_number, old_blob, writer)) {
|
||||
LERROR << "Error writing primary metadata to repair corrupted backup";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Both copies should now be in sync, so we can continue the update.
|
||||
return WriteMetadata(fd, geometry, slot_number, blob, writer);
|
||||
return WriteMetadata(fd, metadata, slot_number, blob, writer);
|
||||
}
|
||||
|
||||
bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata) {
|
||||
|
|
Loading…
Reference in New Issue