]> git.neil.brown.name Git - LaFS.git/commitdiff
clean.c - assorted tidy-ups
authorNeilBrown <neilb@suse.de>
Sun, 15 Aug 2010 05:08:49 +0000 (15:08 +1000)
committerNeilBrown <neilb@suse.de>
Sun, 15 Aug 2010 05:08:49 +0000 (15:08 +1000)
Change some magic constants into named constants, and
improves some comments.

Signed-off-by: NeilBrown <neilb@suse.de>
clean.c
segments.c
state.h

diff --git a/clean.c b/clean.c
index 6cc09f5086440326752840c21dd17f2e427e0921..67606314f784c36887a72e59cfa2e9ffec616bfc 100644 (file)
--- a/clean.c
+++ b/clean.c
@@ -1,13 +1,19 @@
 
 /*
  * fs/lafs/clean.c
- * Copyright (C) 2005-2009
+ * Copyright (C) 2005-2010
  * Neil Brown <neilb@suse.de>
  * Released under the GPL, version 2
  */
 
 #include "lafs.h"
 
+/* mark_cleaning
+ * Given a block that is in a segment that is being cleaner, mark
+ * and pin it so that it gets cleaner.
+ * This is written to cope with failure when allocating space, but in
+ * the current design, that should never happen.
+ */
 static int mark_cleaning(struct block *b)
 {
        int err;
@@ -51,12 +57,16 @@ static int mark_cleaning(struct block *b)
        return 0;
 }
 
