[PATCH 2/2] lssu: add option to print count of live blocks

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

 



This adds new options "-l" and "-p" to lssu command.

"-l" option prints count and ratio of live blocks for in-use segments,
and "-p" option allows users to specify a protection period which is
used to judge whether blocks are live or not.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx>
---
 bin/Makefile.am |    2 +
 bin/lssu.c      |  251 ++++++++++++++++++++++++++++++++++++++++++++++++-------
 man/lssu.1      |   14 +++-
 3 files changed, 235 insertions(+), 32 deletions(-)

diff --git a/bin/Makefile.am b/bin/Makefile.am
index 9d63d06..1a7de64 100644
--- a/bin/Makefile.am
+++ b/bin/Makefile.am
@@ -14,6 +14,8 @@ dumpseg_SOURCES = dumpseg.c
 lscp_SOURCES = lscp.c
 
 lssu_SOURCES = lssu.c
+lssu_LDADD = $(LDADD) $(top_builddir)/lib/libnilfsgc.la \
+	 $(top_builddir)/lib/libparser.la
 
 mkcp_SOURCES = mkcp.c
 mkcp_LDADD = $(LDADD) $(LIB_POSIX_SEM)
diff --git a/bin/lssu.c b/bin/lssu.c
index 443910e..a452d19 100644
--- a/bin/lssu.c
+++ b/bin/lssu.c
@@ -37,79 +37,195 @@
 #include <string.h>
 #endif	/* HAVE_STRING_H */
 
+#if HAVE_LIMITS_H
+#include <limits.h>
+#endif	/* HAVE_LIMITS_H */
+
+#if HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif	/* HAVE_SYS_TIME */
+
 #if HAVE_TIME_H
 #include <time.h>
 #endif	/* HAVE_TIME_H */
 
 #include <errno.h>
 #include "nilfs.h"
+#include "nilfs_gc.h"
+#include "cnoconv.h"
+#include "parser.h"
 
 #ifdef _GNU_SOURCE
 #include <getopt.h>
 const static struct option long_option[] = {
 	{"all",  no_argument, NULL, 'a'},
 	{"index", required_argument, NULL, 'i'},
+	{"latest-usage", no_argument, NULL, 'l' },
 	{"lines", required_argument, NULL, 'n'},
+	{"protection-period", required_argument, NULL, 'p'},
 	{"help", no_argument, NULL, 'h'},
 	{"version", no_argument, NULL, 'V'},
 	{NULL, 0, NULL, 0}
 };
 
-#define LSSU_USAGE	"Usage: %s [OPTION]... [DEVICE]\n"		\
-			"  -a, --all\t\tdo not hide clean segments\n"	\
-			"  -i, --index\t\tstart index\n"		\
-			"  -n, --lines\t\toutput lines\n"		\
-			"  -h, --help\t\tdisplay this help and exit\n"	\
-			"  -V, --version\t\tdisplay version and exit\n"
+#define LSSU_USAGE							\
+	"Usage: %s [OPTION]... [DEVICE]\n"				\
+	"  -a, --all\t\t\tdo not hide clean segments\n"			\
+	"  -h, --help\t\t\tdisplay this help and exit\n"		\
+	"  -i, --index\t\t\tskip index segments at start of inputs\n"	\
+	"  -l, --latest-usage\t\tprint usage status of the moment\n"	\
+	"  -n, --lines\t\t\tlist only lines input segments\n"		\
+	"  -p, --protection-period\tspecify protection period\n"	\
+	"  -V, --version\t\t\tdisplay version and exit\n"
 #else	/* !_GNU_SOURCE */
 #include <unistd.h>
-#define LSSU_USAGE	"Usage: %s [-ahV] [-i index] [-n lines] [device]\n"
+#define LSSU_USAGE \
+	"Usage: %s [-alhV] [-i index] [-n lines] [-p period] [device]\n"
 #endif	/* _GNU_SOURCE */
 
 #define LSSU_BUFSIZE	128
 #define LSSU_NSEGS	512
 
