]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/nilfs2/the_nilfs.c
nilfs2: get rid of nilfs_bmap_union
[karo-tx-linux.git] / fs / nilfs2 / the_nilfs.c
index 0d2a46cb75f85d55c3310ea71de92da05e317083..f2efc8c5be7fbd6a75f7f4773b095ec9c63037d3 100644 (file)
@@ -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)
 {
@@ -45,6 +47,16 @@ void nilfs_set_last_segment(struct the_nilfs *nilfs,
        nilfs->ns_last_pseg = start_blocknr;
        nilfs->ns_last_seq = seq;
        nilfs->ns_last_cno = cno;
+
+       if (!nilfs_sb_dirty(nilfs)) {
+               if (nilfs->ns_prev_seq == nilfs->ns_last_seq)
+                       goto stay_cursor;
+
+               set_nilfs_sb_dirty(nilfs);
+       }
+       nilfs->ns_prev_seq = nilfs->ns_last_seq;
+
+ stay_cursor:
        spin_unlock(&nilfs->ns_last_segment_lock);
 }
 
@@ -265,6 +277,7 @@ static int nilfs_store_log_cursor(struct the_nilfs *nilfs,
        nilfs->ns_last_cno = le64_to_cpu(sbp->s_last_cno);
        nilfs->ns_last_seq = le64_to_cpu(sbp->s_last_seq);
 
+       nilfs->ns_prev_seq = nilfs->ns_last_seq;
        nilfs->ns_seg_seq = nilfs->ns_last_seq;
        nilfs->ns_segnum =
                nilfs_get_segnum_of_block(nilfs, nilfs->ns_last_pseg);
@@ -316,8 +329,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);
@@ -371,6 +426,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);