Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 06f7a967 authored by David Anderson's avatar David Anderson
Browse files

liblp: Move backup sectors to the start of the partition.

Previously, metadata backups were stored at the end of the partition to
make them easy to locate. On older devices where the super partition
could span system/vendor partitions, we may want to leave the end of
each partition free to store an AVB footer. To allow this, we now store
geometry and metadata backups near the start of the partition instead.
They are still positioned at a fixed offset.

Bug: 116802789
Test: device boots after flashing new metadata
Change-Id: Ib173f251a4a13e290adcc4ac5cfbeb030eacda30
parent f8983888
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -273,14 +273,15 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
    }

    // 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
+17 −19
Original line number Diff line number Diff line
@@ -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);
}

+5 −20
Original line number Diff line number Diff line
@@ -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;
}

+1 −2
Original line number Diff line number Diff line
@@ -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_;
};
+8 −8
Original line number Diff line number Diff line
@@ -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;

Loading