diff options
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 180 |
1 files changed, 156 insertions, 24 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 661ab762d765..33400cf0bbe2 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/blkdev.h> | 26 | #include <linux/blkdev.h> |
27 | #include <linux/backing-dev.h> | 27 | #include <linux/backing-dev.h> |
28 | #include <linux/crc32.h> | ||
28 | #include "nilfs.h" | 29 | #include "nilfs.h" |
29 | #include "segment.h" | 30 | #include "segment.h" |
30 | #include "alloc.h" | 31 | #include "alloc.h" |
@@ -105,7 +106,8 @@ void put_nilfs(struct the_nilfs *nilfs) | |||
105 | } | 106 | } |
106 | if (nilfs_init(nilfs)) { | 107 | if (nilfs_init(nilfs)) { |
107 | nilfs_destroy_gccache(nilfs); | 108 | nilfs_destroy_gccache(nilfs); |
108 | brelse(nilfs->ns_sbh); | 109 | brelse(nilfs->ns_sbh[0]); |
110 | brelse(nilfs->ns_sbh[1]); | ||
109 | } | 111 | } |
110 | kfree(nilfs); | 112 | kfree(nilfs); |
111 | } | 113 | } |
@@ -115,6 +117,7 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, | |||
115 | { | 117 | { |
116 | struct buffer_head *bh_sr; | 118 | struct buffer_head *bh_sr; |
117 | struct nilfs_super_root *raw_sr; | 119 | struct nilfs_super_root *raw_sr; |
120 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | ||
118 | unsigned dat_entry_size, segment_usage_size, checkpoint_size; | 121 | unsigned dat_entry_size, segment_usage_size, checkpoint_size; |
119 | unsigned inode_size; | 122 | unsigned inode_size; |
120 | int err; | 123 | int err; |
@@ -124,9 +127,9 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, | |||
124 | return err; | 127 | return err; |
125 | 128 | ||
126 | down_read(&nilfs->ns_sem); | 129 | down_read(&nilfs->ns_sem); |
127 | dat_entry_size = le16_to_cpu(nilfs->ns_sbp->s_dat_entry_size); | 130 | dat_entry_size = le16_to_cpu(sbp[0]->s_dat_entry_size); |
128 | checkpoint_size = le16_to_cpu(nilfs->ns_sbp->s_checkpoint_size); | 131 | checkpoint_size = le16_to_cpu(sbp[0]->s_checkpoint_size); |
129 | segment_usage_size = le16_to_cpu(nilfs->ns_sbp->s_segment_usage_size); | 132 | segment_usage_size = le16_to_cpu(sbp[0]->s_segment_usage_size); |
130 | up_read(&nilfs->ns_sem); | 133 | up_read(&nilfs->ns_sem); |
131 | 134 | ||
132 | inode_size = nilfs->ns_inode_size; | 135 | inode_size = nilfs->ns_inode_size; |
@@ -270,11 +273,8 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
270 | nilfs_mdt_destroy(nilfs->ns_dat); | 273 | nilfs_mdt_destroy(nilfs->ns_dat); |
271 | goto failed; | 274 | goto failed; |
272 | } | 275 | } |
273 | if (ri.ri_need_recovery == NILFS_RECOVERY_SR_UPDATED) { | 276 | if (ri.ri_need_recovery == NILFS_RECOVERY_SR_UPDATED) |
274 | down_write(&nilfs->ns_sem); | 277 | sbi->s_super->s_dirt = 1; |
275 | nilfs_update_last_segment(sbi, 0); | ||
276 | up_write(&nilfs->ns_sem); | ||
277 | } | ||
278 | } | 278 | } |
279 | 279 | ||
280 | set_nilfs_loaded(nilfs); | 280 | set_nilfs_loaded(nilfs); |
@@ -296,9 +296,8 @@ static unsigned long long nilfs_max_size(unsigned int blkbits) | |||
296 | return res; | 296 | return res; |
297 | } | 297 | } |
298 | 298 | ||
299 | static int | 299 | static int nilfs_store_disk_layout(struct the_nilfs *nilfs, |
300 | nilfs_store_disk_layout(struct the_nilfs *nilfs, struct super_block *sb, | 300 | struct nilfs_super_block *sbp) |
301 | struct nilfs_super_block *sbp) | ||
302 | { | 301 | { |
303 | if (le32_to_cpu(sbp->s_rev_level) != NILFS_CURRENT_REV) { | 302 | if (le32_to_cpu(sbp->s_rev_level) != NILFS_CURRENT_REV) { |
304 | printk(KERN_ERR "NILFS: revision mismatch " | 303 | printk(KERN_ERR "NILFS: revision mismatch " |
@@ -309,6 +308,10 @@ nilfs_store_disk_layout(struct the_nilfs *nilfs, struct super_block *sb, | |||
309 | NILFS_CURRENT_REV, NILFS_MINOR_REV); | 308 | NILFS_CURRENT_REV, NILFS_MINOR_REV); |
310 | return -EINVAL; | 309 | return -EINVAL; |
311 | } | 310 | } |
311 | nilfs->ns_sbsize = le16_to_cpu(sbp->s_bytes); | ||
312 | if (nilfs->ns_sbsize > BLOCK_SIZE) | ||
313 | return -EINVAL; | ||
314 | |||
312 | nilfs->ns_inode_size = le16_to_cpu(sbp->s_inode_size); | 315 | nilfs->ns_inode_size = le16_to_cpu(sbp->s_inode_size); |
313 | nilfs->ns_first_ino = le32_to_cpu(sbp->s_first_ino); | 316 | nilfs->ns_first_ino = le32_to_cpu(sbp->s_first_ino); |
314 | 317 | ||
@@ -330,6 +333,122 @@ nilfs_store_disk_layout(struct the_nilfs *nilfs, struct super_block *sb, | |||
330 | return 0; | 333 | return 0; |
331 | } | 334 | } |
332 | 335 | ||
336 | static int nilfs_valid_sb(struct nilfs_super_block *sbp) | ||
337 | { | ||
338 | static unsigned char sum[4]; | ||
339 | const int sumoff = offsetof(struct nilfs_super_block, s_sum); | ||
340 | size_t bytes; | ||
341 | u32 crc; | ||
342 | |||
343 | if (!sbp || le16_to_cpu(sbp->s_magic) != NILFS_SUPER_MAGIC) | ||
344 | return 0; | ||
345 | bytes = le16_to_cpu(sbp->s_bytes); | ||
346 | if (bytes > BLOCK_SIZE) | ||
347 | return 0; | ||
348 | crc = crc32_le(le32_to_cpu(sbp->s_crc_seed), (unsigned char *)sbp, | ||
349 | sumoff); | ||
350 | crc = crc32_le(crc, sum, 4); | ||
351 | crc = crc32_le(crc, (unsigned char *)sbp + sumoff + 4, | ||
352 | bytes - sumoff - 4); | ||
353 | return crc == le32_to_cpu(sbp->s_sum); | ||
354 | } | ||
355 | |||
356 | static int nilfs_sb2_bad_offset(struct nilfs_super_block *sbp, u64 offset) | ||
357 | { | ||
358 | return offset < ((le64_to_cpu(sbp->s_nsegments) * | ||
359 | le32_to_cpu(sbp->s_blocks_per_segment)) << | ||
360 | (le32_to_cpu(sbp->s_log_block_size) + 10)); | ||
361 | } | ||
362 | |||
363 | static void nilfs_release_super_block(struct the_nilfs *nilfs) | ||
364 | { | ||
365 | int i; | ||
366 | |||
367 | for (i = 0; i < 2; i++) { | ||
368 | if (nilfs->ns_sbp[i]) { | ||
369 | brelse(nilfs->ns_sbh[i]); | ||
370 | nilfs->ns_sbh[i] = NULL; | ||
371 | nilfs->ns_sbp[i] = NULL; | ||
372 | } | ||
373 | } | ||
374 | } | ||
375 | |||
376 | void nilfs_fall_back_super_block(struct the_nilfs *nilfs) | ||
377 | { | ||
378 | brelse(nilfs->ns_sbh[0]); | ||
379 | nilfs->ns_sbh[0] = nilfs->ns_sbh[1]; | ||
380 | nilfs->ns_sbp[0] = nilfs->ns_sbp[1]; | ||
381 | nilfs->ns_sbh[1] = NULL; | ||
382 | nilfs->ns_sbp[1] = NULL; | ||
383 | } | ||
384 | |||
385 | void nilfs_swap_super_block(struct the_nilfs *nilfs) | ||
386 | { | ||
387 | struct buffer_head *tsbh = nilfs->ns_sbh[0]; | ||
388 | struct nilfs_super_block *tsbp = nilfs->ns_sbp[0]; | ||
389 | |||
390 | nilfs->ns_sbh[0] = nilfs->ns_sbh[1]; | ||
391 | nilfs->ns_sbp[0] = nilfs->ns_sbp[1]; | ||
392 | nilfs->ns_sbh[1] = tsbh; | ||
393 | nilfs->ns_sbp[1] = tsbp; | ||
394 | } | ||
395 | |||
396 | static int nilfs_load_super_block(struct the_nilfs *nilfs, | ||
397 | struct super_block *sb, int blocksize, | ||
398 | struct nilfs_super_block **sbpp) | ||
399 | { | ||
400 | struct nilfs_super_block **sbp = nilfs->ns_sbp; | ||
401 | struct buffer_head **sbh = nilfs->ns_sbh; | ||
402 | u64 sb2off = NILFS_SB2_OFFSET_BYTES(nilfs->ns_bdev->bd_inode->i_size); | ||
403 | int valid[2], swp = 0; | ||
404 | |||
405 | sbp[0] = nilfs_read_super_block(sb, NILFS_SB_OFFSET_BYTES, blocksize, | ||
406 | &sbh[0]); | ||
407 | sbp[1] = nilfs_read_super_block(sb, sb2off, blocksize, &sbh[1]); | ||
408 | |||
409 | if (!sbp[0]) { | ||
410 | if (!sbp[1]) { | ||
411 | printk(KERN_ERR "NILFS: unable to read superblock\n"); | ||
412 | return -EIO; | ||
413 | } | ||
414 | printk(KERN_WARNING | ||
415 | "NILFS warning: unable to read primary superblock\n"); | ||
416 | } else if (!sbp[1]) | ||
417 | printk(KERN_WARNING | ||
418 | "NILFS warning: unable to read secondary superblock\n"); | ||
419 | |||
420 | valid[0] = nilfs_valid_sb(sbp[0]); | ||
421 | valid[1] = nilfs_valid_sb(sbp[1]); | ||
422 | swp = valid[1] && | ||
423 | (!valid[0] || | ||
424 | le64_to_cpu(sbp[1]->s_wtime) > le64_to_cpu(sbp[0]->s_wtime)); | ||
425 | |||
426 | if (valid[swp] && nilfs_sb2_bad_offset(sbp[swp], sb2off)) { | ||
427 | brelse(sbh[1]); | ||
428 | sbh[1] = NULL; | ||
429 | sbp[1] = NULL; | ||
430 | swp = 0; | ||
431 | } | ||
432 | if (!valid[swp]) { | ||
433 | nilfs_release_super_block(nilfs); | ||
434 | printk(KERN_ERR "NILFS: Can't find nilfs on dev %s.\n", | ||
435 | sb->s_id); | ||
436 | return -EINVAL; | ||
437 | } | ||
438 | |||
439 | if (swp) { | ||
440 | printk(KERN_WARNING "NILFS warning: broken superblock. " | ||
441 | "using spare superblock.\n"); | ||
442 | nilfs_swap_super_block(nilfs); | ||
443 | } | ||
444 | |||
445 | nilfs->ns_sbwtime[0] = le64_to_cpu(sbp[0]->s_wtime); | ||
446 | nilfs->ns_sbwtime[1] = valid[!swp] ? le64_to_cpu(sbp[1]->s_wtime) : 0; | ||
447 | nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq); | ||
448 | *sbpp = sbp[0]; | ||
449 | return 0; | ||
450 | } | ||
451 | |||
333 | /** | 452 | /** |
334 | * init_nilfs - initialize a NILFS instance. | 453 | * init_nilfs - initialize a NILFS instance. |
335 | * @nilfs: the_nilfs structure | 454 | * @nilfs: the_nilfs structure |
@@ -352,16 +471,15 @@ nilfs_store_disk_layout(struct the_nilfs *nilfs, struct super_block *sb, | |||
352 | int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | 471 | int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) |
353 | { | 472 | { |
354 | struct super_block *sb = sbi->s_super; | 473 | struct super_block *sb = sbi->s_super; |
355 | struct buffer_head *sbh; | ||
356 | struct nilfs_super_block *sbp; | 474 | struct nilfs_super_block *sbp; |
357 | struct backing_dev_info *bdi; | 475 | struct backing_dev_info *bdi; |
358 | int blocksize; | 476 | int blocksize; |
359 | int err = 0; | 477 | int err; |
360 | 478 | ||
361 | down_write(&nilfs->ns_sem); | 479 | down_write(&nilfs->ns_sem); |
362 | if (nilfs_init(nilfs)) { | 480 | if (nilfs_init(nilfs)) { |
363 | /* Load values from existing the_nilfs */ | 481 | /* Load values from existing the_nilfs */ |
364 | sbp = nilfs->ns_sbp; | 482 | sbp = nilfs->ns_sbp[0]; |
365 | err = nilfs_store_magic_and_option(sb, sbp, data); | 483 | err = nilfs_store_magic_and_option(sb, sbp, data); |
366 | if (err) | 484 | if (err) |
367 | goto out; | 485 | goto out; |
@@ -377,36 +495,50 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
377 | goto out; | 495 | goto out; |
378 | } | 496 | } |
379 | 497 | ||
380 | sbp = nilfs_load_super_block(sb, &sbh); | 498 | blocksize = sb_min_blocksize(sb, BLOCK_SIZE); |
381 | if (!sbp) { | 499 | if (!blocksize) { |
500 | printk(KERN_ERR "NILFS: unable to set blocksize\n"); | ||
382 | err = -EINVAL; | 501 | err = -EINVAL; |
383 | goto out; | 502 | goto out; |
384 | } | 503 | } |
504 | err = nilfs_load_super_block(nilfs, sb, blocksize, &sbp); | ||
505 | if (err) | ||
506 | goto out; | ||
507 | |||
385 | err = nilfs_store_magic_and_option(sb, sbp, data); | 508 | err = nilfs_store_magic_and_option(sb, sbp, data); |
386 | if (err) | 509 | if (err) |
387 | goto failed_sbh; | 510 | goto failed_sbh; |
388 | 511 | ||
389 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); | 512 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); |
390 | if (sb->s_blocksize != blocksize) { | 513 | if (sb->s_blocksize != blocksize) { |
391 | sbp = nilfs_reload_super_block(sb, &sbh, blocksize); | 514 | int hw_blocksize = bdev_hardsect_size(sb->s_bdev); |
392 | if (!sbp) { | 515 | |
516 | if (blocksize < hw_blocksize) { | ||
517 | printk(KERN_ERR | ||
518 | "NILFS: blocksize %d too small for device " | ||
519 | "(sector-size = %d).\n", | ||
520 | blocksize, hw_blocksize); | ||
393 | err = -EINVAL; | 521 | err = -EINVAL; |
522 | goto failed_sbh; | ||
523 | } | ||
524 | nilfs_release_super_block(nilfs); | ||
525 | sb_set_blocksize(sb, blocksize); | ||
526 | |||
527 | err = nilfs_load_super_block(nilfs, sb, blocksize, &sbp); | ||
528 | if (err) | ||
394 | goto out; | 529 | goto out; |
395 | /* not failed_sbh; sbh is released automatically | 530 | /* not failed_sbh; sbh is released automatically |
396 | when reloading fails. */ | 531 | when reloading fails. */ |
397 | } | ||
398 | } | 532 | } |
399 | nilfs->ns_blocksize_bits = sb->s_blocksize_bits; | 533 | nilfs->ns_blocksize_bits = sb->s_blocksize_bits; |
400 | 534 | ||
401 | err = nilfs_store_disk_layout(nilfs, sb, sbp); | 535 | err = nilfs_store_disk_layout(nilfs, sbp); |
402 | if (err) | 536 | if (err) |
403 | goto failed_sbh; | 537 | goto failed_sbh; |
404 | 538 | ||
405 | sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits); | 539 | sb->s_maxbytes = nilfs_max_size(sb->s_blocksize_bits); |
406 | 540 | ||
407 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); | 541 | nilfs->ns_mount_state = le16_to_cpu(sbp->s_state); |
408 | nilfs->ns_sbh = sbh; | ||
409 | nilfs->ns_sbp = sbp; | ||
410 | 542 | ||
411 | bdi = nilfs->ns_bdev->bd_inode_backing_dev_info; | 543 | bdi = nilfs->ns_bdev->bd_inode_backing_dev_info; |
412 | if (!bdi) | 544 | if (!bdi) |
@@ -443,7 +575,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
443 | return err; | 575 | return err; |
444 | 576 | ||
445 | failed_sbh: | 577 | failed_sbh: |
446 | brelse(sbh); | 578 | nilfs_release_super_block(nilfs); |
447 | goto out; | 579 | goto out; |
448 | } | 580 | } |
449 | 581 | ||