summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Anderson2018-08-01 16:14:37 -0500
committerDavid Anderson2018-08-02 12:33:41 -0500
commit4d9c7459c4fa7baaa61fb3cb930039096f844fe3 (patch)
treea07eaeca5ab8e6d680a916066ac6679dfe6d0548
parentde1daa72aaa25de8b61f004457a60b8f4527dec6 (diff)
downloadplatform-system-core-4d9c7459c4fa7baaa61fb3cb930039096f844fe3.tar.gz
platform-system-core-4d9c7459c4fa7baaa61fb3cb930039096f844fe3.tar.xz
platform-system-core-4d9c7459c4fa7baaa61fb3cb930039096f844fe3.zip
liblp: Require block-aligned partition sizes.
DM_TABLE_LOAD will reject dm-linear entries if their size is not a multiple of the backing device's logical block size. For example, a partition of 10GiB+512 bytes will fail to map in device-mapper if the logical block size is 4096 bytes. To address this, this patch adds a few changes to liblp: The block size given to lpmake is now recorded in LpGeometryMetadata. The block size must be a multiple of the sector size. In addition, partiton sizes are now aligned to the block size, and the super partition must have enough free space to allocate at least one block (in addition to storing metadata). GrowPartition now has multiple checks that the block-size invariant is not violated, to ensure that no invalid partition tables will be created. Bug: 79173901 Test: liblp_test gtest Change-Id: I484aac1f9b90ebd92dc1c89ce1e09cd89bbb441e
-rw-r--r--fs_mgr/liblp/builder.cpp78
-rw-r--r--fs_mgr/liblp/builder_test.cpp50
-rw-r--r--fs_mgr/liblp/include/liblp/builder.h23
-rw-r--r--fs_mgr/liblp/include/liblp/metadata_format.h6
-rw-r--r--fs_mgr/liblp/utility_test.cpp3
5 files changed, 125 insertions, 35 deletions
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index d3c785d33..eb429b930 100644
--- a/fs_mgr/liblp/builder.cpp
+++ b/fs_mgr/liblp/builder.cpp
@@ -48,10 +48,20 @@ bool GetBlockDeviceInfo(const std::string& block_device, BlockDeviceInfo* device
48 PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed"; 48 PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
49 return false; 49 return false;
50 } 50 }
51 if (ioctl(fd, BLKALIGNOFF, &device_info->alignment_offset) < 0) { 51
52 int alignment_offset;
53 if (ioctl(fd, BLKALIGNOFF, &alignment_offset) < 0) {
52 PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed"; 54 PERROR << __PRETTY_FUNCTION__ << "BLKIOMIN failed";
53 return false; 55 return false;
54 } 56 }
57 int logical_block_size;
58 if (ioctl(fd, BLKSSZGET, &logical_block_size) < 0) {
59 PERROR << __PRETTY_FUNCTION__ << "BLKSSZGET failed";
60 return false;
61 }
62
63 device_info->alignment_offset = static_cast<uint32_t>(alignment_offset);
64 device_info->logical_block_size = static_cast<uint32_t>(logical_block_size);
55 return true; 65 return true;
56#else 66#else
57 (void)block_device; 67 (void)block_device;
@@ -178,6 +188,7 @@ bool MetadataBuilder::Init(const LpMetadata& metadata) {
178 188
179 device_info_.alignment = geometry_.alignment; 189 device_info_.alignment = geometry_.alignment;
180 device_info_.alignment_offset = geometry_.alignment_offset; 190 device_info_.alignment_offset = geometry_.alignment_offset;
191 device_info_.logical_block_size = geometry_.logical_block_size;
181 return true; 192 return true;
182} 193}
183 194
@@ -201,6 +212,10 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
201 LERROR << "Block device size must be a multiple of 512."; 212 LERROR << "Block device size must be a multiple of 512.";
202 return false; 213 return false;
203 } 214 }
215 if (device_info_.logical_block_size % LP_SECTOR_SIZE != 0) {
216 LERROR << "Logical block size must be a multiple of 512.";
217 return false;
218 }
204 if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) { 219 if (device_info_.alignment_offset % LP_SECTOR_SIZE != 0) {
205 LERROR << "Alignment offset is not sector-aligned."; 220 LERROR << "Alignment offset is not sector-aligned.";
206 return false; 221 return false;
@@ -244,6 +259,18 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
244 return false; 259 return false;
245 } 260 }
246 261
262 // Finally, the size of the allocatable space must be a multiple of the
263 // logical block size. If we have no more free space after this
264 // computation, then we abort. Note that the last sector is inclusive,
265 // so we have to account for that.
266 uint64_t num_free_sectors = last_sector - first_sector + 1;
267 uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
268 if (num_free_sectors < sectors_per_block) {
269 LERROR << "Not enough space to allocate any partition tables.";
270 return false;
271 }
272 last_sector = first_sector + (num_free_sectors / sectors_per_block) * sectors_per_block - 1;
273
247 geometry_.first_logical_sector = first_sector; 274 geometry_.first_logical_sector = first_sector;
248 geometry_.last_logical_sector = last_sector; 275 geometry_.last_logical_sector = last_sector;
249 geometry_.metadata_max_size = metadata_max_size; 276 geometry_.metadata_max_size = metadata_max_size;
@@ -251,6 +278,7 @@ bool MetadataBuilder::Init(const BlockDeviceInfo& device_info, uint32_t metadata
251 geometry_.alignment = device_info_.alignment; 278 geometry_.alignment = device_info_.alignment;
252 geometry_.alignment_offset = device_info_.alignment_offset; 279 geometry_.alignment_offset = device_info_.alignment_offset;
253 geometry_.block_device_size = device_info_.size; 280 geometry_.block_device_size = device_info_.size;
281 geometry_.logical_block_size = device_info.logical_block_size;
254 return true; 282 return true;
255} 283}
256 284
@@ -297,6 +325,7 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
297 uint64_t end; 325 uint64_t end;
298 326
299 Interval(uint64_t start, uint64_t end) : start(start), end(end) {} 327 Interval(uint64_t start, uint64_t end) : start(start), end(end) {}
328 uint64_t length() const { return end - start; }
300 bool operator<(const Interval& other) const { return start < other.start; } 329 bool operator<(const Interval& other) const { return start < other.start; }
301 }; 330 };
302 331
@@ -343,31 +372,46 @@ bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t aligned_size)
343 free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1); 372 free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
344 } 373 }
345 374
375 const uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
376 CHECK(sectors_needed % sectors_per_block == 0);
377
346 // Find gaps that we can use for new extents. Note we store new extents in a 378 // Find gaps that we can use for new extents. Note we store new extents in a
347 // temporary vector, and only commit them if we are guaranteed enough free 379 // temporary vector, and only commit them if we are guaranteed enough free
348 // space. 380 // space.
349 std::vector<std::unique_ptr<LinearExtent>> new_extents; 381 std::vector<std::unique_ptr<LinearExtent>> new_extents;
350 for (const auto& region : free_regions) { 382 for (auto& region : free_regions) {
351 // This gap is enough to hold the remainder of the space requested, so we 383 if (region.length() % sectors_per_block != 0) {
352 // can allocate what we need and return. 384 // This should never happen, because it would imply that we
353 if (region.end - region.start >= sectors_needed) { 385 // once allocated an extent that was not a multiple of the
354 auto extent = std::make_unique<LinearExtent>(sectors_needed, region.start); 386 // block size. That extent would be rejected by DM_TABLE_LOAD.
355 sectors_needed -= extent->num_sectors(); 387 LERROR << "Region " << region.start << ".." << region.end
356 new_extents.push_back(std::move(extent)); 388 << " is not a multiple of the block size, " << sectors_per_block;
357 break; 389
390 // If for some reason the final region is mis-sized we still want
391 // to be able to grow partitions. So just to be safe, round the
392 // region down to the nearest block.
393 region.end = region.start + (region.length() / sectors_per_block) * sectors_per_block;
394 if (!region.length()) {
395 continue;
396 }
358 } 397 }
359 398
360 // This gap is not big enough to fit the remainder of the space requested, 399 uint64_t sectors = std::min(sectors_needed, region.length());
361 // so consume the whole thing and keep looking for more. 400 CHECK(sectors % sectors_per_block == 0);
362 auto extent = std::make_unique<LinearExtent>(region.end - region.start, region.start); 401
363 sectors_needed -= extent->num_sectors(); 402 auto extent = std::make_unique<LinearExtent>(sectors, region.start);
364 new_extents.push_back(std::move(extent)); 403 new_extents.push_back(std::move(extent));
404 sectors_needed -= sectors;
405 if (!sectors_needed) {
406 break;
407 }
365 } 408 }
366 if (sectors_needed) { 409 if (sectors_needed) {
367 LERROR << "Not enough free space to expand partition: " << partition->name(); 410 LERROR << "Not enough free space to expand partition: " << partition->name();
368 return false; 411 return false;
369 } 412 }
370 413
414 // Everything succeeded, so commit the new extents.
371 for (auto& extent : new_extents) { 415 for (auto& extent : new_extents) {
372 partition->AddExtent(std::move(extent)); 416 partition->AddExtent(std::move(extent));
373 } 417 }
@@ -435,6 +479,12 @@ uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
435void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) { 479void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
436 device_info_.size = device_info.size; 480 device_info_.size = device_info.size;
437 481
482 // Note that if the logical block size changes, we're probably in trouble:
483 // we could have already built extents that will only work on the previous
484 // size.
485 DCHECK(partitions_.empty() ||
486 device_info_.logical_block_size == device_info.logical_block_size);
487
438 // The kernel does not guarantee these values are present, so we only 488 // The kernel does not guarantee these values are present, so we only
439 // replace existing values if the new values are non-zero. 489 // replace existing values if the new values are non-zero.
440 if (device_info.alignment) { 490 if (device_info.alignment) {
@@ -447,7 +497,7 @@ void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info)
447 497
448bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) { 498bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
449 // Align the space needed up to the nearest sector. 499 // Align the space needed up to the nearest sector.
450 uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE); 500 uint64_t aligned_size = AlignTo(requested_size, device_info_.logical_block_size);
451 501
452 if (aligned_size > partition->size()) { 502 if (aligned_size > partition->size()) {
453 return GrowPartition(partition, aligned_size); 503 return GrowPartition(partition, aligned_size);
diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp
index 4334d51a5..f1a91c479 100644
--- a/fs_mgr/liblp/builder_test.cpp
+++ b/fs_mgr/liblp/builder_test.cpp
@@ -92,11 +92,11 @@ TEST(liblp, PartitionAlignment) {
92 Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY); 92 Partition* system = builder->AddPartition("system", TEST_GUID, LP_PARTITION_ATTR_READONLY);
93 ASSERT_NE(system, nullptr); 93 ASSERT_NE(system, nullptr);
94 EXPECT_EQ(builder->ResizePartition(system, 10000), true); 94 EXPECT_EQ(builder->ResizePartition(system, 10000), true);
95 EXPECT_EQ(system->size(), 10240); 95 EXPECT_EQ(system->size(), 12288);
96 EXPECT_EQ(system->extents().size(), 1); 96 EXPECT_EQ(system->extents().size(), 1);
97 97
98 builder->ResizePartition(system, 9000); 98 builder->ResizePartition(system, 7000);
99 EXPECT_EQ(system->size(), 9216); 99 EXPECT_EQ(system->size(), 8192);
100 EXPECT_EQ(system->extents().size(), 1); 100 EXPECT_EQ(system->extents().size(), 1);
101} 101}
102 102
@@ -120,13 +120,13 @@ TEST(liblp, MetadataAlignment) {
120 120
121TEST(liblp, InternalAlignment) { 121TEST(liblp, InternalAlignment) {
122 // Test the metadata fitting within alignment. 122 // Test the metadata fitting within alignment.
123 BlockDeviceInfo device_info(1024 * 1024, 768 * 1024, 0); 123 BlockDeviceInfo device_info(1024 * 1024, 768 * 1024, 0, 4096);
124 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 2); 124 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 2);
125 ASSERT_NE(builder, nullptr); 125 ASSERT_NE(builder, nullptr);
126 unique_ptr<LpMetadata> exported = builder->Export(); 126 unique_ptr<LpMetadata> exported = builder->Export();
127 ASSERT_NE(exported, nullptr); 127 ASSERT_NE(exported, nullptr);
128 EXPECT_EQ(exported->geometry.first_logical_sector, 1536); 128 EXPECT_EQ(exported->geometry.first_logical_sector, 1536);
129 EXPECT_EQ(exported->geometry.last_logical_sector, 2035); 129 EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
130 130
131 // Test a large alignment offset thrown in. 131 // Test a large alignment offset thrown in.
132 device_info.alignment_offset = 753664; 132 device_info.alignment_offset = 753664;
@@ -135,7 +135,7 @@ TEST(liblp, InternalAlignment) {
135 exported = builder->Export(); 135 exported = builder->Export();
136 ASSERT_NE(exported, nullptr); 136 ASSERT_NE(exported, nullptr);
137 EXPECT_EQ(exported->geometry.first_logical_sector, 1472); 137 EXPECT_EQ(exported->geometry.first_logical_sector, 1472);
138 EXPECT_EQ(exported->geometry.last_logical_sector, 2035); 138 EXPECT_EQ(exported->geometry.last_logical_sector, 2031);
139 139
140 // Alignment offset without alignment doesn't mean anything. 140 // Alignment offset without alignment doesn't mean anything.
141 device_info.alignment = 0; 141 device_info.alignment = 0;
@@ -150,7 +150,7 @@ TEST(liblp, InternalAlignment) {
150 exported = builder->Export(); 150 exported = builder->Export();
151 ASSERT_NE(exported, nullptr); 151 ASSERT_NE(exported, nullptr);
152 EXPECT_EQ(exported->geometry.first_logical_sector, 78); 152 EXPECT_EQ(exported->geometry.first_logical_sector, 78);
153 EXPECT_EQ(exported->geometry.last_logical_sector, 1975); 153 EXPECT_EQ(exported->geometry.last_logical_sector, 1973);
154 154
155 // Test a small alignment with no alignment offset. 155 // Test a small alignment with no alignment offset.
156 device_info.alignment = 11 * 1024; 156 device_info.alignment = 11 * 1024;
@@ -163,7 +163,7 @@ TEST(liblp, InternalAlignment) {
163} 163}
164 164
165TEST(liblp, InternalPartitionAlignment) { 165TEST(liblp, InternalPartitionAlignment) {
166 BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664); 166 BlockDeviceInfo device_info(512 * 1024 * 1024, 768 * 1024, 753664, 4096);
167 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2); 167 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 32 * 1024, 2);
168 168
169 Partition* a = builder->AddPartition("a", TEST_GUID, 0); 169 Partition* a = builder->AddPartition("a", TEST_GUID, 0);
@@ -381,7 +381,7 @@ TEST(liblp, MetadataTooLarge) {
381 static const size_t kMetadataSize = 64 * 1024; 381 static const size_t kMetadataSize = 64 * 1024;
382 382
383 // No space to store metadata + geometry. 383 // No space to store metadata + geometry.
384 BlockDeviceInfo device_info(kDiskSize, 0, 0); 384 BlockDeviceInfo device_info(kDiskSize, 0, 0, 4096);
385 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, kMetadataSize, 1); 385 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
386 EXPECT_EQ(builder, nullptr); 386 EXPECT_EQ(builder, nullptr);
387 387
@@ -390,8 +390,8 @@ TEST(liblp, MetadataTooLarge) {
390 builder = MetadataBuilder::New(device_info, kMetadataSize, 1); 390 builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
391 EXPECT_EQ(builder, nullptr); 391 EXPECT_EQ(builder, nullptr);
392 392
393 // Space for metadata + geometry + one free sector. 393 // Space for metadata + geometry + one free block.
394 device_info.size += LP_SECTOR_SIZE; 394 device_info.size += device_info.logical_block_size;
395 builder = MetadataBuilder::New(device_info, kMetadataSize, 1); 395 builder = MetadataBuilder::New(device_info, kMetadataSize, 1);
396 EXPECT_NE(builder, nullptr); 396 EXPECT_NE(builder, nullptr);
397 397
@@ -424,19 +424,21 @@ TEST(liblp, block_device_info) {
424 ASSERT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0); 424 ASSERT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0);
425 ASSERT_EQ(device_info.alignment_offset % LP_SECTOR_SIZE, 0); 425 ASSERT_EQ(device_info.alignment_offset % LP_SECTOR_SIZE, 0);
426 ASSERT_LE(device_info.alignment_offset, INT_MAX); 426 ASSERT_LE(device_info.alignment_offset, INT_MAX);
427 ASSERT_EQ(device_info.logical_block_size % LP_SECTOR_SIZE, 0);
427 428
428 // Having an alignment offset > alignment doesn't really make sense. 429 // Having an alignment offset > alignment doesn't really make sense.
429 ASSERT_LT(device_info.alignment_offset, device_info.alignment); 430 ASSERT_LT(device_info.alignment_offset, device_info.alignment);
430} 431}
431 432
432TEST(liblp, UpdateBlockDeviceInfo) { 433TEST(liblp, UpdateBlockDeviceInfo) {
433 BlockDeviceInfo device_info(1024 * 1024, 4096, 1024); 434 BlockDeviceInfo device_info(1024 * 1024, 4096, 1024, 4096);
434 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1); 435 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
435 ASSERT_NE(builder, nullptr); 436 ASSERT_NE(builder, nullptr);
436 437
437 EXPECT_EQ(builder->block_device_info().size, device_info.size); 438 EXPECT_EQ(builder->block_device_info().size, device_info.size);
438 EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment); 439 EXPECT_EQ(builder->block_device_info().alignment, device_info.alignment);
439 EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset); 440 EXPECT_EQ(builder->block_device_info().alignment_offset, device_info.alignment_offset);
441 EXPECT_EQ(builder->block_device_info().logical_block_size, device_info.logical_block_size);
440 442
441 device_info.alignment = 0; 443 device_info.alignment = 0;
442 device_info.alignment_offset = 2048; 444 device_info.alignment_offset = 2048;
@@ -450,3 +452,27 @@ TEST(liblp, UpdateBlockDeviceInfo) {
450 EXPECT_EQ(builder->block_device_info().alignment, 8192); 452 EXPECT_EQ(builder->block_device_info().alignment, 8192);
451 EXPECT_EQ(builder->block_device_info().alignment_offset, 2048); 453 EXPECT_EQ(builder->block_device_info().alignment_offset, 2048);
452} 454}
455
456TEST(liblp, InvalidBlockSize) {
457 BlockDeviceInfo device_info(1024 * 1024, 0, 0, 513);
458 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
459 EXPECT_EQ(builder, nullptr);
460}
461
462TEST(liblp, AlignedExtentSize) {
463 BlockDeviceInfo device_info(1024 * 1024, 0, 0, 4096);
464 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 1024, 1);
465 ASSERT_NE(builder, nullptr);
466
467 Partition* partition = builder->AddPartition("system", TEST_GUID, 0);
468 ASSERT_NE(partition, nullptr);
469 ASSERT_TRUE(builder->ResizePartition(partition, 512));
470 EXPECT_EQ(partition->size(), 4096);
471}
472
473TEST(liblp, AlignedFreeSpace) {
474 // Only one sector free - at least one block is required.
475 BlockDeviceInfo device_info(10240, 0, 0, 4096);
476 unique_ptr<MetadataBuilder> builder = MetadataBuilder::New(device_info, 512, 1);
477 ASSERT_EQ(builder, nullptr);
478}
diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h
index 0f96e3a60..e83b92297 100644
--- a/fs_mgr/liblp/include/liblp/builder.h
+++ b/fs_mgr/liblp/include/liblp/builder.h
@@ -32,11 +32,16 @@ class LinearExtent;
32 32
33// By default, partitions are aligned on a 1MiB boundary. 33// By default, partitions are aligned on a 1MiB boundary.
34static const uint32_t kDefaultPartitionAlignment = 1024 * 1024; 34static const uint32_t kDefaultPartitionAlignment = 1024 * 1024;
35static const uint32_t kDefaultBlockSize = 4096;
35 36
36struct BlockDeviceInfo { 37struct BlockDeviceInfo {
37 BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0) {} 38 BlockDeviceInfo() : size(0), alignment(0), alignment_offset(0), logical_block_size(0) {}
38 BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset) 39 BlockDeviceInfo(uint64_t size, uint32_t alignment, uint32_t alignment_offset,
39 : size(size), alignment(alignment), alignment_offset(alignment_offset) {} 40 uint32_t logical_block_size)
41 : size(size),
42 alignment(alignment),
43 alignment_offset(alignment_offset),
44 logical_block_size(logical_block_size) {}
40 // Size of the block device, in bytes. 45 // Size of the block device, in bytes.
41 uint64_t size; 46 uint64_t size;
42 // Optimal target alignment, in bytes. Partition extents will be aligned to 47 // Optimal target alignment, in bytes. Partition extents will be aligned to
@@ -46,6 +51,8 @@ struct BlockDeviceInfo {
46 // |alignment_offset| on the target device is correctly aligned on its 51 // |alignment_offset| on the target device is correctly aligned on its
47 // parent device. This value must be 0 or a multiple of 512. 52 // parent device. This value must be 0 or a multiple of 512.
48 uint32_t alignment_offset; 53 uint32_t alignment_offset;
54 // Block size, for aligning extent sizes and partition sizes.
55 uint32_t logical_block_size;
49}; 56};
50 57
51// Abstraction around dm-targets that can be encoded into logical partition tables. 58// Abstraction around dm-targets that can be encoded into logical partition tables.
@@ -88,6 +95,8 @@ class ZeroExtent final : public Extent {
88}; 95};
89 96
90class Partition final { 97class Partition final {
98 friend class MetadataBuilder;
99
91 public: 100 public:
92 Partition(const std::string& name, const std::string& guid, uint32_t attributes); 101 Partition(const std::string& name, const std::string& guid, uint32_t attributes);
93 102
@@ -97,10 +106,6 @@ class Partition final {
97 // Remove all extents from this partition. 106 // Remove all extents from this partition.
98 void RemoveExtents(); 107 void RemoveExtents();
99 108
100 // Remove and/or shrink extents until the partition is the requested size.
101 // See MetadataBuilder::ShrinkPartition for more information.
102 void ShrinkTo(uint64_t requested_size);
103
104 const std::string& name() const { return name_; } 109 const std::string& name() const { return name_; }
105 uint32_t attributes() const { return attributes_; } 110 uint32_t attributes() const { return attributes_; }
106 const std::string& guid() const { return guid_; } 111 const std::string& guid() const { return guid_; }
@@ -108,6 +113,8 @@ class Partition final {
108 uint64_t size() const { return size_; } 113 uint64_t size() const { return size_; }
109 114
110 private: 115 private:
116 void ShrinkTo(uint64_t aligned_size);
117
111 std::string name_; 118 std::string name_;
112 std::string guid_; 119 std::string guid_;
113 std::vector<std::unique_ptr<Extent>> extents_; 120 std::vector<std::unique_ptr<Extent>> extents_;
@@ -144,7 +151,7 @@ class MetadataBuilder {
144 // size. This is a convenience method for tests. 151 // size. This is a convenience method for tests.
145 static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size, 152 static std::unique_ptr<MetadataBuilder> New(uint64_t blockdev_size, uint32_t metadata_max_size,
146 uint32_t metadata_slot_count) { 153 uint32_t metadata_slot_count) {
147 BlockDeviceInfo device_info(blockdev_size, 0, 0); 154 BlockDeviceInfo device_info(blockdev_size, 0, 0, kDefaultBlockSize);
148 return New(device_info, metadata_max_size, metadata_slot_count); 155 return New(device_info, metadata_max_size, metadata_slot_count);
149 } 156 }
150 157
diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h
index e1323e11e..52c80f7f4 100644
--- a/fs_mgr/liblp/include/liblp/metadata_format.h
+++ b/fs_mgr/liblp/include/liblp/metadata_format.h
@@ -136,6 +136,12 @@ typedef struct LpMetadataGeometry {
136 * can be used to verify the geometry against a target device. 136 * can be used to verify the geometry against a target device.
137 */ 137 */
138 uint64_t block_device_size; 138 uint64_t block_device_size;
139
140 /* 76: Logical block size of the super partition block device. This is the
141 * minimal alignment for partition and extent sizes, and it must be a
142 * multiple of LP_SECTOR_SIZE.
143 */
144 uint32_t logical_block_size;
139} __attribute__((packed)) LpMetadataGeometry; 145} __attribute__((packed)) LpMetadataGeometry;
140 146
141/* The logical partition metadata has a number of tables; they are described 147/* The logical partition metadata has a number of tables; they are described
diff --git a/fs_mgr/liblp/utility_test.cpp b/fs_mgr/liblp/utility_test.cpp
index 092dbf11c..7bf42aed9 100644
--- a/fs_mgr/liblp/utility_test.cpp
+++ b/fs_mgr/liblp/utility_test.cpp
@@ -40,7 +40,8 @@ TEST(liblp, GetMetadataOffset) {
40 80000, 40 80000,
41 0, 41 0,
42 0, 42 0,
43 1024 * 1024}; 43 1024 * 1024,
44 4096};
44 EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096); 45 EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 0), 4096);
45 EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384); 46 EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 1), 4096 + 16384);
46 EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2); 47 EXPECT_EQ(GetPrimaryMetadataOffset(geometry, 2), 4096 + 16384 * 2);