Ryusuke Konishi
2014-02-09 18:48:34 UTC
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-***@public.gmane.org>
---
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, ¶ms, &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-***@public.gmane.org>
.\"
-.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
"-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-***@public.gmane.org>
---
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, ¶ms, &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-***@public.gmane.org>
.\"
-.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-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
1.7.9.3
--
To unsubscribe from this list: send the line "unsubscribe linux-nilfs" in
the body of a message to majordomo-***@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html