diff options
Diffstat (limited to 'fs/nilfs2/the_nilfs.c')
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 161 |
1 files changed, 131 insertions, 30 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 8c1097327abc..37de1f062d81 100644 --- a/fs/nilfs2/the_nilfs.c +++ b/fs/nilfs2/the_nilfs.c | |||
@@ -38,6 +38,8 @@ | |||
38 | static LIST_HEAD(nilfs_objects); | 38 | static LIST_HEAD(nilfs_objects); |
39 | static DEFINE_SPINLOCK(nilfs_lock); | 39 | static DEFINE_SPINLOCK(nilfs_lock); |
40 | 40 | ||
41 | static int nilfs_valid_sb(struct nilfs_super_block *sbp); | ||
42 | |||
41 | void nilfs_set_last_segment(struct the_nilfs *nilfs, | 43 | void nilfs_set_last_segment(struct the_nilfs *nilfs, |
42 | sector_t start_blocknr, u64 seq, __u64 cno) | 44 | sector_t start_blocknr, u64 seq, __u64 cno) |
43 | { | 45 | { |
@@ -45,6 +47,16 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs, | |||
45 | nilfs->ns_last_pseg = start_blocknr; | 47 | nilfs->ns_last_pseg = start_blocknr; |
46 | nilfs->ns_last_seq = seq; | 48 | nilfs->ns_last_seq = seq; |
47 | nilfs->ns_last_cno = cno; | 49 | nilfs->ns_last_cno = cno; |
50 | |||
51 | if (!nilfs_sb_dirty(nilfs)) { | ||
52 | if (nilfs->ns_prev_seq == nilfs->ns_last_seq) | ||
53 | goto stay_cursor; | ||
54 | |||
55 | set_nilfs_sb_dirty(nilfs); | ||
56 | } | ||
57 | nilfs->ns_prev_seq = nilfs->ns_last_seq; | ||
58 | |||
59 | stay_cursor: | ||
48 | spin_unlock(&nilfs->ns_last_segment_lock); | 60 | spin_unlock(&nilfs->ns_last_segment_lock); |
49 | } | 61 | } |
50 | 62 | ||
@@ -159,8 +171,7 @@ void put_nilfs(struct the_nilfs *nilfs) | |||
159 | kfree(nilfs); | 171 | kfree(nilfs); |
160 | } | 172 | } |
161 | 173 | ||
162 | static int nilfs_load_super_root(struct the_nilfs *nilfs, | 174 | static int nilfs_load_super_root(struct the_nilfs *nilfs, sector_t sr_block) |
163 | struct nilfs_sb_info *sbi, sector_t sr_block) | ||
164 | { | 175 | { |
165 | struct buffer_head *bh_sr; | 176 | struct buffer_head *bh_sr; |
166 | struct nilfs_super_root *raw_sr; | 177 | struct nilfs_super_root *raw_sr; |
@@ -169,7 +180,7 @@ static int nilfs_load_super_root(struct the_nilfs *nilfs, | |||
169 | unsigned inode_size; | 180 | unsigned inode_size; |
170 | int err; | 181 | int err; |
171 | 182 | ||
172 | err = nilfs_read_super_root_block(sbi->s_super, sr_block, &bh_sr, 1); | 183 | err = nilfs_read_super_root_block(nilfs, sr_block, &bh_sr, 1); |
173 | if (unlikely(err)) | 184 | if (unlikely(err)) |
174 | return err; | 185 | return err; |
175 | 186 | ||
@@ -248,6 +259,37 @@ static void nilfs_clear_recovery_info(struct nilfs_recovery_info *ri) | |||
248 | } | 259 | } |
249 | 260 | ||
250 | /** | 261 | /** |
262 | * nilfs_store_log_cursor - load log cursor from a super block | ||
263 | * @nilfs: nilfs object | ||
264 | * @sbp: buffer storing super block to be read | ||
265 | * | ||
266 | * nilfs_store_log_cursor() reads the last position of the log | ||
267 | * containing a super root from a given super block, and initializes | ||
268 | * relevant information on the nilfs object preparatory for log | ||
269 | * scanning and recovery. | ||
270 | */ | ||
271 | static int nilfs_store_log_cursor(struct the_nilfs *nilfs, | ||
272 | struct nilfs_super_block *sbp) | ||
273 | { | ||
274 | int ret = 0; | ||
275 | |||
276 | nilfs->ns_last_pseg = le64_to_cpu(sbp->s_last_pseg); | ||
277 | nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno); | ||
278 | nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq); | ||
279 | |||
280 | nilfs->ns_prev_seq = nilfs->ns_last_seq; | ||
281 | nilfs->ns_seg_seq = nilfs->ns_last_seq; | ||
282 | nilfs->ns_segnum = | ||
283 | nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg); | ||
284 | nilfs->ns_cno = nilfs->ns_last_cno + 1; | ||
285 | if (nilfs->ns_segnum >= nilfs->ns_nsegments) { | ||
286 | printk(KERN_ERR "NILFS invalid last segment number.\n"); | ||
287 | ret = -EINVAL; | ||
288 | } | ||
289 | return ret; | ||
290 | } | ||
291 | |||
292 | /** | ||
251 | * load_nilfs - load and recover the nilfs | 293 | * load_nilfs - load and recover the nilfs |
252 | * @nilfs: the_nilfs structure to be released | 294 | * @nilfs: the_nilfs structure to be released |
253 | * @sbi: nilfs_sb_info used to recover past segment | 295 | * @sbi: nilfs_sb_info used to recover past segment |
@@ -285,13 +327,55 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
285 | 327 | ||
286 | nilfs_init_recovery_info(&ri); | 328 | nilfs_init_recovery_info(&ri); |
287 | 329 | ||
288 | err = nilfs_search_super_root(nilfs, sbi, &ri); | 330 | err = nilfs_search_super_root(nilfs, &ri); |
289 | if (unlikely(err)) { | 331 | if (unlikely(err)) { |
290 | printk(KERN_ERR "NILFS: error searching super root.\n"); | 332 | struct nilfs_super_block **sbp = nilfs->ns_sbp; |
291 | goto failed; | 333 | int blocksize; |
334 | |||
335 | if (err != -EINVAL) | ||
336 | goto scan_error; | ||
337 | |||
338 | if (!nilfs_valid_sb(sbp[1])) { | ||
339 | printk(KERN_WARNING | ||
340 | "NILFS warning: unable to fall back to spare" | ||
341 | "super block\n"); | ||
342 | goto scan_error; | ||
343 | } | ||
344 | printk(KERN_INFO | ||
345 | "NILFS: try rollback from an earlier position\n"); | ||
346 | |||
347 | /* | ||
348 | * restore super block with its spare and reconfigure | ||
349 | * relevant states of the nilfs object. | ||
350 | */ | ||
351 | memcpy(sbp[0], sbp[1], nilfs->ns_sbsize); | ||
352 | nilfs->ns_crc_seed = le32_to_cpu(sbp[0]->s_crc_seed); | ||
353 | nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime); | ||
354 | |||
355 | /* verify consistency between two super blocks */ | ||
356 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size); | ||
357 | if (blocksize != nilfs->ns_blocksize) { | ||
358 | printk(KERN_WARNING | ||
359 | "NILFS warning: blocksize differs between " | ||
360 | "two super blocks (%d != %d)\n", | ||
361 | blocksize, nilfs->ns_blocksize); | ||
362 | goto scan_error; | ||
363 | } | ||
364 | |||
365 | err = nilfs_store_log_cursor(nilfs, sbp[0]); | ||
366 | if (err) | ||
367 | goto scan_error; | ||
368 | |||
369 | /* drop clean flag to allow roll-forward and recovery */ | ||
370 | nilfs->ns_mount_state &= ~NILFS_VALID_FS; | ||
371 | valid_fs = 0; | ||
372 | |||
373 | err = nilfs_search_super_root(nilfs, &ri); | ||
374 | if (err) | ||
375 | goto scan_error; | ||
292 | } | 376 | } |
293 | 377 | ||
294 | err = nilfs_load_super_root(nilfs, sbi, ri.ri_super_root); | 378 | err = nilfs_load_super_root(nilfs, ri.ri_super_root); |
295 | if (unlikely(err)) { | 379 | if (unlikely(err)) { |
296 | printk(KERN_ERR "NILFS: error loading super root.\n"); | 380 | printk(KERN_ERR "NILFS: error loading super root.\n"); |
297 | goto failed; | 381 | goto failed; |
@@ -301,11 +385,23 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
301 | goto skip_recovery; | 385 | goto skip_recovery; |
302 | 386 | ||
303 | if (s_flags & MS_RDONLY) { | 387 | if (s_flags & MS_RDONLY) { |
388 | __u64 features; | ||
389 | |||
304 | if (nilfs_test_opt(sbi, NORECOVERY)) { | 390 | if (nilfs_test_opt(sbi, NORECOVERY)) { |
305 | printk(KERN_INFO "NILFS: norecovery option specified. " | 391 | printk(KERN_INFO "NILFS: norecovery option specified. " |
306 | "skipping roll-forward recovery\n"); | 392 | "skipping roll-forward recovery\n"); |
307 | goto skip_recovery; | 393 | goto skip_recovery; |
308 | } | 394 | } |
395 | features = le64_to_cpu(nilfs->ns_sbp[0]->s_feature_compat_ro) & | ||
396 | ~NILFS_FEATURE_COMPAT_RO_SUPP; | ||
397 | if (features) { | ||
398 | printk(KERN_ERR "NILFS: couldn't proceed with " | ||
399 | "recovery because of unsupported optional " | ||
400 | "features (%llx)\n", | ||
401 | (unsigned long long)features); | ||
402 | err = -EROFS; | ||
403 | goto failed_unload; | ||
404 | } | ||
309 | if (really_read_only) { | 405 | if (really_read_only) { |
310 | printk(KERN_ERR "NILFS: write access " | 406 | printk(KERN_ERR "NILFS: write access " |
311 | "unavailable, cannot proceed.\n"); | 407 | "unavailable, cannot proceed.\n"); |
@@ -320,14 +416,13 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
320 | goto failed_unload; | 416 | goto failed_unload; |
321 | } | 417 | } |
322 | 418 | ||
323 | err = nilfs_recover_logical_segments(nilfs, sbi, &ri); | 419 | err = nilfs_salvage_orphan_logs(nilfs, sbi, &ri); |
324 | if (err) | 420 | if (err) |
325 | goto failed_unload; | 421 | goto failed_unload; |
326 | 422 | ||
327 | down_write(&nilfs->ns_sem); | 423 | down_write(&nilfs->ns_sem); |
328 | nilfs->ns_mount_state |= NILFS_VALID_FS; | 424 | nilfs->ns_mount_state |= NILFS_VALID_FS; /* set "clean" flag */ |
329 | nilfs->ns_sbp[0]->s_state = cpu_to_le16(nilfs->ns_mount_state); | 425 | err = nilfs_cleanup_super(sbi); |
330 | err = nilfs_commit_super(sbi, 1); | ||
331 | up_write(&nilfs->ns_sem); | 426 | up_write(&nilfs->ns_sem); |
332 | 427 | ||
333 | if (err) { | 428 | if (err) { |
@@ -343,6 +438,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
343 | sbi->s_super->s_flags = s_flags; | 438 | sbi->s_super->s_flags = s_flags; |
344 | return 0; | 439 | return 0; |
345 | 440 | ||
441 | scan_error: | ||
442 | printk(KERN_ERR "NILFS: error searching super root.\n"); | ||
443 | goto failed; | ||
444 | |||
346 | failed_unload: | 445 | failed_unload: |
347 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 446 | nilfs_mdt_destroy(nilfs->ns_cpfile); |
348 | nilfs_mdt_destroy(nilfs->ns_sufile); | 447 | nilfs_mdt_destroy(nilfs->ns_sufile); |
@@ -515,8 +614,8 @@ static int nilfs_load_super_block(struct the_nilfs *nilfs, | |||
515 | nilfs_swap_super_block(nilfs); | 614 | nilfs_swap_super_block(nilfs); |
516 | } | 615 | } |
517 | 616 | ||
518 | nilfs->ns_sbwtime[0] = le64_to_cpu(sbp[0]->s_wtime); | 617 | nilfs->ns_sbwcount = 0; |
519 | nilfs->ns_sbwtime[1] = valid[!swp] ? le64_to_cpu(sbp[1]->s_wtime) : 0; | 618 | nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime); |
520 | nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq); | 619 | nilfs->ns_prot_seq = le64_to_cpu(sbp[valid[1] & !swp]->s_last_seq); |
521 | *sbpp = sbp[0]; | 620 | *sbpp = sbp[0]; |
522 | return 0; | 621 | return 0; |
@@ -557,6 +656,10 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
557 | if (err) | 656 | if (err) |
558 | goto out; | 657 | goto out; |
559 | 658 | ||
659 | err = nilfs_check_feature_compatibility(sb, sbp); | ||
660 | if (err) | ||
661 | goto out; | ||
662 | |||
560 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); | 663 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); |
561 | if (sb->s_blocksize != blocksize && | 664 | if (sb->s_blocksize != blocksize && |
562 | !sb_set_blocksize(sb, blocksize)) { | 665 | !sb_set_blocksize(sb, blocksize)) { |
@@ -568,7 +671,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
568 | goto out; | 671 | goto out; |
569 | } | 672 | } |
570 | 673 | ||
571 | blocksize = sb_min_blocksize(sb, BLOCK_SIZE); | 674 | blocksize = sb_min_blocksize(sb, NILFS_MIN_BLOCK_SIZE); |
572 | if (!blocksize) { | 675 | if (!blocksize) { |
573 | printk(KERN_ERR "NILFS: unable to set blocksize\n"); | 676 | printk(KERN_ERR "NILFS: unable to set blocksize\n"); |
574 | err = -EINVAL; | 677 | err = -EINVAL; |
@@ -582,7 +685,18 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
582 | if (err) | 685 | if (err) |
583 | goto failed_sbh; | 686 | goto failed_sbh; |
584 | 687 | ||
688 | err = nilfs_check_feature_compatibility(sb, sbp); | ||
689 | if (err) | ||
690 | goto failed_sbh; | ||
691 | |||
585 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); | 692 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp->s_log_block_size); |
693 | if (blocksize < NILFS_MIN_BLOCK_SIZE || | ||
694 | blocksize > NILFS_MAX_BLOCK_SIZE) { | ||
695 | printk(KERN_ERR "NILFS: couldn't mount because of unsupported " | ||
696 | "filesystem blocksize %d\n", blocksize); | ||
697 | err = -EINVAL; | ||
698 | goto failed_sbh; | ||
699 | } | ||
586 | if (sb->s_blocksize != blocksize) { | 700 | if (sb->s_blocksize != blocksize) { |
587 | int hw_blocksize = bdev_logical_block_size(sb->s_bdev); | 701 | int hw_blocksize = bdev_logical_block_size(sb->s_bdev); |
588 | 702 | ||
@@ -604,6 +718,7 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
604 | when reloading fails. */ | 718 | when reloading fails. */ |
605 | } | 719 | } |
606 | nilfs->ns_blocksize_bits = sb->s_blocksize_bits; | 720 | nilfs->ns_blocksize_bits = sb->s_blocksize_bits; |
721 | nilfs->ns_blocksize = blocksize; | ||
607 | 722 | ||
608 | err = nilfs_store_disk_layout(nilfs, sbp); | 723 | err = nilfs_store_disk_layout(nilfs, sbp); |
609 | if (err) | 724 | if (err) |
@@ -616,23 +731,9 @@ int init_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi, char *data) | |||
616 | bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; | 731 | bdi = nilfs->ns_bdev->bd_inode->i_mapping->backing_dev_info; |
617 | nilfs->ns_bdi = bdi ? : &default_backing_dev_info; | 732 | nilfs->ns_bdi = bdi ? : &default_backing_dev_info; |
618 | 733 | ||
619 | /* Finding last segment */ | 734 | err = nilfs_store_log_cursor(nilfs, sbp); |
620 | nilfs->ns_last_pseg = le64_to_cpu(sbp->s_last_pseg); | 735 | if (err) |
621 | nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno); | ||
622 | nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq); | ||
623 | |||
624 | nilfs->ns_seg_seq = nilfs->ns_last_seq; | ||
625 | nilfs->ns_segnum = | ||
626 | nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg); | ||
627 | nilfs->ns_cno = nilfs->ns_last_cno + 1; | ||
628 | if (nilfs->ns_segnum >= nilfs->ns_nsegments) { | ||
629 | printk(KERN_ERR "NILFS invalid last segment number.\n"); | ||
630 | err = -EINVAL; | ||
631 | goto failed_sbh; | 736 | goto failed_sbh; |
632 | } | ||
633 | /* Dummy values */ | ||
634 | nilfs->ns_free_segments_count = | ||
635 | nilfs->ns_nsegments - (nilfs->ns_segnum + 1); | ||
636 | 737 | ||
637 | /* Initialize gcinode cache */ | 738 | /* Initialize gcinode cache */ |
638 | err = nilfs_init_gccache(nilfs); | 739 | err = nilfs_init_gccache(nilfs); |