[PATCH 1/2] lib/gc.c: refactor reclaim function

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add the following structures and functions to libnilfsgc library
and its header file (i.e. nilfs_gc.h):

 - nilfs_xreclaim_segment() function
 - nilfs_reclaim_params struct
 - nilfs_reclaim_stat struct
 - nilfs_assess_segment() inline function

nilfs_xreclaim_segment() function is the enhanced version of
nilfs_reclaim_segment().  This function takes GC parameters in an
expandable way using nilfs_reclaim_params structure, and outputs
statistics information of garbage collection including count of
live/dead blocks if a valid pointer to nilfs_reclaim_stat structure is
given.  This function also takes a dryrun argument, which allows
callers to get the statistics information without actually doing GC.

Developers can use an inline function nilfs_assess_segment() to get
the statistics information hiding the dryrun option.

Old api function nilfs_reclaim_segment() is still available for
compatibility reason, but the implementation is replaced by
nilfs_xreclaim_segment() function.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx>
---
 include/nilfs_gc.h |   60 ++++++++++++++++++++++++++++
 lib/gc.c           |  111 +++++++++++++++++++++++++++++++++++++++++++++-------
 2 files changed, 156 insertions(+), 15 deletions(-)

diff --git a/include/nilfs_gc.h b/include/nilfs_gc.h
index 72e9947..e49cbf4 100644
--- a/include/nilfs_gc.h
+++ b/include/nilfs_gc.h
@@ -14,10 +14,70 @@
 #include <sys/types.h>
 #include "nilfs.h"
 
+/* flags for nilfs_reclaim_params struct */
+#define NILFS_RECLAIM_PARAM_PROTSEQ	(1UL << 0)
+#define NILFS_RECLAIM_PARAM_PROTCNO	(1UL << 1)
+#define __NR_NILFS_RECLAIM_PARAMS	2
+
+/**
+ * struct nilfs_reclaim_params - structure to specify GC parameters
+ * @flags: flags of valid fields
+ * @reserved: padding bytes
+ * @protseq: start of sequence number of protected segments
+ * @protcno: start number of checkpoint to be protected
+ */
+struct nilfs_reclaim_params {
+	unsigned long flags;
+	unsigned long reserved;
+	__u64 protseq;
+	nilfs_cno_t protcno;
+};
+
+/**
+ * struct nilfs_reclaim_stat - structure to store GC statistics
+ * @exflags: flags for extended fields (reserved)
+ * @cleaned_segs: number of cleaned segments
+ * @protected_segs: number of protected (deselected) segments
+ * @deferred_segs: number of deferred segments
+ * @live_blks: number of live (in-use) blocks
+ * @live_vblks: number of live (in-use) virtual blocks
+ * @live_pblks: number of live (in-use) DAT file blocks
+ * @defunct_blks: number of defunct (reclaimable) blocks
+ * @defunct_vblks: number of defunct (reclaimable) virtual blocks
+ * @defunct_pblks: number of defunct (reclaimable) DAT file blocks
+ * @freed_vblks: number of freed virtual blocks
+ */
+struct nilfs_reclaim_stat {
+	unsigned long exflags;
+	size_t cleaned_segs;
+	size_t protected_segs;
+	size_t deferred_segs;
+	size_t live_blks;
+	size_t live_vblks;
+	size_t live_pblks;
+	size_t defunct_blks;
+	size_t defunct_vblks;
+	size_t defunct_pblks;
+	size_t freed_vblks;
+};
+
 ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 			      __u64 *segnums, size_t nsegs,
 			      __u64 protseq, nilfs_cno_t protcno);
 
