summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTreehugger Robot2018-08-02 14:20:58 -0500
committerGerrit Code Review2018-08-02 14:20:58 -0500
commitd0e5bcc13fede800e3794e0fe5e55f233c7abd1a (patch)
treea07eaeca5ab8e6d680a916066ac6679dfe6d0548
parentddcee93c0138fc68dbc6320962a53cd4761ab94b (diff)
parent4d9c7459c4fa7baaa61fb3cb930039096f844fe3 (diff)
downloadplatform-system-core-d0e5bcc13fede800e3794e0fe5e55f233c7abd1a.tar.gz
platform-system-core-d0e5bcc13fede800e3794e0fe5e55f233c7abd1a.tar.xz
platform-system-core-d0e5bcc13fede800e3794e0fe5e55f233c7abd1a.zip
Merge changes from topic "liblp-blocksize"
* changes: liblp: Require block-aligned partition sizes. liblp: Simplify GrowPartition().
-rw-r--r--fs_mgr/liblp/builder.cpp152
-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, 157 insertions, 77 deletions
diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp
index d6eee6b32..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,87 +325,93 @@ 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 std::vector<Interval> intervals;
303 331
304 // Collect all extents in the partition table. 332 // Collect all extents in the partition table, then sort them by starting
333 // sector.
334 std::vector<Interval> extents;
305 for (const auto& partition : partitions_) { 335 for (const auto& partition : partitions_) {
306 for (const auto& extent : partition->extents()) { 336 for (const auto& extent : partition->extents()) {
307 LinearExtent* linear = extent->AsLinearExtent(); 337 LinearExtent* linear = extent->AsLinearExtent();
308 if (!linear) { 338 if (!linear) {
309 continue; 339 continue;
310 } 340 }
311 intervals.emplace_back(linear->physical_sector(), 341 extents.emplace_back(linear->physical_sector(),
312 linear->physical_sector() + extent->num_sectors()); 342 linear->physical_sector() + extent->num_sectors());
313 } 343 }
314 } 344 }
345 std::sort(extents.begin(), extents.end());
315 346
316 // Sort extents by starting sector. 347 // Convert the extent list into a list of gaps between the extents; i.e.,
317 std::sort(intervals.begin(), intervals.end()); 348 // the list of ranges that are free on the disk.
318 349 std::vector<Interval> free_regions;
319 // Find gaps that we can use for new extents. Note we store new extents in a 350 for (size_t i = 1; i < extents.size(); i++) {
320 // temporary vector, and only commit them if we are guaranteed enough free 351 const Interval& previous = extents[i - 1];
321 // space. 352 const Interval& current = extents[i];
322 std::vector<std::unique_ptr<LinearExtent>> new_extents;
323 for (size_t i = 1; i < intervals.size(); i++) {
324 const Interval& previous = intervals[i - 1];
325 const Interval& current = intervals[i];
326
327 if (previous.end >= current.start) {
328 // There is no gap between these two extents, try the next one. Note that
329 // extents may never overlap, but just for safety, we ignore them if they
330 // do.
331 DCHECK(previous.end == current.start);
332 continue;
333 }
334 353
335 uint64_t aligned = AlignSector(previous.end); 354 uint64_t aligned = AlignSector(previous.end);
336 if (aligned >= current.start) { 355 if (aligned >= current.start) {
337 // After alignment, this extent is not usable. 356 // There is no gap between these two extents, try the next one.
357 // Note that we check with >= instead of >, since alignment may
358 // bump the ending sector past the beginning of the next extent.
338 continue; 359 continue;
339 } 360 }
340 361
341 // This gap is enough to hold the remainder of the space requested, so we 362 // The new interval represents the free space starting at the end of
342 // can allocate what we need and return. 363 // the previous interval, and ending at the start of the next interval.
343 if (current.start - aligned >= sectors_needed) { 364 free_regions.emplace_back(aligned, current.start);
344 auto extent = std::make_unique<LinearExtent>(sectors_needed, aligned); 365 }
345 sectors_needed -= extent->num_sectors();
346 new_extents.push_back(std::move(extent));
347 break;
348 }
349 366
350 // This gap is not big enough to fit the remainder of the space requested, 367 // Add a final interval representing the remainder of the free space.
351 // so consume the whole thing and keep looking for more. 368 uint64_t last_free_extent_start =
352 auto extent = std::make_unique<LinearExtent>(current.start - aligned, aligned); 369 extents.empty() ? geometry_.first_logical_sector : extents.back().end;
353 sectors_needed -= extent->num_sectors(); 370 last_free_extent_start = AlignSector(last_free_extent_start);
354 new_extents.push_back(std::move(extent)); 371 if (last_free_extent_start <= geometry_.last_logical_sector) {
372 free_regions.emplace_back(last_free_extent_start, geometry_.last_logical_sector + 1);
355 } 373 }
356 374
357 // If we still have more to allocate, take it from the remaining free space 375 const uint64_t sectors_per_block = device_info_.logical_block_size / LP_SECTOR_SIZE;
358 // in the allocatable region. 376 CHECK(sectors_needed % sectors_per_block == 0);
359 if (sectors_needed) { 377
360 uint64_t first_sector; 378 // Find gaps that we can use for new extents. Note we store new extents in a
361 if (intervals.empty()) { 379 // temporary vector, and only commit them if we are guaranteed enough free
362 first_sector = geometry_.first_logical_sector; 380 // space.
363 } else { 381 std::vector<std::unique_ptr<LinearExtent>> new_extents;
364 first_sector = intervals.back().end; 382 for (auto& region : free_regions) {
383 if (region.length() % sectors_per_block != 0) {
384 // This should never happen, because it would imply that we
385 // once allocated an extent that was not a multiple of the
386 // block size. That extent would be rejected by DM_TABLE_LOAD.
387 LERROR << "Region " << region.start << ".." << region.end
388 << " is not a multiple of the block size, " << sectors_per_block;
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 }
365 } 397 }
366 DCHECK(first_sector <= geometry_.last_logical_sector);
367 398
368 // Note: After alignment, |first_sector| may be > the last usable sector. 399 uint64_t sectors = std::min(sectors_needed, region.length());
369 first_sector = AlignSector(first_sector); 400 CHECK(sectors % sectors_per_block == 0);
370 401
371 // Note: the last usable sector is inclusive. 402 auto extent = std::make_unique<LinearExtent>(sectors, region.start);
372 if (first_sector > geometry_.last_logical_sector ||
373 geometry_.last_logical_sector + 1 - first_sector < sectors_needed) {
374 LERROR << "Not enough free space to expand partition: " << partition->name();
375 return false;
376 }
377 auto extent = std::make_unique<LinearExtent>(sectors_needed, first_sector);
378 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 }
408 }
409 if (sectors_needed) {
410 LERROR << "Not enough free space to expand partition: " << partition->name();
411 return false;
379 } 412 }
380 413
414 // Everything succeeded, so commit the new extents.
381 for (auto& extent : new_extents) { 415 for (auto& extent : new_extents) {
382 partition->AddExtent(std::move(extent)); 416 partition->AddExtent(std::move(extent));
383 } 417 }
@@ -445,6 +479,12 @@ uint64_t MetadataBuilder::AlignSector(uint64_t sector) {
445void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) { 479void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info) {
446 device_info_.size = device_info.size; 480 device_info_.size = device_info.size;
447 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
448 // 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
449 // replace existing values if the new values are non-zero. 489 // replace existing values if the new values are non-zero.
450 if (device_info.alignment) { 490 if (device_info.alignment) {
@@ -457,7 +497,7 @@ void MetadataBuilder::set_block_device_info(const BlockDeviceInfo& device_info)
457 497
458bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) { 498bool MetadataBuilder::ResizePartition(Partition* partition, uint64_t requested_size) {
459 // Align the space needed up to the nearest sector. 499 // Align the space needed up to the nearest sector.
460 uint64_t aligned_size = AlignTo(requested_size, LP_SECTOR_SIZE); 500 uint64_t aligned_size = AlignTo(requested_size, device_info_.logical_block_size);
461 501
462 if (aligned_size > partition->size()) { 502 if (aligned_size > partition->size()) {
463 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);