Merge "liblp: Reclaim wasted space from unaligned partitions."
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index 699b9e7..07f9d66 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -606,14 +606,23 @@
         }
 
         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));
-        sectors_needed -= sectors;
-        if (!sectors_needed) {
+        if (sectors >= sectors_needed) {
+            sectors_needed = 0;
             break;
         }
+        sectors_needed -= sectors;
     }
     if (sectors_needed) {
         LERROR << "Not enough free space to expand partition: " << partition->name();
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 7833a25..3793964 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -209,8 +209,8 @@
         ASSERT_TRUE(builder->ResizePartition(a, a->size() + 4096));
         ASSERT_TRUE(builder->ResizePartition(b, b->size() + 4096));
     }
-    EXPECT_EQ(a->size(), 40960);
-    EXPECT_EQ(b->size(), 40960);
+    EXPECT_EQ(a->size(), 7864320);
+    EXPECT_EQ(b->size(), 7864320);
 
     unique_ptr<LpMetadata> exported = builder->Export();
     ASSERT_NE(exported, nullptr);
@@ -218,7 +218,7 @@
     // 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, 8);
+        EXPECT_EQ(extent.num_sectors, 1536);
 
         uint64_t lba = extent.target_data * LP_SECTOR_SIZE;
         uint64_t aligned_lba = AlignTo(lba, device_info.alignment, device_info.alignment_offset);
@@ -645,7 +645,7 @@
     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, 129088);
+    EXPECT_EQ(metadata->extents[2].num_sectors, 129600);
     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);
@@ -744,17 +744,41 @@
     EXPECT_EQ(system_a->extents().size(), static_cast<size_t>(1));
     EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(1));
     ASSERT_TRUE(builder->ResizePartition(system_b, 6_GiB));
-    EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(3));
+    EXPECT_EQ(system_b->extents().size(), static_cast<size_t>(2));
 
     unique_ptr<LpMetadata> exported = builder->Export();
     ASSERT_NE(exported, nullptr);
-    ASSERT_EQ(exported->extents.size(), static_cast<size_t>(4));
+    ASSERT_EQ(exported->extents.size(), static_cast<size_t>(3));
     EXPECT_EQ(exported->extents[0].target_data, 10487808);
-    EXPECT_EQ(exported->extents[0].num_sectors, 4194304);
-    EXPECT_EQ(exported->extents[1].target_data, 14682624);
-    EXPECT_EQ(exported->extents[1].num_sectors, 6288896);
-    EXPECT_EQ(exported->extents[2].target_data, 6292992);
-    EXPECT_EQ(exported->extents[2].num_sectors, 2099712);
-    EXPECT_EQ(exported->extents[3].target_data, 1536);
-    EXPECT_EQ(exported->extents[3].num_sectors, 6291456);
+    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[2].target_data, 1536);
+    EXPECT_EQ(exported->extents[2].num_sectors, 6291456);
+}
+
+TEST_F(BuilderTest, PartialExtents) {
+    // super has a minimum extent size of 768KiB.
+    BlockDeviceInfo device_info("super", 1_GiB, 768 * 1024, 0, 4096);
+    auto builder = MetadataBuilder::New(device_info, 65536, 1);
+    ASSERT_NE(builder, nullptr);
+    Partition* system = builder->AddPartition("system", 0);
+    ASSERT_NE(system, nullptr);
+    Partition* vendor = builder->AddPartition("vendor", 0);
+    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(vendor->size(), device_info.alignment);
+
+    ASSERT_TRUE(builder->ResizePartition(system, device_info.alignment * 2));
+    ASSERT_EQ(system->extents().size(), static_cast<size_t>(1));
+
+    unique_ptr<LpMetadata> exported = builder->Export();
+    ASSERT_NE(exported, nullptr);
+    ASSERT_EQ(exported->extents.size(), static_cast<size_t>(2));
+    EXPECT_EQ(exported->extents[0].target_data, 1536);
+    EXPECT_EQ(exported->extents[0].num_sectors, 3072);
+    EXPECT_EQ(exported->extents[1].target_data, 4608);
+    EXPECT_EQ(exported->extents[1].num_sectors, 1536);
 }