+int nilfs_xreclaim_segment(struct nilfs *nilfs,
+			   __u64 *segnums, size_t nsegs, int dryrun,
+			   const struct nilfs_reclaim_params *params,
+			   struct nilfs_reclaim_stat *stat);
+
+static inline int
+nilfs_assess_segment(struct nilfs *nilfs,
+		     __u64 *segnums, size_t nsegs,
+		     const struct nilfs_reclaim_params *params,
+		     struct nilfs_reclaim_stat *stat)
+{
+	return nilfs_xreclaim_segment(nilfs, segnums, nsegs, 1, params, stat);
+}
 
 static inline int nilfs_suinfo_reclaimable(const struct nilfs_suinfo *si)
 {
diff --git a/lib/gc.c b/lib/gc.c
index 1152299..71c7307 100644
--- a/lib/gc.c
+++ b/lib/gc.c
@@ -601,20 +601,34 @@ static int nilfs_toss_bdescs(struct nilfs_vector *bdescv)
 }
 
 /**
- * nilfs_reclaim_segment - reclaim segments
+ * nilfs_xreclaim_segment - reclaim segments (enhanced API)
  * @nilfs: nilfs object
  * @segnums: array of segment numbers storing selected segments
  * @nsegs: size of the @segnums array
- * @protseq: start of sequence number of protected segments
- * @protcno: start checkpoint number of protected period
+ * @dryrun: dry-run flag
+ * @params: reclaim parameters
+ * @stat: reclaim statistics
  */
-ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
-			      __u64 *segnums, size_t nsegs,
-			      __u64 protseq, nilfs_cno_t protcno)
+int nilfs_xreclaim_segment(struct nilfs *nilfs,
+			   __u64 *segnums, size_t nsegs, int dryrun,
+			   const struct nilfs_reclaim_params *params,
+			   struct nilfs_reclaim_stat *stat)
 {
 	struct nilfs_vector *vdescv, *bdescv, *periodv, *vblocknrv;
 	sigset_t sigset, oldset, waitset;
+	nilfs_cno_t protcno;
 	ssize_t n, ret = -1;
+	size_t nblocks;
+
+	if (!(params->flags & NILFS_RECLAIM_PARAM_PROTSEQ) ||
+	    (params->flags & (~0UL << __NR_NILFS_RECLAIM_PARAMS))) {
+		/*
+		 * The protseq parameter is mandatory.  Unknown
+		 * parameters are rejected.
+		 */
+		errno = EINVAL;
+		return -1;
+	}
 
 	if (nsegs == 0)
 		return 0;
@@ -623,8 +637,7 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 	bdescv = nilfs_vector_create(sizeof(struct nilfs_bdesc));
 	periodv = nilfs_vector_create(sizeof(struct nilfs_period));
 	vblocknrv = nilfs_vector_create(sizeof(__u64));
-	if (vdescv == NULL || bdescv == NULL || periodv == NULL ||
-	    vblocknrv == NULL)
+	if (!vdescv || !bdescv || !periodv || !vblocknrv)
 		goto out_vec;
 
 	sigemptyset(&sigset);
@@ -633,7 +646,7 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 	ret = sigprocmask(SIG_BLOCK, &sigset, &oldset);
 	if (ret < 0) {
 		nilfs_gc_logger(LOG_ERR, "cannot block signals: %s",
-				     strerror(errno));
+				strerror(errno));
 		goto out_vec;
 	}
 
@@ -641,31 +654,66 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 	if (ret < 0)
 		goto out_sig;
 
