.. | .. |
---|
13 | 13 | #include <linux/blkdev.h> |
---|
14 | 14 | #include <linux/backing-dev.h> |
---|
15 | 15 | #include <linux/random.h> |
---|
| 16 | +#include <linux/log2.h> |
---|
16 | 17 | #include <linux/crc32.h> |
---|
17 | 18 | #include "nilfs.h" |
---|
18 | 19 | #include "segment.h" |
---|
.. | .. |
---|
86 | 87 | { |
---|
87 | 88 | might_sleep(); |
---|
88 | 89 | if (nilfs_init(nilfs)) { |
---|
89 | | - nilfs_sysfs_delete_device_group(nilfs); |
---|
90 | 90 | brelse(nilfs->ns_sbh[0]); |
---|
91 | 91 | brelse(nilfs->ns_sbh[1]); |
---|
92 | 92 | } |
---|
.. | .. |
---|
193 | 193 | } |
---|
194 | 194 | |
---|
195 | 195 | /** |
---|
| 196 | + * nilfs_get_blocksize - get block size from raw superblock data |
---|
| 197 | + * @sb: super block instance |
---|
| 198 | + * @sbp: superblock raw data buffer |
---|
| 199 | + * @blocksize: place to store block size |
---|
| 200 | + * |
---|
| 201 | + * nilfs_get_blocksize() calculates the block size from the block size |
---|
| 202 | + * exponent information written in @sbp and stores it in @blocksize, |
---|
| 203 | + * or aborts with an error message if it's too large. |
---|
| 204 | + * |
---|
| 205 | + * Return Value: On success, 0 is returned. If the block size is too |
---|
| 206 | + * large, -EINVAL is returned. |
---|
| 207 | + */ |
---|
| 208 | +static int nilfs_get_blocksize(struct super_block *sb, |
---|
| 209 | + struct nilfs_super_block *sbp, int *blocksize) |
---|
| 210 | +{ |
---|
| 211 | + unsigned int shift_bits = le32_to_cpu(sbp->s_log_block_size); |
---|
| 212 | + |
---|
| 213 | + if (unlikely(shift_bits > |
---|
| 214 | + ilog2(NILFS_MAX_BLOCK_SIZE) - BLOCK_SIZE_BITS)) { |
---|
| 215 | + nilfs_err(sb, "too large filesystem blocksize: 2 ^ %u KiB", |
---|
| 216 | + shift_bits); |
---|
| 217 | + return -EINVAL; |
---|
| 218 | + } |
---|
| 219 | + *blocksize = BLOCK_SIZE << shift_bits; |
---|
| 220 | + return 0; |
---|
| 221 | +} |
---|
| 222 | + |
---|
| 223 | +/** |
---|
196 | 224 | * load_nilfs - load and recover the nilfs |
---|
197 | 225 | * @nilfs: the_nilfs structure to be released |
---|
198 | 226 | * @sb: super block isntance used to recover past segment |
---|
.. | .. |
---|
245 | 273 | nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime); |
---|
246 | 274 | |
---|
247 | 275 | /* verify consistency between two super blocks */ |
---|
248 | | - blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size); |
---|
| 276 | + err = nilfs_get_blocksize(sb, sbp[0], &blocksize); |
---|
| 277 | + if (err) |
---|
| 278 | + goto scan_error; |
---|
| 279 | + |
---|
249 | 280 | if (blocksize != nilfs->ns_blocksize) { |
---|
250 | 281 | nilfs_warn(sb, |
---|
251 | 282 | "blocksize differs between two super blocks (%d != %d)", |
---|
252 | 283 | blocksize, nilfs->ns_blocksize); |
---|
| 284 | + err = -EINVAL; |
---|
253 | 285 | goto scan_error; |
---|
254 | 286 | } |
---|
255 | 287 | |
---|
.. | .. |
---|
271 | 303 | nilfs_err(sb, "error %d while loading super root", err); |
---|
272 | 304 | goto failed; |
---|
273 | 305 | } |
---|
| 306 | + |
---|
| 307 | + err = nilfs_sysfs_create_device_group(sb); |
---|
| 308 | + if (unlikely(err)) |
---|
| 309 | + goto sysfs_error; |
---|
274 | 310 | |
---|
275 | 311 | if (valid_fs) |
---|
276 | 312 | goto skip_recovery; |
---|
.. | .. |
---|
333 | 369 | goto failed; |
---|
334 | 370 | |
---|
335 | 371 | failed_unload: |
---|
| 372 | + nilfs_sysfs_delete_device_group(nilfs); |
---|
| 373 | + |
---|
| 374 | + sysfs_error: |
---|
336 | 375 | iput(nilfs->ns_cpfile); |
---|
337 | 376 | iput(nilfs->ns_sufile); |
---|
338 | 377 | iput(nilfs->ns_dat); |
---|
.. | .. |
---|
366 | 405 | 100)); |
---|
367 | 406 | } |
---|
368 | 407 | |
---|
| 408 | +/** |
---|
| 409 | + * nilfs_max_segment_count - calculate the maximum number of segments |
---|
| 410 | + * @nilfs: nilfs object |
---|
| 411 | + */ |
---|
| 412 | +static u64 nilfs_max_segment_count(struct the_nilfs *nilfs) |
---|
| 413 | +{ |
---|
| 414 | + u64 max_count = U64_MAX; |
---|
| 415 | + |
---|
| 416 | + do_div(max_count, nilfs->ns_blocks_per_segment); |
---|
| 417 | + return min_t(u64, max_count, ULONG_MAX); |
---|
| 418 | +} |
---|
| 419 | + |
---|
369 | 420 | void nilfs_set_nsegments(struct the_nilfs *nilfs, unsigned long nsegs) |
---|
370 | 421 | { |
---|
371 | 422 | nilfs->ns_nsegments = nsegs; |
---|
.. | .. |
---|
375 | 426 | static int nilfs_store_disk_layout(struct the_nilfs *nilfs, |
---|
376 | 427 | struct nilfs_super_block *sbp) |
---|
377 | 428 | { |
---|
| 429 | + u64 nsegments, nblocks; |
---|
| 430 | + |
---|
378 | 431 | if (le32_to_cpu(sbp->s_rev_level) < NILFS_MIN_SUPP_REV) { |
---|
379 | 432 | nilfs_err(nilfs->ns_sb, |
---|
380 | 433 | "unsupported revision (superblock rev.=%d.%d, current rev.=%d.%d). Please check the version of mkfs.nilfs(2).", |
---|
.. | .. |
---|
418 | 471 | return -EINVAL; |
---|
419 | 472 | } |
---|
420 | 473 | |
---|
421 | | - nilfs_set_nsegments(nilfs, le64_to_cpu(sbp->s_nsegments)); |
---|
| 474 | + nsegments = le64_to_cpu(sbp->s_nsegments); |
---|
| 475 | + if (nsegments > nilfs_max_segment_count(nilfs)) { |
---|
| 476 | + nilfs_err(nilfs->ns_sb, |
---|
| 477 | + "segment count %llu exceeds upper limit (%llu segments)", |
---|
| 478 | + (unsigned long long)nsegments, |
---|
| 479 | + (unsigned long long)nilfs_max_segment_count(nilfs)); |
---|
| 480 | + return -EINVAL; |
---|
| 481 | + } |
---|
| 482 | + |
---|
| 483 | + nblocks = (u64)i_size_read(nilfs->ns_sb->s_bdev->bd_inode) >> |
---|
| 484 | + nilfs->ns_sb->s_blocksize_bits; |
---|
| 485 | + if (nblocks) { |
---|
| 486 | + u64 min_block_count = nsegments * nilfs->ns_blocks_per_segment; |
---|
| 487 | + /* |
---|
| 488 | + * To avoid failing to mount early device images without a |
---|
| 489 | + * second superblock, exclude that block count from the |
---|
| 490 | + * "min_block_count" calculation. |
---|
| 491 | + */ |
---|
| 492 | + |
---|
| 493 | + if (nblocks < min_block_count) { |
---|
| 494 | + nilfs_err(nilfs->ns_sb, |
---|
| 495 | + "total number of segment blocks %llu exceeds device size (%llu blocks)", |
---|
| 496 | + (unsigned long long)min_block_count, |
---|
| 497 | + (unsigned long long)nblocks); |
---|
| 498 | + return -EINVAL; |
---|
| 499 | + } |
---|
| 500 | + } |
---|
| 501 | + |
---|
| 502 | + nilfs_set_nsegments(nilfs, nsegments); |
---|
422 | 503 | nilfs->ns_crc_seed = le32_to_cpu(sbp->s_crc_seed); |
---|
423 | 504 | return 0; |
---|
424 | 505 | } |
---|
.. | .. |
---|
443 | 524 | return crc == le32_to_cpu(sbp->s_sum); |
---|
444 | 525 | } |
---|
445 | 526 | |
---|
446 | | -static int nilfs_sb2_bad_offset(struct nilfs_super_block *sbp, u64 offset) |
---|
| 527 | +/** |
---|
| 528 | + * nilfs_sb2_bad_offset - check the location of the second superblock |
---|
| 529 | + * @sbp: superblock raw data buffer |
---|
| 530 | + * @offset: byte offset of second superblock calculated from device size |
---|
| 531 | + * |
---|
| 532 | + * nilfs_sb2_bad_offset() checks if the position on the second |
---|
| 533 | + * superblock is valid or not based on the filesystem parameters |
---|
| 534 | + * stored in @sbp. If @offset points to a location within the segment |
---|
| 535 | + * area, or if the parameters themselves are not normal, it is |
---|
| 536 | + * determined to be invalid. |
---|
| 537 | + * |
---|
| 538 | + * Return Value: true if invalid, false if valid. |
---|
| 539 | + */ |
---|
| 540 | +static bool nilfs_sb2_bad_offset(struct nilfs_super_block *sbp, u64 offset) |
---|
447 | 541 | { |
---|
448 | | - return offset < ((le64_to_cpu(sbp->s_nsegments) * |
---|
449 | | - le32_to_cpu(sbp->s_blocks_per_segment)) << |
---|
450 | | - (le32_to_cpu(sbp->s_log_block_size) + 10)); |
---|
| 542 | + unsigned int shift_bits = le32_to_cpu(sbp->s_log_block_size); |
---|
| 543 | + u32 blocks_per_segment = le32_to_cpu(sbp->s_blocks_per_segment); |
---|
| 544 | + u64 nsegments = le64_to_cpu(sbp->s_nsegments); |
---|
| 545 | + u64 index; |
---|
| 546 | + |
---|
| 547 | + if (blocks_per_segment < NILFS_SEG_MIN_BLOCKS || |
---|
| 548 | + shift_bits > ilog2(NILFS_MAX_BLOCK_SIZE) - BLOCK_SIZE_BITS) |
---|
| 549 | + return true; |
---|
| 550 | + |
---|
| 551 | + index = offset >> (shift_bits + BLOCK_SIZE_BITS); |
---|
| 552 | + do_div(index, blocks_per_segment); |
---|
| 553 | + return index < nsegments; |
---|
451 | 554 | } |
---|
452 | 555 | |
---|
453 | 556 | static void nilfs_release_super_block(struct the_nilfs *nilfs) |
---|
.. | .. |
---|
489 | 592 | { |
---|
490 | 593 | struct nilfs_super_block **sbp = nilfs->ns_sbp; |
---|
491 | 594 | struct buffer_head **sbh = nilfs->ns_sbh; |
---|
492 | | - u64 sb2off = NILFS_SB2_OFFSET_BYTES(nilfs->ns_bdev->bd_inode->i_size); |
---|
| 595 | + u64 sb2off, devsize = nilfs->ns_bdev->bd_inode->i_size; |
---|
493 | 596 | int valid[2], swp = 0; |
---|
| 597 | + |
---|
| 598 | + if (devsize < NILFS_SEG_MIN_BLOCKS * NILFS_MIN_BLOCK_SIZE + 4096) { |
---|
| 599 | + nilfs_err(sb, "device size too small"); |
---|
| 600 | + return -EINVAL; |
---|
| 601 | + } |
---|
| 602 | + sb2off = NILFS_SB2_OFFSET_BYTES(devsize); |
---|
494 | 603 | |
---|
495 | 604 | sbp[0] = nilfs_read_super_block(sb, NILFS_SB_OFFSET_BYTES, blocksize, |
---|
496 | 605 | &sbh[0]); |
---|
.. | .. |
---|
586 | 695 | if (err) |
---|
587 | 696 | goto failed_sbh; |
---|
588 | 697 | |
---|
589 | | - blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); |
---|
590 | | - if (blocksize < NILFS_MIN_BLOCK_SIZE || |
---|
591 | | - blocksize > NILFS_MAX_BLOCK_SIZE) { |
---|
| 698 | + err = nilfs_get_blocksize(sb, sbp, &blocksize); |
---|
| 699 | + if (err) |
---|
| 700 | + goto failed_sbh; |
---|
| 701 | + |
---|
| 702 | + if (blocksize < NILFS_MIN_BLOCK_SIZE) { |
---|
592 | 703 | nilfs_err(sb, |
---|
593 | 704 | "couldn't mount because of unsupported filesystem blocksize %d", |
---|
594 | 705 | blocksize); |
---|
.. | .. |
---|
631 | 742 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); |
---|
632 | 743 | |
---|
633 | 744 | err = nilfs_store_log_cursor(nilfs, sbp); |
---|
634 | | - if (err) |
---|
635 | | - goto failed_sbh; |
---|
636 | | - |
---|
637 | | - err = nilfs_sysfs_create_device_group(sb); |
---|
638 | 745 | if (err) |
---|
639 | 746 | goto failed_sbh; |
---|
640 | 747 | |
---|