summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'fs_mgr/liblp/builder.cpp')
-rw-r--r--fs_mgr/liblp/builder.cpp78
1 files changed, 64 insertions, 14 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);