Merge changes I88689889,Ibfd66734

* changes:
  liblp: Reclaim wasted space from unaligned partitions, v2.
  Revert "liblp: Reclaim wasted space from unaligned partitions."
This commit is contained in:
David Anderson 2019-03-18 20:09:44 +00:00 committed by Gerrit Code Review
commit e2d977bffd
3 changed files with 92 additions and 22 deletions

View file

@ -591,11 +591,25 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
free_regions = PrioritizeSecondHalfOfSuper(free_regions);
}
// Find gaps that we can use for new extents. Note we store new extents in a
// temporary vector, and only commit them if we are guaranteed enough free
// space.
// Note we store new extents in a temporary vector, and only commit them
// if we are guaranteed enough free space.
std::vector<std::unique_ptr<LinearExtent>> new_extents;
// If the last extent in the partition has a size < alignment, then the
// difference is unallocatable due to being misaligned. We peek for that
// case here to avoid wasting space.
if (auto extent = ExtendFinalExtent(partition, free_regions, sectors_needed)) {
sectors_needed -= extent->num_sectors();
new_extents.emplace_back(std::move(extent));
}
for (auto& region : free_regions) {
// Note: this comes first, since we may enter the loop not needing any
// more sectors.
if (!sectors_needed) {
break;
}
if (region.length() % sectors_per_block != 0) {
// This should never happen, because it would imply that we
// once allocated an extent that was not a multiple of the
@ -613,22 +627,10 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
}
uint64_t sectors = std::min(sectors_needed, region.length());
if (sectors < region.length()) {
const auto& block_device = block_devices_[region.device_index];
if (block_device.alignment) {
const uint64_t alignment = block_device.alignment / LP_SECTOR_SIZE;
sectors = AlignTo(sectors, alignment);
sectors = std::min(sectors, region.length());
}
}
CHECK(sectors % sectors_per_block == 0);
auto extent = std::make_unique<LinearExtent>(sectors, region.device_index, region.start);
new_extents.push_back(std::move(extent));
if (sectors >= sectors_needed) {
sectors_needed = 0;
break;
}
sectors_needed -= sectors;
}
if (sectors_needed) {
@ -677,6 +679,64 @@ std::vector<MetadataBuilder::Interval> MetadataBuilder::PrioritizeSecondHalfOfSu
return second_half;
}
std::unique_ptr<LinearExtent> MetadataBuilder::ExtendFinalExtent(
Partition* partition, const std::vector<Interval>& free_list,
uint64_t sectors_needed) const {
if (partition->extents().empty()) {
return nullptr;
}
LinearExtent* extent = partition->extents().back()->AsLinearExtent();
if (!extent) {
return nullptr;
}
// If the sector ends where the next aligned chunk begins, then there's
// no missing gap to try and allocate.
const auto& block_device = block_devices_[extent->device_index()];
uint64_t next_aligned_sector = AlignSector(block_device, extent->end_sector());
if (extent->end_sector() == next_aligned_sector) {
return nullptr;
}
uint64_t num_sectors = std::min(next_aligned_sector - extent->end_sector(), sectors_needed);
auto new_extent = std::make_unique<LinearExtent>(num_sectors, extent->device_index(),
extent->end_sector());
if (IsAnyRegionAllocated(*new_extent.get()) ||
IsAnyRegionCovered(free_list, *new_extent.get())) {
LERROR << "Misaligned region " << new_extent->physical_sector() << ".."
<< new_extent->end_sector() << " was allocated or marked allocatable.";
return nullptr;
}
return new_extent;
}
bool MetadataBuilder::IsAnyRegionCovered(const std::vector<Interval>& regions,
const LinearExtent& candidate) const {
for (const auto& region : regions) {
if (region.device_index == candidate.device_index() &&
(candidate.OwnsSector(region.start) || candidate.OwnsSector(region.end))) {
return true;
}
}
return false;
}
bool MetadataBuilder::IsAnyRegionAllocated(const LinearExtent& candidate) const {
for (const auto& partition : partitions_) {
for (const auto& extent : partition->extents()) {
LinearExtent* linear = extent->AsLinearExtent();
if (!linear || linear->device_index() != candidate.device_index()) {
continue;
}
if (linear->OwnsSector(candidate.physical_sector()) ||
linear->OwnsSector(candidate.end_sector() - 1)) {
return true;
}
}
}
return false;
}
void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t aligned_size) {
partition->ShrinkTo(aligned_size);
}

View file

