By using the v_flags field of the nilfs_argv struct, it is possible to
communicate additional information to the kernel. This patch defines
two new flags, which are to be used with the nilfs_clean_segments
function.

NILFS_CLEAN_SEGMENTS_DEFAULT: Normal GC operation

NILFS_CLEAN_SEGMENTS_UPDATE_SEGUSG: Do not move any blocks, just update
        the segment usage metadata

Additionally this patch implements a simple check in
nilfs_reclaim_segment. If the number of free blocks that can be gained
by cleaning the segments is below the threshold of minblocks, it sets
the NILFS_CLEAN_SEGMENTS_UPDATE_SEGUSG flag. This causes the kernel to
leave the segment alone, not move any blocks, and only update the
SUFILE.

This is useful, because if the gain of cleaning a segment is very low,
it is better to leave it alone and try cleaning a different segment.

Signed-off-by: Andreas Rohner <[email protected]>
---
 include/nilfs.h     |  2 +-
 include/nilfs2_fs.h |  6 ++++++
 lib/gc.c            | 16 ++++++++++++++--
 lib/nilfs.c         |  3 ++-
 4 files changed, 23 insertions(+), 4 deletions(-)

diff --git a/include/nilfs.h b/include/nilfs.h
index 56286a9..5ca8bec 100644
--- a/include/nilfs.h
+++ b/include/nilfs.h
@@ -304,7 +304,7 @@ ssize_t nilfs_get_vinfo(const struct nilfs *, struct 
nilfs_vinfo *, size_t);
 ssize_t nilfs_get_bdescs(const struct nilfs *, struct nilfs_bdesc *, size_t);
 int nilfs_clean_segments(struct nilfs *, struct nilfs_vdesc *, size_t,
                         struct nilfs_period *, size_t, __u64 *, size_t,
-                        struct nilfs_bdesc *, size_t, __u64 *, size_t);
+                        struct nilfs_bdesc *, size_t, __u64 *, size_t, int);
 int nilfs_sync(const struct nilfs *, nilfs_cno_t *);
 int nilfs_resize(struct nilfs *nilfs, off_t size);
 int nilfs_set_alloc_range(struct nilfs *nilfs, off_t start, off_t end);
diff --git a/include/nilfs2_fs.h b/include/nilfs2_fs.h
index e674f44..1ac558f 100644
--- a/include/nilfs2_fs.h
+++ b/include/nilfs2_fs.h
@@ -731,6 +731,12 @@ struct nilfs_cpmode {
        __u32 cm_pad;
 };
 
+/* values for v_flags */
+enum {
+       NILFS_CLEAN_SEGMENTS_DEFAULT,
+       NILFS_CLEAN_SEGMENTS_UPDATE_SEGUSG,
+};
+
 /**
  * struct nilfs_argv - argument vector
  * @v_base: pointer on data array from userspace
diff --git a/lib/gc.c b/lib/gc.c
index 0b0e2d6..cbae0f3 100644
--- a/lib/gc.c
+++ b/lib/gc.c
@@ -616,6 +616,8 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
        struct nilfs_vector *vdescv, *bdescv, *periodv, *vblocknrv;
        sigset_t sigset, oldset, waitset;
        ssize_t n, ret = -1;
+       __u32 freeblocks;
+       int cleaning_flags = NILFS_CLEAN_SEGMENTS_DEFAULT;
 
        if (nsegs == 0)
                return 0;
@@ -678,6 +680,13 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
                goto out_lock;
        }
 
+       freeblocks = (nilfs_get_blocks_per_segment(nilfs) * n)
+                               - (nilfs_vector_get_size(vdescv)
+                               + nilfs_vector_get_size(bdescv));
+
+       if (freeblocks < minblocks * n)
+               cleaning_flags = NILFS_CLEAN_SEGMENTS_UPDATE_SEGUSG;
+
        ret = nilfs_clean_segments(nilfs,
                                   nilfs_vector_get_data(vdescv),
                                   nilfs_vector_get_size(vdescv),
@@ -687,12 +696,15 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
                                   nilfs_vector_get_size(vblocknrv),
                                   nilfs_vector_get_data(bdescv),
                                   nilfs_vector_get_size(bdescv),
-                                  segnums, n);
+                                  segnums, n, cleaning_flags);
        if (ret < 0) {
                nilfs_gc_logger(LOG_ERR, "cannot clean segments: %s",
                                strerror(errno));
        } else {
-               ret = n;
+               if (cleaning_flags == NILFS_CLEAN_SEGMENTS_UPDATE_SEGUSG)
+                       ret = -EGCTRYAGAIN;
+               else
+                       ret = n;
        }
 
 out_lock:
diff --git a/lib/nilfs.c b/lib/nilfs.c
index ebe50b8..50eed5e 100644
--- a/lib/nilfs.c
+++ b/lib/nilfs.c
@@ -627,7 +627,7 @@ int nilfs_clean_segments(struct nilfs *nilfs,
                         struct nilfs_period *periods, size_t nperiods,
                         __u64 *vblocknrs, size_t nvblocknrs,
                         struct nilfs_bdesc *bdescs, size_t nbdescs,
-                        __u64 *segnums, size_t nsegs)
+                        __u64 *segnums, size_t nsegs, int flags)
 {
        struct nilfs_argv argv[5];
 
@@ -639,6 +639,7 @@ int nilfs_clean_segments(struct nilfs *nilfs,
        argv[0].v_base = (unsigned long)vdescs;
        argv[0].v_nmembs = nvdescs;
        argv[0].v_size = sizeof(struct nilfs_vdesc);
+       argv[0].v_flags = flags;
        argv[1].v_base = (unsigned long)periods;
        argv[1].v_nmembs = nperiods;
        argv[1].v_size = sizeof(struct nilfs_period);
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to