aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nilfs2
diff options
context:
space:
mode:
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-06-28 06:15:26 -0400
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>2010-07-22 21:02:11 -0400
commit6c12516083cf51b6e576691ac6e20c4a32f4edb9 (patch)
tree61d3b3d2502aac37ee2a6d426be104ac8728d6aa /fs/nilfs2
parent2d72b99ecdf8cbb5d9422c54b401d9d590b2faf5 (diff)
nilfs2: implement fallback for super root search
Although nilfs redundantly uses two super blocks and each may point to different position on log, the current version of nilfs does not try fallback to the spare super block when it doesn't find any valid log at the position that the primary super block points to. This has been a cause of mount failures due to write order reversals on barrier less block devices. This inserts fallback code in error path of nilfs_search_super_root routine to resolve the mount failure problem. Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Diffstat (limited to 'fs/nilfs2')
-rw-r--r--fs/nilfs2/the_nilfs.c52
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 @@
38static LIST_HEAD(nilfs_objects); 38static LIST_HEAD(nilfs_objects);
39static DEFINE_SPINLOCK(nilfs_lock); 39static DEFINE_SPINLOCK(nilfs_lock);
40 40
41static int nilfs_valid_sb(struct nilfs_super_block *sbp);
42
41void nilfs_set_last_segment(struct the_nilfs *nilfs, 43void 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);