nfsd: move some of fh_compose into helper functions
[safe/jmp/linux-2.6] / fs / nilfs2 / recovery.c
index 877dc1b..d80cc71 100644 (file)
@@ -28,7 +28,6 @@
 #include "segment.h"
 #include "sufile.h"
 #include "page.h"
-#include "seglist.h"
 #include "segbuf.h"
 
 /*
@@ -92,9 +91,6 @@ static int nilfs_warn_segment_error(int err)
                printk(KERN_WARNING
                       "NILFS warning: No super root in the last segment\n");
                break;
-       case NILFS_SEG_VALID:
-       default:
-               BUG();
        }
        return -EINVAL;
 }
@@ -398,6 +394,24 @@ static void dispose_recovery_list(struct list_head *head)
        }
 }
 
+struct nilfs_segment_entry {
+       struct list_head        list;
+       __u64                   segnum;
+};
+
+static int nilfs_segment_list_add(struct list_head *head, __u64 segnum)
+{
+       struct nilfs_segment_entry *ent = kmalloc(sizeof(*ent), GFP_NOFS);
+
+       if (unlikely(!ent))
+               return -ENOMEM;
+
+       ent->segnum = segnum;
+       INIT_LIST_HEAD(&ent->list);
+       list_add_tail(&ent->list, head);
+       return 0;
+}
+
 void nilfs_dispose_segment_list(struct list_head *head)
 {
        while (!list_empty(head)) {
@@ -405,11 +419,12 @@ void nilfs_dispose_segment_list(struct list_head *head)
                        = list_entry(head->next,
                                     struct nilfs_segment_entry, list);
                list_del(&ent->list);
-               nilfs_free_segment_entry(ent);
+               kfree(ent);
        }
 }
 
 static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
+                                             struct nilfs_sb_info *sbi,
                                              struct nilfs_recovery_info *ri)
 {
        struct list_head *head = &ri->ri_used_segments;
@@ -424,6 +439,7 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
        segnum[2] = ri->ri_segnum;
        segnum[3] = ri->ri_nextnum;
 
+       nilfs_attach_writer(nilfs, sbi);
        /*
         * Releasing the next segment of the latest super root.
         * The next segment is invalidated by this recovery.
@@ -432,49 +448,25 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
        if (unlikely(err))
                goto failed;
 
-       err = -ENOMEM;
        for (i = 1; i < 4; i++) {
-               ent = nilfs_alloc_segment_entry(segnum[i]);
-               if (unlikely(!ent))
+               err = nilfs_segment_list_add(head, segnum[i]);
+               if (unlikely(err))
                        goto failed;
-               list_add_tail(&ent->list, head);
        }
 
        /*
         * Collecting segments written after the latest super root.
-        * These are marked volatile active, and won't be reallocated in
-        * the next construction.
+        * These are marked dirty to avoid being reallocated in the next write.
         */
        list_for_each_entry_safe(ent, n, head, list) {
-               if (ent->segnum == segnum[0]) {
-                       list_del(&ent->list);
-                       nilfs_free_segment_entry(ent);
-                       continue;
-               }
-               err = nilfs_open_segment_entry(ent, sufile);
-               if (unlikely(err))
-                       goto failed;
-               if (nilfs_segment_usage_clean(ent->raw_su)) {
-                       nilfs_segment_usage_set_volatile_active(ent->raw_su);
-                       /* Keep it open */
-               } else {
-                       /* Removing duplicated entries */
-                       list_del(&ent->list);
-                       nilfs_close_segment_entry(ent, sufile);
-                       nilfs_free_segment_entry(ent);
+               if (ent->segnum != segnum[0]) {
+                       err = nilfs_sufile_scrap(sufile, ent->segnum);
+                       if (unlikely(err))
+                               goto failed;
                }
+               list_del(&ent->list);
+               kfree(ent);
        }
-       list_splice_init(head, nilfs->ns_used_segments.prev);
-
-       /*
-        * The segment having the latest super root is active, and
-        * should be deactivated on the next construction for recovery.
-        */
-       err = -ENOMEM;
-       ent = nilfs_alloc_segment_entry(segnum[0]);
-       if (unlikely(!ent))
-               goto failed;
-       list_add_tail(&ent->list, &ri->ri_used_segments);
 
        /* Allocate new segments for recovery */
        err = nilfs_sufile_alloc(sufile, &segnum[0]);
@@ -484,10 +476,10 @@ static int nilfs_prepare_segment_for_recovery(struct the_nilfs *nilfs,
        nilfs->ns_pseg_offset = 0;
        nilfs->ns_seg_seq = ri->ri_seq + 2;
        nilfs->ns_nextnum = nilfs->ns_segnum = segnum[0];
-       return 0;
 
  failed:
        /* No need to recover sufile because it will be destroyed on error */
+       nilfs_detach_writer(nilfs, sbi);
        return err;
 }
 
@@ -753,14 +745,14 @@ int nilfs_recover_logical_segments(struct the_nilfs *nilfs,
                goto failed;
 
        if (ri->ri_need_recovery == NILFS_RECOVERY_ROLLFORWARD_DONE) {
-               err = nilfs_prepare_segment_for_recovery(nilfs, ri);
+               err = nilfs_prepare_segment_for_recovery(nilfs, sbi, ri);
                if (unlikely(err)) {
                        printk(KERN_ERR "NILFS: Error preparing segments for "
                               "recovery.\n");
                        goto failed;
                }
 
-               err = nilfs_attach_segment_constructor(sbi, ri);
+               err = nilfs_attach_segment_constructor(sbi);
                if (unlikely(err))
                        goto failed;
 
@@ -814,7 +806,6 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
        u64 seg_seq;
        __u64 segnum, nextnum = 0;
        __u64 cno;
-       struct nilfs_segment_entry *ent;
        LIST_HEAD(segments);
        int empty_seg = 0, scan_newer = 0;
        int ret;
@@ -882,10 +873,11 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
 
                if (scan_newer)
                        ri->ri_need_recovery = NILFS_RECOVERY_SR_UPDATED;
-               else if (nilfs->ns_mount_state & NILFS_VALID_FS)
-                       goto super_root_found;
-
-               scan_newer = 1;
+               else {
+                       if (nilfs->ns_mount_state & NILFS_VALID_FS)
+                               goto super_root_found;
+                       scan_newer = 1;
+               }
 
                /* reset region for roll-forward */
                pseg_start += ssi.nblocks;
@@ -914,12 +906,9 @@ int nilfs_search_super_root(struct the_nilfs *nilfs, struct nilfs_sb_info *sbi,
                if (empty_seg++)
                        goto super_root_found; /* found a valid super root */
 
-               ent = nilfs_alloc_segment_entry(segnum);
-               if (unlikely(!ent)) {
-                       ret = -ENOMEM;
+               ret = nilfs_segment_list_add(&segments, segnum);
+               if (unlikely(ret))
                        goto failed;
-               }
-               list_add_tail(&ent->list, &segments);
 
                seg_seq++;
                segnum = nextnum;