@ -209,8 +209,8 @@ TEST_F(BuilderTest, InternalPartitionAlignment) {
ASSERT_TRUE(builder->ResizePartition(a, a->size() + 4096));
ASSERT_TRUE(builder->ResizePartition(b, b->size() + 4096));
}
EXPECT_EQ(a->size(), 7864320);
EXPECT_EQ(b->size(), 7864320);
EXPECT_EQ(a->size(), 40960);
EXPECT_EQ(b->size(), 40960);
unique_ptr<LpMetadata> exported = builder->Export();
ASSERT_NE(exported, nullptr);
@ -218,7 +218,7 @@ TEST_F(BuilderTest, InternalPartitionAlignment) {
// Check that each starting sector is aligned.
for (const auto& extent : exported->extents) {
ASSERT_EQ(extent.target_type, LP_TARGET_TYPE_LINEAR);
EXPECT_EQ(extent.num_sectors, 1536);
EXPECT_EQ(extent.num_sectors, 80);
uint64_t lba = extent.target_data * LP_SECTOR_SIZE;
uint64_t aligned_lba = AlignTo(lba, device_info.alignment, device_info.alignment_offset);
@ -226,7 +226,7 @@ TEST_F(BuilderTest, InternalPartitionAlignment) {
}
// Sanity check one extent.
EXPECT_EQ(exported->extents.back().target_data, 30656);
EXPECT_EQ(exported->extents.back().target_data, 3008);
}
TEST_F(BuilderTest, UseAllDiskSpace) {
@ -698,7 +698,7 @@ TEST_F(BuilderTest, MultipleBlockDevices) {
EXPECT_EQ(metadata->extents[1].target_type, LP_TARGET_TYPE_LINEAR);
EXPECT_EQ(metadata->extents[1].target_data, 1472);
EXPECT_EQ(metadata->extents[1].target_source, 1);
EXPECT_EQ(metadata->extents[2].num_sectors, 129600);
EXPECT_EQ(metadata->extents[2].num_sectors, 129088);
EXPECT_EQ(metadata->extents[2].target_type, LP_TARGET_TYPE_LINEAR);
EXPECT_EQ(metadata->extents[2].target_data, 1472);
EXPECT_EQ(metadata->extents[2].target_source, 2);
@ -805,7 +805,7 @@ TEST_F(BuilderTest, ABExtents) {
EXPECT_EQ(exported->extents[0].target_data, 10487808);
EXPECT_EQ(exported->extents[0].num_sectors, 10483712);
EXPECT_EQ(exported->extents[1].target_data, 6292992);
EXPECT_EQ(exported->extents[1].num_sectors, 2099712);
EXPECT_EQ(exported->extents[1].num_sectors, 2099200);
EXPECT_EQ(exported->extents[2].target_data, 1536);
EXPECT_EQ(exported->extents[2].num_sectors, 6291456);
}
@ -821,7 +821,7 @@ TEST_F(BuilderTest, PartialExtents) {
ASSERT_NE(vendor, nullptr);
ASSERT_TRUE(builder->ResizePartition(system, device_info.alignment + 4096));
ASSERT_TRUE(builder->ResizePartition(vendor, device_info.alignment));
ASSERT_EQ(system->size(), device_info.alignment * 2);
ASSERT_EQ(system->size(), device_info.alignment + 4096);
ASSERT_EQ(vendor->size(), device_info.alignment);
ASSERT_TRUE(builder->ResizePartition(system, device_info.alignment * 2));

View file

@ -66,6 +66,10 @@ class LinearExtent final : public Extent {
uint64_t end_sector() const { return physical_sector_ + num_sectors_; }
uint32_t device_index() const { return device_index_; }
bool OwnsSector(uint64_t sector) const {
return sector >= physical_sector_ && sector < end_sector();
}
private:
uint32_t device_index_;
uint64_t physical_sector_;
@ -322,9 +326,15 @@ class MetadataBuilder {
}
};
std::vector<Interval> GetFreeRegions() const;
bool IsAnyRegionCovered(const std::vector<Interval>& regions,
const LinearExtent& candidate) const;
bool IsAnyRegionAllocated(const LinearExtent& candidate) const;
void ExtentsToFreeList(const std::vector<Interval>& extents,
std::vector<Interval>* free_regions) const;
std::vector<Interval> PrioritizeSecondHalfOfSuper(const std::vector<Interval>& free_list);
std::unique_ptr<LinearExtent> ExtendFinalExtent(Partition* partition,
const std::vector<Interval>& free_list,
uint64_t sectors_needed) const;
static bool sABOverrideValue;
static bool sABOverrideSet;