+enum lssu_mode {
+	LSSU_MODE_NORMAL,
+	LSSU_MODE_LATEST_USAGE,
+};
+
+struct lssu_format {
+	char *header;
+	char *body;
+};
+
+const static struct lssu_format lssu_format[] = {
+	{
+		"              SEGNUM        DATE     TIME STAT     NBLOCKS\n",
+		"%20llu  %s  %c%c%c  %10u\n"
+	},
+	{
+		"           SEGNUM        DATE     TIME STAT     NBLOCKS"
+		"       NLIVEBLOCKS\n",
+		"%17llu  %s  %c%c%c  %10u %10u (%3u%%)\n"
+	}
+};
+
+static char *progname;
+
+static int all;
+static int latest;
+static int disp_mode;		/* display mode */
+static nilfs_cno_t protcno;
 static __u64 param_index;
 static __u64 param_lines;
-static struct nilfs_suinfo suinfos[LSSU_NSEGS];
 
+static size_t blocks_per_segment;
+static struct nilfs_suinfo suinfos[LSSU_NSEGS];
 
 static void lssu_print_header(void)
 {
-	printf("              SEGNUM        DATE     TIME STAT     NBLOCKS\n");
+	printf(lssu_format[disp_mode].header);
+}
+
+static ssize_t lssu_get_latest_usage(struct nilfs *nilfs,
+				     __u64 segnum, __u64 protseq,
+				     nilfs_cno_t protcno)
+{
+	struct nilfs_reclaim_stat stat;
+	struct nilfs_reclaim_params params = {
+		.flags = NILFS_RECLAIM_PARAM_PROTSEQ,
+		.protseq = protseq
+	};
+	__u64 segnums[1];
+	int ret;
+
+	if (protcno == NILFS_CNO_MAX) {
+		params.flags |= NILFS_RECLAIM_PARAM_PROTCNO;
+		params.protcno = protcno;
+	}
+
+	memset(&stat, 0, sizeof(stat));
+	segnums[0] = segnum;
+
+	ret = nilfs_assess_segment(nilfs, segnums, 1, &params, &stat);
+	if (ret < 0)
+		return -1;
+
+	if (stat.protected_segs > 0)
+		return -2;
+
+	return stat.live_blks;
 }
 
