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

Commit 13e160e0 authored by David Anderson's avatar David Anderson Committed by Gerrit Code Review
Browse files

Merge "liblp: Store device information in a new block device table."

parents 2a846072 9a532417
Loading
Loading
Loading
Loading
+37 −11
Original line number Diff line number Diff line
@@ -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;
+31 −19
Original line number Diff line number Diff line
@@ -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;
}
+17 −6
Original line number Diff line number Diff line
@@ -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;
+8 −11
Original line number Diff line number Diff line
@@ -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
+4 −0
Original line number Diff line number Diff line
@@ -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
Loading