Merge "liblp: Reserve the first logical block of the super partition."

This commit is contained in:
David Anderson 2018-10-19 02:04:08 +00:00 committed by Gerrit Code Review
commit 6f4722e98e
9 changed files with 93 additions and 53 deletions

View file

@ -261,7 +261,7 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
// we store a backup copy of everything. // we store a backup copy of everything.
uint64_t reserved = uint64_t reserved =
LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count); LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count);
uint64_t total_reserved = reserved * 2; uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + 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."; LERROR << "Attempting to create metadata on a block device that is too small.";
return false; return false;

View file

@ -48,8 +48,11 @@ TEST(liblp, ResizePartition) {
LinearExtent* extent = system->extents()[0]->AsLinearExtent(); LinearExtent* extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr); ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE); EXPECT_EQ(extent->num_sectors(), 65536 / LP_SECTOR_SIZE);
// The first logical sector will be (8192+1024*4)/512 = 12. // The first logical sector will be:
EXPECT_EQ(extent->physical_sector(), 24); // (LP_PARTITION_RESERVED_BYTES + 4096*2 + 1024*4) / 512
// Or, in terms of sectors (reserved + geometry + metadata):
// (8 + 16 + 8) = 32
EXPECT_EQ(extent->physical_sector(), 32);
// Test resizing to the same size. // Test resizing to the same size.
EXPECT_EQ(builder->ResizePartition(system, 65536), true); EXPECT_EQ(builder->ResizePartition(system, 65536), true);
@ -78,7 +81,7 @@ TEST(liblp, ResizePartition) {
extent = system->extents()[0]->AsLinearExtent(); extent = system->extents()[0]->AsLinearExtent();
ASSERT_NE(extent, nullptr); ASSERT_NE(extent, nullptr);
EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(extent->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(extent->physical_sector(), 24); EXPECT_EQ(extent->physical_sector(), 32);
// Test shrinking to 0. // Test shrinking to 0.
builder->ResizePartition(system, 0); builder->ResizePartition(system, 0);
@ -148,7 +151,7 @@ TEST(liblp, InternalAlignment) {
ASSERT_NE(builder, nullptr); ASSERT_NE(builder, nullptr);
exported = builder->Export(); exported = builder->Export();
ASSERT_NE(exported, nullptr); ASSERT_NE(exported, nullptr);
EXPECT_EQ(exported->geometry.first_logical_sector, 150); EXPECT_EQ(exported->geometry.first_logical_sector, 174);
// Test a small alignment with no alignment offset. // Test a small alignment with no alignment offset.
device_info.alignment = 11 * 1024; device_info.alignment = 11 * 1024;
@ -202,7 +205,8 @@ TEST(liblp, UseAllDiskSpace) {
// maximum size of a metadata blob. Then, we double that space since // maximum size of a metadata blob. Then, we double that space since
// we store a backup copy of everything. // we store a backup copy of everything.
static constexpr uint64_t geometry = 4 * 1024; static constexpr uint64_t geometry = 4 * 1024;
static constexpr uint64_t allocatable = total - (metadata * slots + geometry) * 2; static constexpr uint64_t allocatable =
total - (metadata * slots + geometry) * 2 - LP_PARTITION_RESERVED_BYTES;
EXPECT_EQ(builder->AllocatableSpace(), allocatable); EXPECT_EQ(builder->AllocatableSpace(), allocatable);
EXPECT_EQ(builder->UsedSpace(), 0); EXPECT_EQ(builder->UsedSpace(), 0);
@ -243,11 +247,11 @@ TEST(liblp, BuildComplex) {
ASSERT_NE(system2, nullptr); ASSERT_NE(system2, nullptr);
ASSERT_NE(vendor1, nullptr); ASSERT_NE(vendor1, nullptr);
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE); EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
EXPECT_EQ(system1->physical_sector(), 24); EXPECT_EQ(system1->physical_sector(), 32);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(system2->physical_sector(), 216); EXPECT_EQ(system2->physical_sector(), 224);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(vendor1->physical_sector(), 152); EXPECT_EQ(vendor1->physical_sector(), 160);
EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector()); EXPECT_EQ(system1->physical_sector() + system1->num_sectors(), vendor1->physical_sector());
EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector()); EXPECT_EQ(vendor1->physical_sector() + vendor1->num_sectors(), system2->physical_sector());
} }
@ -293,7 +297,7 @@ TEST(liblp, BuilderExport) {
EXPECT_EQ(geometry.struct_size, sizeof(geometry)); EXPECT_EQ(geometry.struct_size, sizeof(geometry));
EXPECT_EQ(geometry.metadata_max_size, 1024); EXPECT_EQ(geometry.metadata_max_size, 1024);
EXPECT_EQ(geometry.metadata_slot_count, 2); EXPECT_EQ(geometry.metadata_slot_count, 2);
EXPECT_EQ(geometry.first_logical_sector, 24); EXPECT_EQ(geometry.first_logical_sector, 32);
static const size_t kMetadataSpace = static const size_t kMetadataSpace =
((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2; ((kMetadataSize * kMetadataSlots) + LP_METADATA_GEOMETRY_SIZE) * 2;
@ -354,9 +358,9 @@ TEST(liblp, BuilderImport) {
LinearExtent* system2 = system->extents()[1]->AsLinearExtent(); LinearExtent* system2 = system->extents()[1]->AsLinearExtent();
LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent(); LinearExtent* vendor1 = vendor->extents()[0]->AsLinearExtent();
EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE); EXPECT_EQ(system1->num_sectors(), 65536 / LP_SECTOR_SIZE);
EXPECT_EQ(system1->physical_sector(), 24); EXPECT_EQ(system1->physical_sector(), 32);
EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(system2->num_sectors(), 32768 / LP_SECTOR_SIZE);
EXPECT_EQ(system2->physical_sector(), 216); EXPECT_EQ(system2->physical_sector(), 224);
EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE); EXPECT_EQ(vendor1->num_sectors(), 32768 / LP_SECTOR_SIZE);
} }
@ -381,7 +385,7 @@ TEST(liblp, MetadataTooLarge) {
EXPECT_EQ(builder, nullptr); EXPECT_EQ(builder, nullptr);
// No space to store metadata + geometry + one free sector. // No space to store metadata + geometry + one free sector.
device_info.size += LP_METADATA_GEOMETRY_SIZE * 2; device_info.size += LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2);
builder = MetadataBuilder::New(device_info, kMetadataSize, 1); builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
EXPECT_EQ(builder, nullptr); EXPECT_EQ(builder, nullptr);

