Skip to content

Commit

Permalink
nilfs2: implement fallback for super root search
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Ryusuke Konishi committed Jul 23, 2010
1 parent 2d72b99 commit 6c12516
Showing 1 changed file with 50 additions and 2 deletions.
52 changes: 50 additions & 2 deletions fs/nilfs2/the_nilfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
static LIST_HEAD(nilfs_objects);
static DEFINE_SPINLOCK(nilfs_lock);

static int nilfs_valid_sb(struct nilfs_super_block *sbp);

void nilfs_set_last_segment(struct the_nilfs *nilfs,
sector_t start_blocknr, u64 seq, __u64 cno)
{
Expand Down Expand Up @@ -316,8 +318,50 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)

err = nilfs_search_super_root(nilfs, &ri);
if (unlikely(err)) {
printk(KERN_ERR "NILFS: error searching super root.\n");
goto failed;
struct nilfs_super_block **sbp = nilfs->ns_sbp;
int blocksize;

if (err != -EINVAL)
goto scan_error;

if (!nilfs_valid_sb(sbp[1])) {
printk(KERN_WARNING
"NILFS warning: unable to fall back to spare"
"super block\n");
goto scan_error;
}
printk(KERN_INFO
"NILFS: try rollback from an earlier position\n");

/*
* restore super block with its spare and reconfigure
* relevant states of the nilfs object.
*/
memcpy(sbp[0], sbp[1], nilfs->ns_sbsize);
nilfs->ns_crc_seed = le32_to_cpu(sbp[0]->s_crc_seed);
nilfs->ns_sbwtime = le64_to_cpu(sbp[0]->s_wtime);

/* verify consistency between two super blocks */
blocksize = BLOCK_SIZE << le32_to_cpu(sbp[0]->s_log_block_size);
if (blocksize != nilfs->ns_blocksize) {
printk(KERN_WARNING
"NILFS warning: blocksize differs between "
"two super blocks (%d != %d)\n",
blocksize, nilfs->ns_blocksize);
goto scan_error;
}

err = nilfs_store_log_cursor(nilfs, sbp[0]);
if (err)
goto scan_error;

/* drop clean flag to allow roll-forward and recovery */
nilfs->ns_mount_state &= ~NILFS_VALID_FS;
valid_fs = 0;

err = nilfs_search_super_root(nilfs, &ri);
if (err)
goto scan_error;
}

err = nilfs_load_super_root(nilfs, ri.ri_super_root);
Expand Down Expand Up @@ -371,6 +415,10 @@ int load_nilfs(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi)
sbi->s_super->s_flags = s_flags;
return 0;

scan_error:
printk(KERN_ERR "NILFS: error searching super root.\n");
goto failed;

failed_unload:
nilfs_mdt_destroy(nilfs->ns_cpfile);
nilfs_mdt_destroy(nilfs->ns_sufile);
Expand Down

0 comments on commit 6c12516

Please sign in to comment.