]> git.neil.brown.name Git - LaFS.git/commitdiff
Close segments properly when we get to the end.
authorNeilBrown <neilb@suse.de>
Fri, 2 Jul 2010 23:29:34 +0000 (09:29 +1000)
committerNeilBrown <neilb@suse.de>
Sat, 3 Jul 2010 00:00:07 +0000 (10:00 +1000)
Passing -1 to new_segment was just *wrong*.
Do it right, and make sure to close all segments, and
release refcounts, at unmount.

Signed-off-by: NeilBrown <neilb@suse.de>
cluster.c
lafs.h
super.c

index 55692055a62e2c31042df9fe256b352b7cb0809d..526fb9d1fd9ff2b8006cb69aee425d8b7568bdb4 100644 (file)
--- a/cluster.c
+++ b/cluster.c
@@ -396,26 +396,46 @@ static void cluster_reset(struct fs *fs, struct wc *wc)
        
 }
 
-static int new_segment(struct fs *fs, int cnum)
+static void close_segment(struct fs *fs, int cnum)
 {
-       /* new_segment can fail if cnum > 0 and there is no
-        * clean_reserved
-        */
-       struct wc *wc = fs->wc + cnum;
-       unsigned int dev;
-       u32 seg;
-
        /* Release old segment */
        /* FIXME I need lafs_seg_{de,}ref for every snapshot,
         * don't I ???
         */
+       struct wc *wc = fs->wc + cnum;
        if (wc->seg.dev >= 0) {
+               if (cnum) {
+                       spin_lock(&fs->lock);
+                       fs->clean_reserved -= seg_remainder(fs, &wc->seg);
+                       spin_unlock(&fs->lock);
+               }
                lafs_seg_forget(fs, wc->seg.dev, wc->seg.num);
                wc->seg.dev = -1;
        }
+}
 
-       if (cnum < 0 ||
-           (cnum && fs->clean_reserved < fs->max_segment))
+void lafs_close_all_segments(struct fs *fs)
+{
+       int cnum;
+       for (cnum = 0; cnum < WC_NUM; cnum++)
+               close_segment(fs, cnum);
+}
+
+static int new_segment(struct fs *fs, int cnum)
+{
+       /* new_segment can fail if cnum > 0 and there is no
+        * clean_reserved
+        */
+       struct wc *wc = fs->wc + cnum;
+       unsigned int dev;
+       u32 seg;
+
+       close_segment(fs, cnum);
+
+       /* FIXME if clean_reserve is too small, maybe
+        * clear it completely.
+        */
+       if ((cnum && fs->clean_reserved < fs->max_segment))
                        return -ENOSPC;
        /* This gets a reference on the 'segsum' */
        lafs_free_get(fs, &dev, &seg, 0);
@@ -1194,7 +1214,7 @@ static void cluster_flush(struct fs *fs, int cnum)
                if (cnum == 0)
                        new_segment(fs, cnum);
                else
-                       new_segment(fs, -1);
+                       close_segment(fs, cnum);
        }
 
        /* Fill in the cluster header */
diff --git a/lafs.h b/lafs.h
index 78cadfd80ae1257079fb52abe3a68d58e5f50d59..7c9928a8d1765ff241a3659ec6cfa6be6b3c9472 100644 (file)
--- a/lafs.h
+++ b/lafs.h
@@ -648,6 +648,7 @@ int lafs_calc_cluster_csum(struct cluster_head *head);
 int lafs_cluster_init(struct fs *fs, int cnum, u64 addr, u64 prev, u64 seq);
 void lafs_clusters_done(struct fs *fs);
 void lafs_done_work(struct work_struct *ws);
+void lafs_close_all_segments(struct fs *fs);
 
 /* index.c */
 void lafs_pin_block_ph(struct block *b, int ph);
diff --git a/super.c b/super.c
index 71f50980a611ca0b40a8fb692a97b95c4d0c4eea..efc2071054bb80deb624d24f494fe8cf0d35aac6 100644 (file)
--- a/super.c
+++ b/super.c
@@ -732,6 +732,7 @@ lafs_put_super(struct super_block *sb)
                set_bit(FinalCheckpoint, &fs->fsstate);
                lafs_checkpoint_unlock_wait(fs);
                lafs_cluster_wait_all(fs);
+               lafs_close_all_segments(fs);
                lafs_empty_segment_table(fs);
                lafs_seg_put_all(fs);