+/* first_in_seg
+ * Find the first block among this and its ancenstor which
+ * is in the nominated segment - if any are.
+ * As the cluster header does not differentiate between
+ * index blocks of different depths, we need to check them
+ * all.
+ */
 static struct block *first_in_seg(struct block *b, struct fs *fs,
                                  int dev, u32 seg, REFARG)
 {
-       /* Find the first block at or above b which is in the given
-        * segment and return a reference to it.
-        */
        struct address_space *as = &b->inode->i_data;
        struct block *p;
        if (in_seg(fs, dev, seg, b->physaddr))
@@ -88,8 +98,9 @@ static struct block *first_in_seg(struct block *b, struct fs *fs,
 
 /* To 'flush' the cleaner, anything on the fs->clean_leafs needs
  * to be either allocated to a cleaning-cluster or incorporated then added.
- * If the list gets empty we flush out the cleaning cluster
- * and check again.
+ * If the list gets empty we flush out the cleaning cluster and return.
+ * The next time the cleaner runs it will come back here and do
+ * some more flushing.
  */
 static void cleaner_flush(struct fs *fs)
 {
@@ -103,7 +114,7 @@ static void cleaner_flush(struct fs *fs)
                dprintk("cleaning %s\n", strblk(b));
 
                if (test_bit(B_PinPending, &b->flags)) {
-                       /* Cannot safely clean this now.  Just make
+                       /* Cannot safely clean this now.  Just mark
                         * it Dirty (it probably will be soon anyway)
                         * so it gets written to the new-data segment
                         * which will effectively clean it.
@@ -133,9 +144,14 @@ static void cleaner_flush(struct fs *fs)
        lafs_cluster_flush(fs, 1);
 }
 
+/*
+ * Load the next cluster header for this segment and perform
+ * some validity checks.  If there is a failure, simply
+ * update the 'tc' state so that it looks like there are
+ * no more clusters to find.
+ */
 static void cleaner_load(struct fs *fs, struct toclean *tc)
 {
-       /* Need to read in the cluster header */
        int err;
        err = lafs_load_page_async(fs, tc->chead,
                                   tc->haddr,
@@ -178,6 +194,14 @@ bad_header:
        tc->have_addr = 0;
 }
 
+/* Parse a cluster header and identify blocks that might need cleaning.
+ * Each time through we start parsing from the start.
+ * As we find blocks, or reject inodes we update the header so that
+ * the next time through we don't try those again.
+ * Once we have started IO on 16 different inodes, we take a break
+ * and let some of the IO complete.
+ * As we find blocks, we put them on a list to be processed later.
+ */
 static void cleaner_parse(struct fs *fs, struct toclean *tc)
 {
        u32 bnum;
@@ -393,6 +417,13 @@ static void cleaner_parse(struct fs *fs, struct toclean *tc)
                iput(ino);
 }
 
+/* Process all blocks that have been found to possibly need to be
+ * moved from their current address (i.e. cleaned).
+ * We initiate async index lookup, then if the block really
+ * is in the target segment we initiate async read.  Once
+ * that is complete we mark the block for cleaning and
+ * releaes it.
+ */
 static int cleaner_process(struct fs *fs, struct toclean *tc)
 {
        struct datablock *b, *tmp;
@@ -463,6 +494,11 @@ static int cleaner_process(struct fs *fs, struct toclean *tc)
        return rv;
 }
 
+/*
+ * Try to advance the process of cleaning the given segment.
+ * This may require loading a cluster head, parsing or reparsing
+ * that head, or loading some blocks.
+ */
 static int try_clean(struct fs *fs, struct toclean *tc)
 {
        /* return 1 if everything has been found, -ve if we need to flush */
@@ -485,6 +521,12 @@ static int try_clean(struct fs *fs, struct toclean *tc)
        return rv;
 }
 
+/*
+ * When we truncate a file, and block that is in the
+ * process of being cleaned must have that cleaning
+ * cancelled.  That is done by lafs_erase_dblock calling
+ * lafs_unclean.
+ */
 void lafs_unclean(struct datablock *db)
 {
        if (!list_empty_careful(&db->cleaning)) {
@@ -528,6 +570,7 @@ unsigned long lafs_do_clean(struct fs *fs)
         * Any activity may trigger an async read in which case we
         * leave it and move on.
         *
+        * (Most of this happens in try_clean() )
         * - If we have chosen a segment/cluster but haven't loaded the
         *   cluster head, load the cluster head.
         * - If we have loaded a cluster head but haven't processed all
@@ -545,17 +588,22 @@ unsigned long lafs_do_clean(struct fs *fs)
        if (!fs->cleaner.active &&
            !test_bit(CheckpointNeeded, &fs->fsstate) &&
            !test_bit(CleanerDisabled, &fs->fsstate)) {
-               /* choose to clean when the fraction of all space that is clean
-                * is below the faction of free space that is not clean.
+               /* Choose to clean when the fraction of all space that is clean
+                * is below the fraction of free space that is not clean.
                 * i.e. if T is total space, C is clean space, F is free space,
                 * then clean when C/T < (F-C)/F
+                * So as the amount of clean space decreases we are less tolerant
+                * of unavailable free space.
                 * Avoiding division, this is
                 *       C * F < T * (F - C)
+                * As we always reserve 3 clean segments for accounting overhead
+                * and 1 to ensure we can handle deletions,  we exclude those
+                * clean segments from the calculations.
+                * i.e. subtract 4 segments from T, C and F
                 *
                 * T we know from the size of the devices
                 * C we know by counting the clean segments
-                * F we count each time we scan the segments.
-                * We actually count free space in active segments, and add C.
+                * F we count each time we scan the segments. (total_free)
                 *  We used the largest count of last pass and this pass.
                 *
                 * We need to avoid cleaning too much in one checkpoint as
@@ -572,10 +620,9 @@ unsigned long lafs_do_clean(struct fs *fs)
                for (i = 0; i < fs->devices; i++)
                        T += fs->devs[i].size;
 
-               /* adjust to unusable space FIXME adjust F too? */
-               T -= 4 * fs->max_segment;
+               T -= TOTAL_RESERVED * fs->max_segment;
 
-               max_segs = lafs_alloc_cleaner_segs(fs, 4);
+               max_segs = lafs_alloc_cleaner_segs(fs, CLEANER_SEGS);
                if (max_segs < 1) {
                        /* If we can only clean to main segment, we may
                         * have to.  However:
@@ -596,12 +643,12 @@ unsigned long lafs_do_clean(struct fs *fs)
                                + fs->cleaner.cleaning;
                        u64 F = max(fs->total_free, fs->total_free_prev);
 
-                       if (4 * fs->max_segment < C)
-                               C -= 4 * fs->max_segment; /* adjust to unusable space FIXME adjust F too? */
+                       if (TOTAL_RESERVED * fs->max_segment < C)
+                               C -= TOTAL_RESERVED * fs->max_segment; /* adjust to unusable space FIXME adjust F too? */
                        else
                                C = 0;
-                       if (4 * fs->max_segment < F)
-                               F -= 4 * fs->max_segment; /* adjust to unusable space FIXME adjust F too? */
+                       if (TOTAL_RESERVED * fs->max_segment < F)
+                               F -= TOTAL_RESERVED * fs->max_segment; /* adjust to unusable space FIXME adjust F too? */
                        else
                                F = 0;
 
@@ -634,14 +681,14 @@ unsigned long lafs_do_clean(struct fs *fs)
                        INIT_LIST_HEAD(&tc->cleaning);
                        fs->cleaner.active = 1;
                }
-               if (i == 4)
-                       printk("CLEANER: found 4 segments to clean\n");
+               if (i == CLEANER_SEGS)
+                       dprintk("CLEANER: found %d segments to clean\n", i);
        }
        if (fs->cleaner.active) {
                int cnt = 0;
                int i;
                int doflush = 1;
-               for (i = 0; i < 4 ; i++) {
+               for (i = 0; i < CLEANER_SEGS ; i++) {
                        struct toclean *tc = &fs->cleaner.seg[i];
                        if (tc->have_addr || !list_empty(&tc->cleaning)) {
                                /* Might be something to do here */
index 214cba75a7e37f761188cfd59f2d099f5d7036ba..0656bac7117147399b9e103cece815ce654b346c 100644 (file)
@@ -619,10 +619,10 @@ int lafs_space_alloc(struct fs *fs, int credits, int why)
        spin_lock(&fs->alloc_lock);
        switch(why) {
        case NewSpace:
-               watermark += 1 * fs->max_segment;
+               watermark += RELEASE_RESERVED * fs->max_segment;
                /* FALL THROUGH */
        case ReleaseSpace:
-               watermark += 3 * fs->max_segment;
+               watermark += ACCOUNT_RESERVED * fs->max_segment;
                /* FALL THROUGH */
        case CleanSpace:
        case AccountSpace:
diff --git a/state.h b/state.h
index f0be1d30968fe90ffc8fa0a76d95a37dac012155..9e741d3b65a0a46d4766ba277fef7c98c27b1147 100644 (file)
--- a/state.h
+++ b/state.h
@@ -37,6 +37,15 @@ struct skippoint {
 };
 
 #define WC_NUM 3       /* 3 active write-clusters: new, clean, and defrag */
+#define CLEANER_SEGS 4 /* Clean at most 4 segments at a time */
+
+#define        ACCOUNT_RESERVED  3 /* Reserve 3 segments of space for accounting and
+                            * cleaning
+                            */
+#define        RELEASE_RESERVED 1 /* Reserve 1 segment of space for overhead required
+                           * to release space (e.g. delete file)
+                           */
+#define TOTAL_RESERVED (ACCOUNT_RESERVED + RELEASE_RESERVED)
 struct fs {
        struct  lafs_state      *state;
 
@@ -138,7 +147,7 @@ struct fs {
                        int have_addr;  /* true if dev/seg are valid */
                        struct list_head cleaning;
                        struct page *chead;
-               } seg[4];
+               } seg[CLEANER_SEGS];
        } cleaner;
        struct task_struct *thread;