View file

@ -28,12 +28,17 @@ namespace android {
namespace fs_mgr { namespace fs_mgr {
std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) { std::unique_ptr<LpMetadata> ReadFromImageFile(int fd) {
LpMetadataGeometry geometry; std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (!ReadLogicalPartitionGeometry(fd, &geometry)) { if (SeekFile64(fd, 0, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << " lseek failed";
return nullptr; return nullptr;
} }
if (SeekFile64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) < 0) { if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << LP_METADATA_GEOMETRY_SIZE; PERROR << __PRETTY_FUNCTION__ << " read failed";
return nullptr;
}
LpMetadataGeometry geometry;
if (!ParseGeometry(buffer.get(), &geometry)) {
return nullptr; return nullptr;
} }
return ParseMetadata(geometry, fd); return ParseMetadata(geometry, fd);
@ -59,7 +64,7 @@ std::unique_ptr<LpMetadata> ReadFromImageBlob(const void* data, size_t bytes) {
std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) { std::unique_ptr<LpMetadata> ReadFromImageFile(const char* file) {
android::base::unique_fd fd(open(file, O_RDONLY)); android::base::unique_fd fd(open(file, O_RDONLY));
if (fd < 0) { if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << file; PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
return nullptr; return nullptr;
} }
return ReadFromImageFile(fd); return ReadFromImageFile(fd);
@ -72,7 +77,7 @@ bool WriteToImageFile(int fd, const LpMetadata& input) {
std::string everything = geometry + metadata; std::string everything = geometry + metadata;
if (!android::base::WriteFully(fd, everything.data(), everything.size())) { if (!android::base::WriteFully(fd, everything.data(), everything.size())) {
PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed"; PERROR << __PRETTY_FUNCTION__ << " write " << everything.size() << " bytes failed";
return false; return false;
} }
return true; return true;
@ -81,7 +86,7 @@ bool WriteToImageFile(int fd, const LpMetadata& input) {
bool WriteToImageFile(const char* file, const LpMetadata& input) { bool WriteToImageFile(const char* file, const LpMetadata& input) {
android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644)); android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644));
if (fd < 0) { if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << file; PERROR << __PRETTY_FUNCTION__ << " open failed: " << file;
return false; return false;
} }
return WriteToImageFile(fd, input); return WriteToImageFile(fd, input);
@ -106,6 +111,14 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size,
LERROR << "Metadata max size must be a multiple of the block size, " << block_size; LERROR << "Metadata max size must be a multiple of the block size, " << block_size;
return; return;
} }
if (LP_METADATA_GEOMETRY_SIZE % block_size != 0) {
LERROR << "Geometry size is not a multiple of the block size, " << block_size;
return;
}
if (LP_PARTITION_RESERVED_BYTES % block_size != 0) {
LERROR << "Reserved size is not a multiple of the block size, " << block_size;
return;
}
uint64_t num_blocks = metadata.geometry.block_device_size % block_size; uint64_t num_blocks = metadata.geometry.block_device_size % block_size;
if (num_blocks >= UINT_MAX) { if (num_blocks >= UINT_MAX) {
@ -163,6 +176,11 @@ bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) {
} }
bool SparseBuilder::Build() { bool SparseBuilder::Build() {
if (sparse_file_add_fill(file_.get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) {
LERROR << "Could not add initial sparse block for reserved zeroes";
return false;
}
std::string geometry_blob = SerializeGeometry(geometry_); std::string geometry_blob = SerializeGeometry(geometry_);
std::string metadata_blob = SerializeMetadata(metadata_); std::string metadata_blob = SerializeMetadata(metadata_);
metadata_blob.resize(geometry_.metadata_max_size); metadata_blob.resize(geometry_.metadata_max_size);

View file

@ -38,7 +38,7 @@ extern "C" {
#define LP_METADATA_HEADER_MAGIC 0x414C5030 #define LP_METADATA_HEADER_MAGIC 0x414C5030
/* Current metadata version. */ /* Current metadata version. */
#define LP_METADATA_MAJOR_VERSION 5 #define LP_METADATA_MAJOR_VERSION 6
#define LP_METADATA_MINOR_VERSION 0 #define LP_METADATA_MINOR_VERSION 0
/* Attributes for the LpMetadataPartition::attributes field. /* Attributes for the LpMetadataPartition::attributes field.
@ -72,6 +72,11 @@ extern "C" {
/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */ /* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */
#define LP_SECTOR_SIZE 512 #define LP_SECTOR_SIZE 512
/* Amount of space reserved at the start of every super partition to avoid
* creating an accidental boot sector.
*/
#define LP_PARTITION_RESERVED_BYTES 4096
/* This structure is stored at block 0 in the first 4096 bytes of the /* 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 * partition, and again in the following block. It is never modified and
* describes how logical partition information can be located. * describes how logical partition information can be located.

View file

@ -376,6 +376,7 @@ TEST(liblp, ImageFiles) {
ASSERT_NE(builder, nullptr); ASSERT_NE(builder, nullptr);
ASSERT_TRUE(AddDefaultPartitions(builder.get())); ASSERT_TRUE(AddDefaultPartitions(builder.get()));
unique_ptr<LpMetadata> exported = builder->Export(); unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
unique_fd fd(syscall(__NR_memfd_create, "image_file", 0)); unique_fd fd(syscall(__NR_memfd_create, "image_file", 0));
ASSERT_GE(fd, 0); ASSERT_GE(fd, 0);

View file

@ -123,11 +123,11 @@ bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) {
bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) { bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE); std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) { if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed"; PERROR << __PRETTY_FUNCTION__ << " lseek failed";
return false; return false;
} }
if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) { if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
PERROR << __PRETTY_FUNCTION__ << "read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed"; PERROR << __PRETTY_FUNCTION__ << " read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed";
return false; return false;
} }
return ParseGeometry(buffer.get(), geometry); return ParseGeometry(buffer.get(), geometry);
@ -136,11 +136,11 @@ bool ReadPrimaryGeometry(int fd, LpMetadataGeometry* geometry) {
bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) { bool ReadBackupGeometry(int fd, LpMetadataGeometry* geometry) {
std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE); std::unique_ptr<uint8_t[]> buffer = std::make_unique<uint8_t[]>(LP_METADATA_GEOMETRY_SIZE);
if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) { if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed, offset " << -LP_METADATA_GEOMETRY_SIZE; PERROR << __PRETTY_FUNCTION__ << " lseek failed";
return false; return false;
} }
if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) { if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) {
PERROR << __PRETTY_FUNCTION__ << "backup read " << LP_METADATA_GEOMETRY_SIZE PERROR << __PRETTY_FUNCTION__ << " backup read " << LP_METADATA_GEOMETRY_SIZE
<< " bytes failed"; << " bytes failed";
return false; return false;
} }
@ -223,7 +223,7 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
// First read and validate the header. // First read and validate the header.
std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>(); std::unique_ptr<LpMetadata> metadata = std::make_unique<LpMetadata>();
if (!reader->ReadFully(&metadata->header, sizeof(metadata->header))) { if (!reader->ReadFully(&metadata->header, sizeof(metadata->header))) {
PERROR << __PRETTY_FUNCTION__ << "read " << sizeof(metadata->header) << "bytes failed"; PERROR << __PRETTY_FUNCTION__ << " read " << sizeof(metadata->header) << "bytes failed";
return nullptr; return nullptr;
} }
if (!ValidateMetadataHeader(metadata->header)) { if (!ValidateMetadataHeader(metadata->header)) {
@ -241,7 +241,7 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome
return nullptr; return nullptr;
} }
if (!reader->ReadFully(buffer.get(), header.tables_size)) { if (!reader->ReadFully(buffer.get(), header.tables_size)) {
PERROR << __PRETTY_FUNCTION__ << "read " << header.tables_size << "bytes failed"; PERROR << __PRETTY_FUNCTION__ << " read " << header.tables_size << "bytes failed";
return nullptr; return nullptr;
} }
@ -312,7 +312,7 @@ std::unique_ptr<LpMetadata> ReadPrimaryMetadata(int fd, const LpMetadataGeometry
uint32_t slot_number) { uint32_t slot_number) {
int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number); int64_t offset = GetPrimaryMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_SET) < 0) { if (SeekFile64(fd, offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset; PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset;
return nullptr; return nullptr;
} }
return ParseMetadata(geometry, fd); return ParseMetadata(geometry, fd);
@ -322,7 +322,7 @@ std::unique_ptr<LpMetadata> ReadBackupMetadata(int fd, const LpMetadataGeometry&
uint32_t slot_number) { uint32_t slot_number) {
int64_t offset = GetBackupMetadataOffset(geometry, slot_number); int64_t offset = GetBackupMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, offset, SEEK_SET) < 0) { if (SeekFile64(fd, offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << offset; PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << offset;
return nullptr; return nullptr;
} }
return ParseMetadata(geometry, fd); return ParseMetadata(geometry, fd);
@ -335,7 +335,7 @@ std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
} }
if (slot_number >= geometry.metadata_slot_count) { if (slot_number >= geometry.metadata_slot_count) {
LERROR << __PRETTY_FUNCTION__ << "invalid metadata slot number"; LERROR << __PRETTY_FUNCTION__ << " invalid metadata slot number";
return nullptr; return nullptr;
} }
@ -350,7 +350,7 @@ std::unique_ptr<LpMetadata> ReadMetadata(int fd, uint32_t slot_number) {
std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) { std::unique_ptr<LpMetadata> ReadMetadata(const char* block_device, uint32_t slot_number) {
android::base::unique_fd fd(open(block_device, O_RDONLY)); android::base::unique_fd fd(open(block_device, O_RDONLY));
if (fd < 0) { if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device; PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
return nullptr; return nullptr;
} }
return ReadMetadata(fd, slot_number); return ReadMetadata(fd, slot_number);

View file

@ -57,17 +57,18 @@ int64_t SeekFile64(int fd, int64_t offset, int whence) {
} }
int64_t GetPrimaryGeometryOffset() { int64_t GetPrimaryGeometryOffset() {
return 0; return LP_PARTITION_RESERVED_BYTES;
} }
int64_t GetBackupGeometryOffset() { int64_t GetBackupGeometryOffset() {
return LP_METADATA_GEOMETRY_SIZE; return GetPrimaryGeometryOffset() + LP_METADATA_GEOMETRY_SIZE;
} }
int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) { int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count); CHECK(slot_number < geometry.metadata_slot_count);
int64_t offset = (LP_METADATA_GEOMETRY_SIZE * 2) + geometry.metadata_max_size * slot_number; int64_t offset = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
geometry.metadata_max_size * slot_number;
CHECK(offset + geometry.metadata_max_size <= CHECK(offset + geometry.metadata_max_size <=
int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE)); int64_t(geometry.first_logical_sector * LP_SECTOR_SIZE));
return offset; return offset;
@ -75,7 +76,7 @@ int64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t sl
int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) { int64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) {
CHECK(slot_number < geometry.metadata_slot_count); CHECK(slot_number < geometry.metadata_slot_count);
int64_t start = LP_METADATA_GEOMETRY_SIZE * 2 + int64_t start = LP_PARTITION_RESERVED_BYTES + (LP_METADATA_GEOMETRY_SIZE * 2) +
int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count; int64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
return start + int64_t(geometry.metadata_max_size * slot_number); return start + int64_t(geometry.metadata_max_size * slot_number);
} }

View file

@ -41,13 +41,13 @@ TEST(liblp, GetMetadataOffset) {
0, 0,
1024 * 1024, 1024 * 1024,
4096}; 4096};
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 8192); static const uint64_t start = LP_PARTITION_RESERVED_BYTES;
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 8192 + 16384); EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), start + 8192);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 8192 + 16384 * 2); EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), start + 8192 + 16384);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), 8192 + 16384 * 3); EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), start + 8192 + 16384 * 2);
EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 3), start + 8192 + 16384 * 3);
static const uint64_t backup_start = 8192 + 16384 * 4;
static const uint64_t backup_start = start + 8192 + 16384 * 4;
EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), backup_start + 16384 * 3); EXPECT_EQ(GetBackupMetadataOffset(geometry, 3), backup_start + 16384 * 3);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), backup_start + 16384 * 2); EXPECT_EQ(GetBackupMetadataOffset(geometry, 2), backup_start + 16384 * 2);
EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), backup_start + 16384 * 1); EXPECT_EQ(GetBackupMetadataOffset(geometry, 1), backup_start + 16384 * 1);

View file

@ -144,11 +144,11 @@ static bool WritePrimaryMetadata(int fd, const LpMetadataGeometry& geometry, uin
const std::function<bool(int, const std::string&)>& writer) { const std::function<bool(int, const std::string&)>& writer) {
int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number); int64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number);
if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) { if (SeekFile64(fd, primary_offset, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << primary_offset; PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << primary_offset;
return false; return false;
} }
if (!writer(fd, blob)) { if (!writer(fd, blob)) {
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed"; PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
return false; return false;
} }
return true; return true;
@ -160,16 +160,16 @@ static bool WriteBackupMetadata(int fd, const LpMetadataGeometry& geometry, uint
int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number); int64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number);
int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET); int64_t abs_offset = SeekFile64(fd, backup_offset, SEEK_SET);
if (abs_offset == (int64_t)-1) { if (abs_offset == (int64_t)-1) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << backup_offset; PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset " << backup_offset;
return false; return false;
} }
if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) { if (abs_offset >= int64_t(geometry.first_logical_sector) * LP_SECTOR_SIZE) {
PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset PERROR << __PRETTY_FUNCTION__ << " backup offset " << abs_offset
<< " is within logical partition bounds, sector " << geometry.first_logical_sector; << " is within logical partition bounds, sector " << geometry.first_logical_sector;
return false; return false;
} }
if (!writer(fd, blob)) { if (!writer(fd, blob)) {
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
return false; return false;
} }
return true; return true;
@ -205,22 +205,33 @@ bool FlashPartitionTable(int fd, const LpMetadata& metadata) {
return false; return false;
} }
// Write geometry to the first and last 4096 bytes of the device. // Write zeroes to the first block.
std::string zeroes(LP_PARTITION_RESERVED_BYTES, 0);
if (SeekFile64(fd, 0, SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << " lseek failed: offset 0";
return false;
}
if (!android::base::WriteFully(fd, zeroes.data(), zeroes.size())) {
PERROR << __PRETTY_FUNCTION__ << " write " << zeroes.size() << " bytes failed";
return false;
}
// Write geometry to the primary and backup locations.
std::string blob = SerializeGeometry(metadata.geometry); std::string blob = SerializeGeometry(metadata.geometry);
if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) { if (SeekFile64(fd, GetPrimaryGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset 0"; PERROR << __PRETTY_FUNCTION__ << " lseek failed: primary geometry";
return false; return false;
} }
if (!android::base::WriteFully(fd, blob.data(), blob.size())) { if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() << " bytes failed"; PERROR << __PRETTY_FUNCTION__ << " write " << blob.size() << " bytes failed";
return false; return false;
} }
if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) { if (SeekFile64(fd, GetBackupGeometryOffset(), SEEK_SET) < 0) {
PERROR << __PRETTY_FUNCTION__ << "lseek failed: offset " << -LP_METADATA_GEOMETRY_SIZE; PERROR << __PRETTY_FUNCTION__ << " lseek failed: backup geometry";
return false; return false;
} }
if (!android::base::WriteFully(fd, blob.data(), blob.size())) { if (!android::base::WriteFully(fd, blob.data(), blob.size())) {
PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() << " bytes failed"; PERROR << __PRETTY_FUNCTION__ << " backup write " << blob.size() << " bytes failed";
return false; return false;
} }
@ -303,7 +314,7 @@ bool UpdatePartitionTable(int fd, const LpMetadata& metadata, uint32_t slot_numb
bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata) { bool FlashPartitionTable(const std::string& block_device, const LpMetadata& metadata) {
android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC)); android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
if (fd < 0) { if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device; PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
return false; return false;
} }
if (!FlashPartitionTable(fd, metadata)) { if (!FlashPartitionTable(fd, metadata)) {
@ -317,7 +328,7 @@ bool UpdatePartitionTable(const std::string& block_device, const LpMetadata& met
uint32_t slot_number) { uint32_t slot_number) {
android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC)); android::base::unique_fd fd(open(block_device.c_str(), O_RDWR | O_SYNC));
if (fd < 0) { if (fd < 0) {
PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device; PERROR << __PRETTY_FUNCTION__ << " open failed: " << block_device;
return false; return false;
} }
if (!UpdatePartitionTable(fd, metadata, slot_number)) { if (!UpdatePartitionTable(fd, metadata, slot_number)) {