-	n = nilfs_acc_blocks(nilfs, segnums, nsegs, protseq, vdescv, bdescv);
-	if (n <= 0) {
+	/* count blocks */
+	n = nilfs_acc_blocks(nilfs, segnums, nsegs, params->protseq, vdescv,
+			     bdescv);
+	if (n < 0) {
 		ret = n;
 		goto out_lock;
 	}
+	if (stat) {
+		stat->cleaned_segs = n;
+		stat->protected_segs = nsegs - n;
+		stat->deferred_segs = 0;
+	}
+	if (n == 0) {
+		ret = 0;
+		goto out_lock;
+	}
 
+	/* toss virtual blocks */
 	ret = nilfs_get_vdesc(nilfs, vdescv);
 	if (ret < 0)
 		goto out_lock;
 
+	nblocks = nilfs_vector_get_size(vdescv);
+	protcno = (params->flags & NILFS_RECLAIM_PARAM_PROTCNO) ?
+		params->protcno : NILFS_CNO_MAX;
+
 	ret = nilfs_toss_vdescs(nilfs, vdescv, periodv, vblocknrv, protcno);
 	if (ret < 0)
 		goto out_lock;
 
+	if (stat) {
+		stat->live_vblks = nilfs_vector_get_size(vdescv);
+		stat->defunct_vblks = nblocks - stat->live_vblks;
+		stat->freed_vblks = nilfs_vector_get_size(vblocknrv);
+	}
+
 	nilfs_vector_sort(vdescv, nilfs_comp_vdesc_blocknr);
 	nilfs_unify_period(periodv);
 
+	/* toss DAT file blocks */
 	ret = nilfs_get_bdesc(nilfs, bdescv);
 	if (ret < 0)
 		goto out_lock;
 
+	nblocks = nilfs_vector_get_size(bdescv);
 	ret = nilfs_toss_bdescs(bdescv);
 	if (ret < 0)
 		goto out_lock;
 
+	if (stat) {
+		stat->live_pblks = nilfs_vector_get_size(bdescv);
+		stat->defunct_pblks = nblocks - stat->live_pblks;
+
+		stat->live_blks = stat->live_vblks + stat->live_pblks;
+		stat->defunct_blks = n * nilfs_get_blocks_per_segment(nilfs) -
+			stat->live_blks;
+	}
+	if (dryrun)
+		goto out_lock;
+
 	ret = sigpending(&waitset);
 	if (ret < 0) {
 		nilfs_gc_logger(LOG_ERR, "cannot test signals: %s",
@@ -690,13 +738,14 @@ ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
 	if (ret < 0) {
 		nilfs_gc_logger(LOG_ERR, "cannot clean segments: %s",
 				strerror(errno));
-	} else {
-		ret = n;
 	}
 
 out_lock:
-	if (nilfs_unlock_cleaner(nilfs) < 0)
-		ret = -1;
+	if (nilfs_unlock_cleaner(nilfs) < 0) {
+		nilfs_gc_logger(LOG_CRIT, "failed to unlock cleaner: %s",
+				strerror(errno));
+		exit(1);
+	}
 
 out_sig:
 	sigprocmask(SIG_SETMASK, &oldset, NULL);
@@ -710,6 +759,38 @@ out_vec:
 		nilfs_vector_destroy(periodv);
 	if (vblocknrv != NULL)
 		nilfs_vector_destroy(vblocknrv);
+	/*
+	 * Flags of valid fields in stat->exflags must be unset.
+	 */
+	return ret;
+}
 
+/**
+ * nilfs_reclaim_segment - reclaim segments
+ * @nilfs: nilfs object
+ * @segnums: array of segment numbers storing selected segments
+ * @nsegs: size of the @segnums array
+ * @protseq: start of sequence number of protected segments
+ * @protcno: start checkpoint number of protected period
+ */
+ssize_t nilfs_reclaim_segment(struct nilfs *nilfs,
+			      __u64 *segnums, size_t nsegs,
+			      __u64 protseq, nilfs_cno_t protcno)
+{
+	struct nilfs_reclaim_params params;
+	struct nilfs_reclaim_stat stat;
+	int ret;
+
+	params.flags =
+		NILFS_RECLAIM_PARAM_PROTSEQ | NILFS_RECLAIM_PARAM_PROTCNO;
+	params.reserved = 0;
+	params.protseq = protseq;
+	params.protcno = protcno;
+	memset(&stat, 0, sizeof(stat));
+
+	ret = nilfs_xreclaim_segment(nilfs, segnums, nsegs, 0,
+				     &params, &stat);
+	if (!ret)
+		ret = stat.cleaned_segs;
 	return ret;
 }
-- 
1.7.9.3

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




[Index of Archives]     [Linux Filesystem Development]     [Linux BTRFS]     [Linux CIFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux SCSI]

  Powered by Linux