-static ssize_t lssu_print_suinfo(__u64 segnum, ssize_t nsi, int all)
+static ssize_t lssu_print_suinfo(struct nilfs *nilfs, __u64 segnum,
+				 ssize_t nsi, __u64 protseq)
 {
 	struct tm tm;
 	time_t t;
 	char timebuf[LSSU_BUFSIZE];
-	ssize_t i, n = 0;
+	ssize_t i, n = 0, ret;
+	int ratio;
+	size_t nliveblks;
 
 	for (i = 0; i < nsi; i++, segnum++) {
-		if (all || !nilfs_suinfo_clean(&suinfos[i])) {
-			t = (time_t)suinfos[i].sui_lastmod;
-			if (t != 0) {
-				localtime_r(&t, &tm);
-				strftime(timebuf, LSSU_BUFSIZE, "%F %T", &tm);
-			} else
-				snprintf(timebuf, LSSU_BUFSIZE,
-					 "---------- --:--:--");
-
-			printf("%20llu  %s  %c%c%c  %10u\n",
+		if (!all && nilfs_suinfo_clean(&suinfos[i]))
+			continue;
+
+		t = (time_t)suinfos[i].sui_lastmod;
+		if (t != 0) {
+			localtime_r(&t, &tm);
+			strftime(timebuf, LSSU_BUFSIZE, "%F %T", &tm);
+		} else
+			snprintf(timebuf, LSSU_BUFSIZE,
+				 "---------- --:--:--");
+
+		switch (disp_mode) {
+		case LSSU_MODE_NORMAL:
+			printf(lssu_format[disp_mode].body,
 			       (unsigned long long)segnum,
 			       timebuf,
 			       nilfs_suinfo_active(&suinfos[i]) ? 'a' : '-',
 			       nilfs_suinfo_dirty(&suinfos[i]) ? 'd' : '-',
 			       nilfs_suinfo_error(&suinfos[i]) ? 'e' : '-',
 			       suinfos[i].sui_nblocks);
-			n++;
+			break;
+		case LSSU_MODE_LATEST_USAGE:
+			nliveblks = 0;
+			ratio = 0;
+
+			if (!nilfs_suinfo_dirty(&suinfos[i]) ||
+			    nilfs_suinfo_error(&suinfos[i]))
+				goto skip_scan;
+
+			ret = lssu_get_latest_usage(nilfs, segnum, protseq,
+						    protcno);
+			if (ret >= 0) {
+				nliveblks = ret;
+				ratio = (ret * 100 + 99) / blocks_per_segment;
+			} else if (ret == -2) {
+				nliveblks = suinfos[i].sui_nblocks;
+				ratio = 100;
+			} else {
+				fprintf(stderr,
+					"%s: failed to get usage: %s\n",
+					progname, strerror(errno));
+				exit(1);
+			}
+
+		skip_scan:
+			printf(lssu_format[disp_mode].body,
+			       (unsigned long long)segnum,
+			       timebuf,
+			       nilfs_suinfo_active(&suinfos[i]) ? 'a' : '-',
+			       nilfs_suinfo_dirty(&suinfos[i]) ? 'd' : '-',
+			       nilfs_suinfo_error(&suinfos[i]) ? 'e' : '-',
+			       suinfos[i].sui_nblocks, nliveblks, ratio);
+			break;
 		}
+		n++;
 	}
 	return n;
 }
 
-static int lssu_list_suinfo(struct nilfs *nilfs, int all)
+static int lssu_list_suinfo(struct nilfs *nilfs)
 {
 	struct nilfs_sustat sustat;
 	__u64 segnum, rest, count;
@@ -128,23 +244,66 @@ static int lssu_list_suinfo(struct nilfs *nilfs, int all)
 		if (nsi < 0)
 			return 1;
 
-		n = lssu_print_suinfo(segnum, nsi, all);
+		n = lssu_print_suinfo(nilfs, segnum, nsi, sustat.ss_prot_seq);
 		segnum += nsi;
 	}
 
 	return 0;
 }
 
+static int lssu_get_protcno(struct nilfs *nilfs,
+			    unsigned long protection_period,
+			    nilfs_cno_t *protcnop)
+{
+	struct nilfs_cnoconv *cnoconv;
+	struct timeval tv;
+	__u64 prottime;
+	int ret;
+
+	if (protection_period == ULONG_MAX) {
+		*protcnop = NILFS_CNO_MAX;
+		return 0;
+	}
+
+	ret = gettimeofday(&tv, NULL);
+	if (ret < 0) {
+		fprintf(stderr, "%s: cannot get current time: %m\n", progname);
+		return -1;
+	}
+	prottime = tv.tv_sec - protection_period;
+
+	cnoconv = nilfs_cnoconv_create(nilfs);
+	if (!cnoconv) {
+		fprintf(stderr,
+			"%s: cannot create checkpoint number converter: %m\n",
+			progname);
+		return -1;
+	}
+
+	ret = nilfs_cnoconv_time2cno(cnoconv, prottime, protcnop);
+	if (ret < 0) {
+		fprintf(stderr,
+			"%s: cannot convert protectoin time to checkpoint "
+			"number: %m\n",
+			progname);
+	}
+
+	nilfs_cnoconv_destroy(cnoconv);
+	return ret;
+}
+
 int main(int argc, char *argv[])
 {
 	struct nilfs *nilfs;
-	char *dev, *progname;
-	int c, all, status;
+	char *dev;
+	int c, status;
+	int open_flags;
+	unsigned long protection_period = ULONG_MAX;
+	int ret;
 #ifdef _GNU_SOURCE
 	int option_index;
 #endif	/* _GNU_SOURCE */
 
-	all = 0;
 	opterr = 0;
 	progname = strrchr(argv[0], '/');
 	if (progname == NULL)
@@ -153,10 +312,10 @@ int main(int argc, char *argv[])
 		progname++;
 
 #ifdef _GNU_SOURCE
-	while ((c = getopt_long(argc, argv, "ai:n:hV",
+	while ((c = getopt_long(argc, argv, "ai:ln:hp:V",
 				long_option, &option_index)) >= 0) {
 #else	/* !_GNU_SOURCE */
-	while ((c = getopt(argc, argv, "ai:n:hV")) >= 0) {
+	while ((c = getopt(argc, argv, "ai:ln:hp:V")) >= 0) {
 #endif	/* _GNU_SOURCE */
 
 		switch (c) {
@@ -166,12 +325,30 @@ int main(int argc, char *argv[])
 		case 'i':
 			param_index = (__u64)atoll(optarg);
 			break;
+		case 'l':
+			latest = 1;
+			break;
 		case 'n':
 			param_lines = (__u64)atoll(optarg);
 			break;
 		case 'h':
 			fprintf(stderr, LSSU_USAGE, progname);
 			exit(0);
+		case 'p':
+			ret = nilfs_parse_protection_period(
+				optarg, &protection_period);
+			if (!ret)
+				break;
+
+			if (errno == ERANGE) {
+				fprintf(stderr, "too large period: %s\n",
+					optarg);
+			} else {
+				fprintf(stderr,
+					"invalid protection period: %s\n",
+					optarg);
+			}
+			exit(1);
 		case 'V':
 			printf("%s (%s %s)\n", progname, PACKAGE,
 			       PACKAGE_VERSION);
@@ -192,14 +369,26 @@ int main(int argc, char *argv[])
 		exit(1);
 	}
 
-	nilfs = nilfs_open(dev, NULL, NILFS_OPEN_RDONLY);
+	open_flags = NILFS_OPEN_RDONLY;
+	if (latest)
+		open_flags |= NILFS_OPEN_RAW | NILFS_OPEN_GCLK;
+
+	nilfs = nilfs_open(dev, NULL, open_flags);
 	if (nilfs == NULL) {
 		fprintf(stderr, "%s: %s: cannot open NILFS\n",
 			progname, dev);
 		exit(1);
 	}
 
-	status = lssu_list_suinfo(nilfs, all);
+	if (latest) {
+		blocks_per_segment = nilfs_get_blocks_per_segment(nilfs);
+		disp_mode = LSSU_MODE_LATEST_USAGE;
+		ret = lssu_get_protcno(nilfs, protection_period, &protcno);
+		if (ret < 0)
+			exit(1);
+	}
+
+	status = lssu_list_suinfo(nilfs);
 
 	nilfs_close(nilfs);
 	exit(status);
diff --git a/man/lssu.1 b/man/lssu.1
index 00cfcfa..2b58f8f 100644
--- a/man/lssu.1
+++ b/man/lssu.1
@@ -1,7 +1,7 @@
 .\"  Copyright (C) 2007-2012 Nippon Telegraph and Telephone Corporation.
 .\"  Written by Ryusuke Konishi <konishi.ryusuke@xxxxxxxxxxxxx>
 .\"
-.TH LSSU 1 "May 2011" "nilfs-utils version 2.1"
+.TH LSSU 1 "Feb 2014" "nilfs-utils version 2.1"
 .SH NAME
 lssu \- list usage state of NILFS2 segments
 .SH SYNOPSIS
@@ -27,9 +27,17 @@ Display help message and exit.
 \fB\-i \fIindex\fR, \fB\-\-index\fR=\fIindex\fR
 Skip \fIindex\fP segments at start of input.
 .TP
+\fB\-l\fR, \fB\-\-latest-usage\fR
+Print usage status of the moment.
+.TP
 \fB\-n \fIlines\fR, \fB\-\-lines\fR=\fIlines\fR
 List only \fIlines\fP input segments.
 .TP
+\fB\-p \fIperiod\fR, \fB\-\-protection-period\fR=\fIperiod\fR
+Specify protection period.  This option is used when printing usage
+status of the moment (with \fB\-l\fR option) to test if each
+block in segments is protected and is not reclaimable.
+.TP
 \fB\-V\fR, \fB\-\-version\fR
 Display version and exit.
 .SH "FIELD DESCRIPTION"
@@ -63,6 +71,10 @@ error.  NILFS2 avoids allocating the segments with this flag.
 .TP
 .B NBLOCKS
 Number of in-use blocks of the segment.
+.TP
+.B NLIVEBLOCKS (optional)
+Number and ratio of in-use blocks of the moment.  This field is
+displayed when \fB\-l\fR option is specified.
 .SH AUTHOR
 Koji Sato
 .SH AVAILABILITY
-- 
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