Merge changes Ib244a98f,Ib173f251

am: 0730260a6a

Change-Id: Icc596f4928e1855d850445014064e3d65e47825a
This commit is contained in:
David Anderson 2018-10-12 13:41:38 -07:00 committed by android-build-merger
commit 612c390937
12 changed files with 140 additions and 126 deletions

View file

@ -150,7 +150,7 @@ std::unique_ptr<MetadataBuilder> MetadataBuilder::New(const std::string& block_d
}
BlockDeviceInfo device_info;
if (fs_mgr::GetBlockDeviceInfo(block_device, &device_info)) {
builder->set_block_device_info(device_info);
builder->UpdateBlockDeviceInfo(device_info);
}
return builder;
}
@ -217,10 +217,6 @@ bool MetadataBuilder::Init(const LpMetadata& metadata) {
}
}
}
device_info_.alignment = geometry_.alignment;
device_info_.alignment_offset = geometry_.alignment_offset;
device_info_.logical_block_size = geometry_.logical_block_size;
return true;
}
@ -239,24 +235,23 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
metadata_max_size = AlignTo(metadata_max_size, LP_SECTOR_SIZE);
// Check that device properties are sane.
device_info_ = device_info;
if (device_info_.size % LP_SECTOR_SIZE != 0) {
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) {
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) {
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) {
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) {
if (device_info.alignment_offset > device_info.alignment) {
LERROR << "Partition alignment offset is greater than its alignment.";
return false;
}
@ -267,20 +262,21 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
uint64_t reserved =
LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
uint64_t total_reserved = reserved * 2;
if (device_info_.size < total_reserved) {
if (device_info.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 = AlignTo(reserved, device_info_.alignment, device_info_.alignment_offset);
uint64_t free_area =
AlignTo(total_reserved, device_info.alignment, device_info.alignment_offset);
uint64_t first_sector = free_area / LP_SECTOR_SIZE;
// Compute the last free sector, which is inclusive. We subtract 1 to make
// sure that logical partitions won't overlap with the same sector as the
// backup metadata, which could happen if the block device was not aligned
// to LP_SECTOR_SIZE.
uint64_t last_sector = ((device_info_.size - reserved) / LP_SECTOR_SIZE) - 1;
uint64_t last_sector = (device_info.size / LP_SECTOR_SIZE) - 1;
// If this check fails, it means either (1) we did not have free space to
// allocate a single sector, or (2) we did, but the alignment was high
@ -296,7 +292,7 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
// computation, then we abort. Note that the last sector is inclusive,
// so we have to account for that.
uint64_t num_free_sectors = last_sector - first_sector + 1;
uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
uint64_t sectors_per_block = device_info.logical_block_size / LP_SECTOR_SIZE;
if (num_free_sectors < sectors_per_block) {
LERROR << "Not enough space to allocate any partition tables.";
return false;
@ -307,9 +303,9 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
geometry_.last_logical_sector = last_sector;
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_.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)) {
@ -460,7 +456,7 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
}
const uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
const uint64_t sectors_per_block = geometry_.logical_block_size / LP_SECTOR_SIZE;
CHECK_NE(sectors_per_block, 0);
CHECK(sectors_needed % sectors_per_block == 0);
@ -578,32 +574,44 @@ uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
// 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, device_info_.alignment, device_info_.alignment_offset);
uint64_t aligned = AlignTo(lba, geometry_.alignment, geometry_.alignment_offset);
return AlignTo(aligned, LP_SECTOR_SIZE) / LP_SECTOR_SIZE;
}
void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
device_info_.size = device_info.size;
bool MetadataBuilder::GetBlockDeviceInfo(BlockDeviceInfo* info) const {
info->size = geometry_.block_device_size;
info->alignment = geometry_.alignment;
info->alignment_offset = geometry_.alignment_offset;
info->logical_block_size = geometry_.logical_block_size;
return true;
}
// Note that if the logical block size changes, we're probably in trouble:
// we could have already built extents that will only work on the previous
// size.
DCHECK(partitions_.empty() ||
device_info_.logical_block_size == device_info.logical_block_size);
bool MetadataBuilder::UpdateBlockDeviceInfo(const BlockDeviceInfo& device_info) {
if (device_info.size != geometry_.block_device_size) {
LERROR << "Device size does not match (got " << device_info.size << ", expected "
<< geometry_.block_device_size << ")";
return false;
}
if (device_info.logical_block_size != geometry_.logical_block_size) {
LERROR << "Device logical block size does not match (got " << device_info.logical_block_size
<< ", expected " << geometry_.logical_block_size << ")";
return false;
}
// 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) {
device_info_.alignment = device_info.alignment;
geometry_.alignment = device_info.alignment;
}
if (device_info.alignment_offset) {
device_info_.alignment_offset = device_info.alignment_offset;
geometry_.alignment_offset = device_info.alignment_offset;
}
return true;
}
bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
// Align the space needed up to the nearest sector.
uint64_t aligned_size = AlignTo(requested_size, device_info_.logical_block_size);
uint64_t aligned_size = AlignTo(requested_size, geometry_.logical_block_size);
uint64_t old_size = partition->size();
if (aligned_size > old_size) {

View file

@ -48,8 +48,8 @@ TEST(liblp, ResizePartition) {
LinearExtent* extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE);
// The first logical sector will be (4096+1024*2)/512 = 12.
EXPECT_EQ(extent->physical_sector(), 12);
// The first logical sector will be (8192+1024*4)/512 = 12.
EXPECT_EQ(extent->physical_sector(), 24);
// Test resizing to the same size.
EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@ -78,7 +78,7 @@ TEST(liblp, ResizePartition) {
extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(extent->physical_sector(), 12);
EXPECT_EQ(extent->physical_sector(), 24);
// Test shrinking to 0.
builder->ResizePartition(system, 0);
@ -127,7 +127,7 @@ TEST(liblp, InternalAlignment) {
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
// Test a large alignment offset thrown in.
device_info.alignment_offset = 753664;
@ -136,7 +136,7 @@ TEST(liblp, InternalAlignment) {
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
// Alignment offset without alignment doesn't mean anything.
device_info.alignment = 0;
@ -150,8 +150,8 @@ TEST(liblp, InternalAlignment) {
ASSERT_NE(builder, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 78);
EXPECT_EQ(exported->geometry.last_logical_sector, 1973);
EXPECT_EQ(exported->geometry.first_logical_sector, 150);
EXPECT_EQ(exported->geometry.last_logical_sector, 2045);
// Test a small alignment with no alignment offset.
device_info.alignment = 11 * 1024;
@ -159,8 +159,8 @@ TEST(liblp, InternalAlignment) {
ASSERT_NE(builder, nullptr);
exported = builder->Export();
ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 72);
EXPECT_EQ(exported->geometry.last_logical_sector, 1975);
EXPECT_EQ(exported->geometry.first_logical_sector, 160);
EXPECT_EQ(exported->geometry.last_logical_sector, 2047);
}
TEST(liblp, InternalPartitionAlignment) {
@ -247,11 +247,11 @@ TEST(liblp, BuildComplex) {
ASSERT_NE(system2, nullptr);
ASSERT_NE(vendor1, nullptr);
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
EXPECT_EQ(system1->physical_sector(), 12);
EXPECT_EQ(system1->physical_sector(), 24);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(system2->physical_sector(), 204);
EXPECT_EQ(system2->physical_sector(), 216);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(vendor1->physical_sector(), 140);
EXPECT_EQ(vendor1->physical_sector(), 152);
EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector());
EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
}
@ -297,13 +297,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, 12);
EXPECT_EQ(geometry.last_logical_sector, 2035);
EXPECT_EQ(geometry.first_logical_sector, 24);
EXPECT_EQ(geometry.last_logical_sector, 2047);
static const size_t kMetadataSpace =
(kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE;
uint64_t space_at_end = kDiskSize - (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE;
EXPECT_GE(space_at_end, kMetadataSpace);
((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
EXPECT_GE(geometry.first_logical_sector * LP_SECTOR_SIZE, kMetadataSpace);
// Verify header.
@ -361,9 +359,9 @@ TEST(liblp, BuilderImport) {
LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
EXPECT_EQ(system1->physical_sector(), 12);
EXPECT_EQ(system1->physical_sector(), 24);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(system2->physical_sector(), 204);
EXPECT_EQ(system2->physical_sector(), 216);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
}
@ -437,22 +435,37 @@ TEST(liblp, UpdateBlockDeviceInfo) {
unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
ASSERT_NE(builder, nullptr);
EXPECT_EQ(builder->block_device_info().size, device_info.size);
EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment);
EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
EXPECT_EQ(builder->block_device_info().logical_block_size, device_info.logical_block_size);
BlockDeviceInfo new_info;
ASSERT_TRUE(builder->GetBlockDeviceInfo(&new_info));
EXPECT_EQ(new_info.size, device_info.size);
EXPECT_EQ(new_info.alignment, device_info.alignment);
EXPECT_EQ(new_info.alignment_offset, device_info.alignment_offset);
EXPECT_EQ(new_info.logical_block_size, device_info.logical_block_size);
device_info.alignment = 0;
device_info.alignment_offset = 2048;
builder->set_block_device_info(device_info);
EXPECT_EQ(builder->block_device_info().alignment, 4096);
EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
ASSERT_TRUE(builder->GetBlockDeviceInfo(&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;
builder->set_block_device_info(device_info);
EXPECT_EQ(builder->block_device_info().alignment, 8192);
EXPECT_EQ(builder->block_device_info().alignment_offset, 2048);
ASSERT_TRUE(builder->UpdateBlockDeviceInfo(device_info));
ASSERT_TRUE(builder->GetBlockDeviceInfo(&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));
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));
EXPECT_EQ(new_info.logical_block_size, 4096);
}
TEST(liblp, InvalidBlockSize) {

View file

@ -167,16 +167,12 @@ bool SparseBuilder::Build() {
std::string metadata_blob = SerializeMetadata(metadata_);
metadata_blob.resize(geometry_.metadata_max_size);
std::string all_metadata;
for (size_t i = 0; i < geometry_.metadata_slot_count; i++) {
all_metadata += metadata_blob;
// Two copies of geometry, then two copies of each metadata slot.
all_metadata_ += geometry_blob + geometry_blob;
for (size_t i = 0; i < geometry_.metadata_slot_count * 2; i++) {
all_metadata_ += metadata_blob;
}
// Metadata immediately follows geometry, and we write the same metadata
// to all slots. Note that we don't bother trying to write skip chunks
// here since it's a small amount of data.
primary_blob_ = geometry_blob + all_metadata;
if (!AddData(primary_blob_, 0)) {
if (!AddData(all_metadata_, 0)) {
return false;
}
@ -195,17 +191,6 @@ bool SparseBuilder::Build() {
LERROR << "Partition image was specified but no partition was found.";
return false;
}
// The backup area contains all metadata slots, and then geometry. Similar
// to before we write the metadata to every slot.
int64_t backup_offset = GetBackupMetadataOffset(geometry_, 0);
int64_t backups_start = static_cast<int64_t>(geometry_.block_device_size) + backup_offset;
int64_t backup_sector = backups_start / LP_SECTOR_SIZE;
backup_blob_ = all_metadata + geometry_blob;
if (!AddData(backup_blob_, backup_sector)) {
return false;
}
return true;
}

View file

@ -56,8 +56,7 @@ class SparseBuilder {
const LpMetadataGeometry& geometry_;
uint32_t block_size_;
std::unique_ptr<sparse_file, decltype(&sparse_file_destroy)> file_;
std::string primary_blob_;
std::string backup_blob_;
std::string all_metadata_;
std::map<std::string, std::string> images_;
std::vector<android::base::unique_fd> temp_fds_;
};

View file

@ -215,10 +215,8 @@ class MetadataBuilder {
uint64_t AllocatableSpace() const;
uint64_t UsedSpace() const;
// Merge new block device information into previous values. Alignment values
// are only overwritten if the new values are non-zero.
void set_block_device_info(const BlockDeviceInfo& device_info);
const BlockDeviceInfo& block_device_info() const { return device_info_; }
bool GetBlockDeviceInfo(BlockDeviceInfo* info) const;
bool UpdateBlockDeviceInfo(const BlockDeviceInfo& info);
private:
MetadataBuilder();
@ -238,7 +236,6 @@ class MetadataBuilder {
LpMetadataHeader header_;
std::vector<std::unique_ptr<Partition>> partitions_;
std::vector<std::unique_ptr<PartitionGroup>> groups_;
BlockDeviceInfo device_info_;
};
// Read BlockDeviceInfo for a given block device. This always returns false

View file

@ -38,7 +38,7 @@ extern "C" {
#define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */
#define LP_METADATA_MAJOR_VERSION 3
#define LP_METADATA_MAJOR_VERSION 4
#define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field.
@ -58,13 +58,13 @@ extern "C" {
* +--------------------+
* | Disk Geometry |
* +--------------------+
* | Metadata |
* | Geometry Backup |
* +--------------------+
* | Logical Partitions |
* | Metadata |
* +--------------------+
* | Backup Metadata |
* +--------------------+
* | Geometry Backup |
* | Logical Partitions |
* +--------------------+
*/
#define LP_METADATA_DEFAULT_PARTITION_NAME "super"
@ -72,8 +72,8 @@ extern "C" {
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512
/* This structure is stored at sector 0 in the first 4096 bytes of the
* partition, and again in the very last 4096 bytes. It is never modified and
/* This structure is stored at block 0 in the first 4096 bytes of the
* partition, and again in the following block. It is never modified and
* describes how logical partition information can be located.
*/
typedef struct LpMetadataGeometry {
@ -99,8 +99,8 @@ 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 4096 geometry block, followed by the
* space consumed by metadata_max_size*metadata_slot_count.
* 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;

View file

@ -290,13 +290,13 @@ TEST(liblp, ReadBackupGeometry) {
char corruption[LP_METADATA_GEOMETRY_SIZE];
memset(corruption, 0xff, sizeof(corruption));
// Corrupt the first 4096 bytes of the disk.
ASSERT_GE(lseek(fd, 0, SEEK_SET), 0);
// Corrupt the primary geometry.
ASSERT_GE(lseek(fd, GetPrimaryGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
// Corrupt the last 4096 bytes too.
ASSERT_GE(lseek(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END), 0);
// Corrupt the backup geometry.
ASSERT_GE(lseek(fd, GetBackupGeometryOffset(), SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}
@ -310,14 +310,16 @@ TEST(liblp, ReadBackupMetadata) {
char corruption[kMetadataSize];
memset(corruption, 0xff, sizeof(corruption));
ASSERT_GE(lseek(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET), 0);
off_t offset = GetPrimaryMetadataOffset(metadata->geometry, 0);
ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_NE(ReadMetadata(fd, 0), nullptr);
off_t offset = LP_METADATA_GEOMETRY_SIZE + kMetadataSize * 2;
offset = GetBackupMetadataOffset(metadata->geometry, 0);
// Corrupt the backup metadata.
ASSERT_GE(lseek(fd, -offset, SEEK_END), 0);
ASSERT_GE(lseek(fd, offset, SEEK_SET), 0);
ASSERT_TRUE(android::base::WriteFully(fd, corruption, sizeof(corruption)));
EXPECT_EQ(ReadMetadata(fd, 0), nullptr);
}

View file

@ -121,9 +121,8 @@ bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
}
bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
// Read the first 4096 bytes.
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, 0, SEEK_SET) < 0) {
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed";
return false;
}
@ -135,9 +134,8 @@ bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
}
bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) {
// Try the backup copy in the last 4096 bytes.
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed, offset " << -LP_METADATA_GEOMETRY_SIZE;
return false;
}
@ -323,7 +321,7 @@ std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry
std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry& geometry,
uint32_t slot_number) {
int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_END) < 0) {
if (SeekFile64(fd, offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset;
return nullptr;
}

View file

@ -56,10 +56,18 @@ int64_t SeekFile64(int fd, int64_t offset, int whence) {
return lseek(fd, offset, whence);
}
int64_t GetPrimaryGeometryOffset() {
return 0;
}
int64_t GetBackupGeometryOffset() {
return LP_METADATA_GEOMETRY_SIZE;
}
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
int64_t offset = LP_METADATA_GEOMETRY_SIZE + geometry.metadata_max_size * slot_number;
int64_t offset = (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;
@ -67,7 +75,7 @@ int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t sl
int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count);
int64_t start = int64_t(-LP_METADATA_GEOMETRY_SIZE) -
int64_t start = LP_METADATA_GEOMETRY_SIZE * 2 +
int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
return start + int64_t(geometry.metadata_max_size * slot_number);
}

View file

@ -38,6 +38,10 @@ namespace fs_mgr {
// error. After calling this, the position of |fd| may have changed.
bool GetDescriptorSize(int fd, uint64_t* size);
// Return the offset of the primary or backup geometry.
int64_t GetPrimaryGeometryOffset();
int64_t GetBackupGeometryOffset();
// Return the offset of a primary metadata slot, relative to the start of the
// device.
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number);

View file

@ -42,15 +42,17 @@ TEST(liblp, GetMetadataOffset) {
0,
1024 * 1024,
4096};
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 4096 + 16384 * 3);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 8192);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 8192 + 16384);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 8192 + 16384 * 2);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 8192 + 16384 * 3);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), -4096 - 16384 * 1);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), -4096 - 16384 * 2);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), -4096 - 16384 * 3);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), -4096 - 16384 * 4);
static const uint64_t backup_start = 8192 + 16384 * 4;
EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), backup_start + 16384 * 3);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), backup_start + 16384 * 2);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), backup_start + 16384 * 1);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 0), backup_start + 16384 * 0);
}
TEST(liblp, AlignTo) {

View file

@ -106,15 +106,13 @@ static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std
// metadata.
uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
if (reserved_size > blockdevice_size ||
reserved_size > geometry.first_logical_sector * LP_SECTOR_SIZE) {
uint64_t total_reserved = reserved_size * 2;
if (total_reserved > blockdevice_size ||
total_reserved > geometry.first_logical_sector * LP_SECTOR_SIZE) {
LERROR << "Not enough space to store all logical partition metadata slots.";
return false;
}
if (blockdevice_size - reserved_size < (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE) {
LERROR << "Not enough space to backup all logical partition metadata slots.";
return false;
}
if (blockdevice_size != metadata.geometry.block_device_size) {
LERROR << "Block device size " << blockdevice_size
<< " does not match metadata requested size " << metadata.geometry.block_device_size;
@ -162,12 +160,12 @@ static bool WriteBackupMetadata(int fd, const LpMetadataGeometry& geometry, uint
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_END);
int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET);
if (abs_offset == (int64_t)-1) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset;
return false;
}
if (abs_offset < int64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) {
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.last_logical_sector;
return false;
@ -211,7 +209,7 @@ bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
// Write geometry to the first and last 4096 bytes of the device.
std::string blob = SerializeGeometry(metadata.geometry);
if (SeekFile64(fd, 0, SEEK_SET) < 0) {
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0";
return false;
}
@ -219,7 +217,7 @@ bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed";
return false;
}
if (SeekFile64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) < 0) {
if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE;
return false;
}