diff options
-rw-r--r-- | fs/nilfs2/the_nilfs.c | 52 |
1 files changed, 50 insertions, 2 deletions
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c index 0d2a46cb75f8..88c8976c55a9 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 | { |
@@ -316,8 +318,50 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
316 | 318 | ||
317 | err = nilfs_search_super_root(nilfs, &ri); | 319 | err = nilfs_search_super_root(nilfs, &ri); |
318 | if (unlikely(err)) { | 320 | if (unlikely(err)) { |
319 | printk(KERN_ERR "NILFS: error searching super root.\n"); | 321 | struct nilfs_super_block **sbp = nilfs->ns_sbp; |
320 | goto failed; | 322 | int blocksize; |
323 | |||
324 | if (err != -EINVAL) | ||
325 | goto scan_error; | ||
326 | |||
327 | if (!nilfs_valid_sb(sbp[1])) { | ||
328 | printk(KERN_WARNING | ||
329 | "NILFS warning: unable to fall back to spare" | ||
330 | "super block\n"); | ||
331 | goto scan_error; | ||
332 | } | ||
333 | printk(KERN_INFO | ||
334 | "NILFS: try rollback from an earlier position\n"); | ||
335 | |||
336 | /* | ||
337 | * restore super block with its spare and reconfigure | ||
338 | * relevant states of the nilfs object. | ||
339 | */ | ||
340 | memcpy(sbp[0], sbp[1], nilfs->ns_sbsize); | ||
341 | nilfs->ns_crc_seed = le32_to_cpu(sbp[0]->s_crc_seed); | ||
342 | nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime); | ||
343 | |||
344 | /* verify consistency between two super blocks */ | ||
345 | blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size); | ||
346 | if (blocksize != nilfs->ns_blocksize) { | ||
347 | printk(KERN_WARNING | ||
348 | "NILFS warning: blocksize differs between " | ||
349 | "two super blocks (%d != %d)\n", | ||
350 | blocksize, nilfs->ns_blocksize); | ||
351 | goto scan_error; | ||
352 | } | ||
353 | |||
354 | err = nilfs_store_log_cursor(nilfs, sbp[0]); | ||
355 | if (err) | ||
356 | goto scan_error; | ||
357 | |||
358 | /* drop clean flag to allow roll-forward and recovery */ | ||
359 | nilfs->ns_mount_state &= ~NILFS_VALID_FS; | ||
360 | valid_fs = 0; | ||
361 | |||
362 | err = nilfs_search_super_root(nilfs, &ri); | ||
363 | if (err) | ||
364 | goto scan_error; | ||
321 | } | 365 | } |
322 | 366 | ||
323 | err = nilfs_load_super_root(nilfs, ri.ri_super_root); | 367 | err = nilfs_load_super_root(nilfs, ri.ri_super_root); |
@@ -371,6 +415,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi) | |||
371 | sbi->s_super->s_flags = s_flags; | 415 | sbi->s_super->s_flags = s_flags; |
372 | return 0; | 416 | return 0; |
373 | 417 | ||
418 | scan_error: | ||
419 | printk(KERN_ERR "NILFS: error searching super root.\n"); | ||
420 | goto failed; | ||
421 | |||
374 | failed_unload: | 422 | failed_unload: |
375 | nilfs_mdt_destroy(nilfs->ns_cpfile); | 423 | nilfs_mdt_destroy(nilfs->ns_cpfile); |
376 | nilfs_mdt_destroy(nilfs->ns_sufile); | 424 | nilfs_mdt_destroy(nilfs->ns_sufile); |