From 3a95c7f8306da18ea14148797d3d1b6864f7442e Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Thu, 11 Jul 2013 18:34:00 +0200 Subject: [PATCH 01/13] thin_metadata_size.c: new C implementation of metadata size calculation tool --- thin-provisioning/thin_metadata_size.c | 209 +++++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100755 thin-provisioning/thin_metadata_size.c diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c new file mode 100755 index 0000000..56c7ea2 --- /dev/null +++ b/thin-provisioning/thin_metadata_size.c @@ -0,0 +1,209 @@ +/* + * Copyright (C) 2013 Red Hat, GmbH + * + * This file is released under the GPL + * + * + * Calculates device-mapper thin privisioning + * metadata device size based on pool, block size and + * maximum expected thin provisioned devices and snapshots. + * + */ + +#include +#include +#include +#include +#include +#include + +/*----------------------------------------------------------------*/ + +static char *prg; + +enum numeric_options { blocksize, poolsize, maxthins, numeric, opt_end}; +struct global { + #define UNIT_ARRAY_SZ 18 + struct { + char *chars; + char *strings[UNIT_ARRAY_SZ]; + unsigned long long factors[UNIT_ARRAY_SZ]; + } unit; + + struct options { + unsigned long long n[opt_end]; + char unit; + } options; +}; +#define bytes_per_sector g->unit.factors[1] + +static struct global *init(void) +{ + unsigned u; + static struct global r; + static char *unit_strings[] = { "bytes", "sectors", + "kilobytes", "kibibytes", "megabytes", "mebibytes", + "gigabytes", "gibibytes", "terabytes", "tebibytes", + "petabytes", "pebibytes", "exabytes", "ebibytes", + "zetabytes", "zebibytes", "yottabytes", "yobibytes" }; + + memset(&r, 0, sizeof(r)); + r.unit.chars = "bskKmMgGtTpPeEzZyY"; + u = 0; + r.unit.factors[u++] = 1; + r.unit.factors[u++] = 512; + r.unit.factors[u++] = 1024; + r.unit.factors[u++] = 1000; + for ( ; u < UNIT_ARRAY_SZ; u += 2) { + r.unit.factors[u] = r.unit.factors[2] * r.unit.factors[u - 2]; + r.unit.factors[u+1] = r.unit.factors[3] * r.unit.factors[u - 1]; + } + + u = UNIT_ARRAY_SZ; + while (u--) + r.unit.strings[u] = unit_strings[u]; + + r.options.unit = 's'; + + return &r; +} + +static unsigned get_index(struct global *g, char unit_char) +{ + char *o = strchr(g->unit.chars, unit_char); + + return o ? o - g->unit.chars : 1; +} + +static void abort_prg(const char *msg) +{ + fprintf(stderr, "%s - %s\n", prg, msg); + exit(1); +} + +static void check_opts(struct options *options) +{ + if (!options->n[blocksize] || !options->n[poolsize] || !options->n[maxthins]) + abort_prg("3 arguments required!"); + else if (options->n[blocksize] & (options->n[blocksize] - 1)) + abort_prg("block size must be 2^^N"); + else if (options->n[poolsize] < options->n[blocksize]) + abort_prg("poolsize must be much larger than blocksize"); + else if (!options->n[maxthins]) + abort_prg("maximum number of thin provisioned devices must be > 0"); +} + +static unsigned long long to_bytes(struct global *g, char *sz, int div) +{ + unsigned len = strlen(sz); + char uc = 's', *us = strchr(g->unit.chars, sz[len-1]); + + if (us) + uc = sz[len-1], sz[len-1] = 0; + + return g->unit.factors[get_index(g, uc)] * atoll(sz) / (div ? bytes_per_sector : 1); +} + +static void printf_aligned(struct global *g, char *a, char *b, char *c, int units) +{ + char buf[80]; + + strcpy(buf, b); + if (units) + strcat(buf, "["), strcat(buf, g->unit.chars), strcat(buf, "]"); + + printf("\t%-4s%-45s%s\n", a, buf, c); +} + +static void help(struct global *g) +{ + printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [opts]\n", prg); + printf_aligned(g, "-b", "--block-size BLOCKSIZE", "Block size of thin provisioned devices.", 1); + printf_aligned(g, "-s", "--pool-size SIZE", "Size of pool device.", 1); + printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", 0); + printf_aligned(g, "-u", "--unit ", "Output unit specifier.", 1); + printf_aligned(g, "-n", "--numeric-only", "Output numeric value only.", 0); + printf_aligned(g, "-h", "--help", "This help.", 0); + exit(0); +} + +static struct global *parse_command_line(struct global *g, int argc, char **argv) +{ + int c; + static struct option long_options[] = { + {"block-size", required_argument, 0, 'b' }, + {"pool-size", required_argument, 0, 's' }, + {"max-thins", required_argument, 0, 'm' }, + {"unit", required_argument, 0, 'u' }, + {"numeric-only",required_argument, 0, 'n' }, + {"help", no_argument, 0, 'h' }, + {NULL, 0, 0, 0 } + }; + + while ((c = getopt_long(argc, argv, "b:s:m:u:nh", long_options, NULL)) != -1) { + if (c == 'b') + g->options.n[blocksize] = to_bytes(g, optarg, 1); + else if (c == 's') + g->options.n[poolsize] = to_bytes(g, optarg, 1); + else if (c == 'm') + g->options.n[maxthins] = to_bytes(g, optarg, 0); + else if (c == 'u') { + if (*(optarg + 1)) + abort_prg("only one unit specifier allowed!"); + else if (!strchr(g->unit.chars, *optarg)) + abort_prg("output unit specifier invalid!"); + + g->options.unit = *optarg; + } else if (c == 'n') + g->options.n[numeric] = 1; + else if (c == 'h') + help(g); + else + abort_prg("Invalid option!"); + } + + check_opts(&g->options); + + return g; +} + +static const unsigned mappings_per_block(void) +{ + const struct { + const unsigned node; + const unsigned node_header; + const unsigned entry; + } btree_size = { 4096, 64, 16 }; + + return (btree_size.node - btree_size.node_header) / btree_size.entry; +} + +static unsigned precision(double r) +{ + return r == truncl(r) ? 0 : 3; +} + +static void estimated_result(struct global *g) +{ + unsigned idx = get_index(g, g->options.unit); + double r; + + /* double-fold # of nodes, because they aren't fully populated in average */ + r = (1.0 + (2 * g->options.n[poolsize] / g->options.n[blocksize] / mappings_per_block() + g->options.n[maxthins])) * 8 * bytes_per_sector; /* in bytes! */ + r /= g->unit.factors[idx]; /* in requested unit */ + +// printf("%c idx=%u factor=%llu r=%f\n", g->options.unit, idx, g->unit.factors[idx], r); + + /* FIXME: correct output */ + if (g->options.n[numeric]) + printf("%.*f\n", precision(r), r); + else + printf("%s - estimated metadata area size is %.*f %s\n", prg, precision(r), r, g->unit.strings[idx]); +} + +int main(int argc, char **argv) +{ + prg = basename(*argv); + estimated_result(parse_command_line(init(), argc, argv)); + return 0; +} From 99a1b96b2f5495e7047813b8d349e5ea8ccd2629 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Fri, 12 Jul 2013 12:58:53 +0200 Subject: [PATCH 02/13] thin_metadata_size.c: format output enhancements --- thin-provisioning/thin_metadata_size.c | 31 +++++++++++++++----------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index 56c7ea2..7207ff9 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -50,10 +50,7 @@ static struct global *init(void) memset(&r, 0, sizeof(r)); r.unit.chars = "bskKmMgGtTpPeEzZyY"; u = 0; - r.unit.factors[u++] = 1; - r.unit.factors[u++] = 512; - r.unit.factors[u++] = 1024; - r.unit.factors[u++] = 1000; + r.unit.factors[u++] = 1, r.unit.factors[u++] = 512, r.unit.factors[u++] = 1024, r.unit.factors[u++] = 1000; for ( ; u < UNIT_ARRAY_SZ; u += 2) { r.unit.factors[u] = r.unit.factors[2] * r.unit.factors[u - 2]; r.unit.factors[u+1] = r.unit.factors[3] * r.unit.factors[u - 1]; @@ -178,9 +175,23 @@ static const unsigned mappings_per_block(void) return (btree_size.node - btree_size.node_header) / btree_size.entry; } -static unsigned precision(double r) +static void printf_precision(double r, int full, char *unit_str) { - return r == truncl(r) ? 0 : 3; + double rtrunc = truncl(r); + + /* FIXME: correct output */ + if (full) + printf("%s - estimated metadata area size is ", prg); + + if (r == rtrunc) + printf("%llu", (unsigned long long) r); + else + printf(r - truncl(r) < 1E-3 ? "%0.3e" : "%0.3f", r); + + if (full) + printf(" %s", unit_str); + + putchar('\n'); } static void estimated_result(struct global *g) @@ -192,13 +203,7 @@ static void estimated_result(struct global *g) r = (1.0 + (2 * g->options.n[poolsize] / g->options.n[blocksize] / mappings_per_block() + g->options.n[maxthins])) * 8 * bytes_per_sector; /* in bytes! */ r /= g->unit.factors[idx]; /* in requested unit */ -// printf("%c idx=%u factor=%llu r=%f\n", g->options.unit, idx, g->unit.factors[idx], r); - - /* FIXME: correct output */ - if (g->options.n[numeric]) - printf("%.*f\n", precision(r), r); - else - printf("%s - estimated metadata area size is %.*f %s\n", prg, precision(r), r, g->unit.strings[idx]); + printf_precision(r, !g->options.n[numeric], g->unit.strings[idx]); } int main(int argc, char **argv) From 931221647c863fb2db02e6054b6a09388767042e Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Fri, 12 Jul 2013 13:29:12 +0200 Subject: [PATCH 03/13] thin_metadata_size.c: fix --maxthins unit processing --- thin-provisioning/thin_metadata_size.c | 71 +++++++++++++++----------- 1 file changed, 41 insertions(+), 30 deletions(-) diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index 7207ff9..c99e534 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -19,9 +19,10 @@ /*----------------------------------------------------------------*/ -static char *prg; +static char *prg; /* program name */ -enum numeric_options { blocksize, poolsize, maxthins, numeric, opt_end}; +enum numeric_options { BLOCKSIZE, POOLSIZE, MAXTHINS, NUMERIC, OPT_END}; +enum return_units { RETURN_BYTES, RETURN_SECTORS }; struct global { #define UNIT_ARRAY_SZ 18 struct { @@ -31,7 +32,7 @@ struct global { } unit; struct options { - unsigned long long n[opt_end]; + unsigned long long n[OPT_END]; char unit; } options; }; @@ -48,16 +49,19 @@ static struct global *init(void) "zetabytes", "zebibytes", "yottabytes", "yobibytes" }; memset(&r, 0, sizeof(r)); + r.unit.chars = "bskKmMgGtTpPeEzZyY"; u = 0; - r.unit.factors[u++] = 1, r.unit.factors[u++] = 512, r.unit.factors[u++] = 1024, r.unit.factors[u++] = 1000; + r.unit.factors[u++] = 1; + r.unit.factors[u++] = 512; + r.unit.factors[u++] = 1024; + r.unit.factors[u++] = 1000; for ( ; u < UNIT_ARRAY_SZ; u += 2) { r.unit.factors[u] = r.unit.factors[2] * r.unit.factors[u - 2]; r.unit.factors[u+1] = r.unit.factors[3] * r.unit.factors[u - 1]; } - u = UNIT_ARRAY_SZ; - while (u--) + for (u = UNIT_ARRAY_SZ; u--; ) r.unit.strings[u] = unit_strings[u]; r.options.unit = 's'; @@ -80,25 +84,27 @@ static void abort_prg(const char *msg) static void check_opts(struct options *options) { - if (!options->n[blocksize] || !options->n[poolsize] || !options->n[maxthins]) + if (!options->n[BLOCKSIZE] || !options->n[POOLSIZE] || !options->n[MAXTHINS]) abort_prg("3 arguments required!"); - else if (options->n[blocksize] & (options->n[blocksize] - 1)) + else if (options->n[BLOCKSIZE] & (options->n[BLOCKSIZE] - 1)) abort_prg("block size must be 2^^N"); - else if (options->n[poolsize] < options->n[blocksize]) - abort_prg("poolsize must be much larger than blocksize"); - else if (!options->n[maxthins]) + else if (options->n[POOLSIZE] < options->n[BLOCKSIZE]) + abort_prg("POOLSIZE must be much larger than BLOCKSIZE"); + else if (!options->n[MAXTHINS]) abort_prg("maximum number of thin provisioned devices must be > 0"); } -static unsigned long long to_bytes(struct global *g, char *sz, int div) +static unsigned long long to_bytes(struct global *g, char *sz, enum return_units unit) { unsigned len = strlen(sz); + unsigned long long r; char uc = 's', *us = strchr(g->unit.chars, sz[len-1]); if (us) - uc = sz[len-1], sz[len-1] = 0; + uc = *us, sz[len-1] = 0; - return g->unit.factors[get_index(g, uc)] * atoll(sz) / (div ? bytes_per_sector : 1); + r = atoll(sz) * g->unit.factors[get_index(g, uc)]; + return (!us || unit == RETURN_SECTORS) ? r / bytes_per_sector : r; } static void printf_aligned(struct global *g, char *a, char *b, char *c, int units) @@ -117,13 +123,23 @@ static void help(struct global *g) printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [opts]\n", prg); printf_aligned(g, "-b", "--block-size BLOCKSIZE", "Block size of thin provisioned devices.", 1); printf_aligned(g, "-s", "--pool-size SIZE", "Size of pool device.", 1); - printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", 0); + printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", 1); printf_aligned(g, "-u", "--unit ", "Output unit specifier.", 1); printf_aligned(g, "-n", "--numeric-only", "Output numeric value only.", 0); printf_aligned(g, "-h", "--help", "This help.", 0); exit(0); } +static void check_unit(struct global *g, char *arg) +{ + if (*(arg + 1)) + abort_prg("only one unit specifier allowed!"); + else if (!strchr(g->unit.chars, *arg)) + abort_prg("output unit specifier invalid!"); + + g->options.unit = *arg; +} + static struct global *parse_command_line(struct global *g, int argc, char **argv) { int c; @@ -139,20 +155,15 @@ static struct global *parse_command_line(struct global *g, int argc, char **argv while ((c = getopt_long(argc, argv, "b:s:m:u:nh", long_options, NULL)) != -1) { if (c == 'b') - g->options.n[blocksize] = to_bytes(g, optarg, 1); + g->options.n[BLOCKSIZE] = to_bytes(g, optarg, RETURN_SECTORS); else if (c == 's') - g->options.n[poolsize] = to_bytes(g, optarg, 1); + g->options.n[POOLSIZE] = to_bytes(g, optarg, RETURN_SECTORS); else if (c == 'm') - g->options.n[maxthins] = to_bytes(g, optarg, 0); - else if (c == 'u') { - if (*(optarg + 1)) - abort_prg("only one unit specifier allowed!"); - else if (!strchr(g->unit.chars, *optarg)) - abort_prg("output unit specifier invalid!"); - - g->options.unit = *optarg; - } else if (c == 'n') - g->options.n[numeric] = 1; + g->options.n[MAXTHINS] = to_bytes(g, optarg, RETURN_BYTES); + else if (c == 'u') + check_unit(g, optarg); + else if (c == 'n') + g->options.n[NUMERIC] = 1; else if (c == 'h') help(g); else @@ -186,7 +197,7 @@ static void printf_precision(double r, int full, char *unit_str) if (r == rtrunc) printf("%llu", (unsigned long long) r); else - printf(r - truncl(r) < 1E-3 ? "%0.3e" : "%0.3f", r); + printf(r - truncl(r) < 1E-2 ? "%0.2e" : "%0.2f", r); if (full) printf(" %s", unit_str); @@ -200,10 +211,10 @@ static void estimated_result(struct global *g) double r; /* double-fold # of nodes, because they aren't fully populated in average */ - r = (1.0 + (2 * g->options.n[poolsize] / g->options.n[blocksize] / mappings_per_block() + g->options.n[maxthins])) * 8 * bytes_per_sector; /* in bytes! */ + r = (1.0 + (2 * g->options.n[POOLSIZE] / g->options.n[BLOCKSIZE] / mappings_per_block() + g->options.n[MAXTHINS])) * 8 * bytes_per_sector; /* in bytes! */ r /= g->unit.factors[idx]; /* in requested unit */ - printf_precision(r, !g->options.n[numeric], g->unit.strings[idx]); + printf_precision(r, !g->options.n[NUMERIC], g->unit.strings[idx]); } int main(int argc, char **argv) From a7e196cc3aeaf741ce62aac93f1eb46330c901ea Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Fri, 12 Jul 2013 17:09:14 +0200 Subject: [PATCH 04/13] thin_metadata_size.c: indenting --- thin-provisioning/thin_metadata_size.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index c99e534..e798b0c 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -157,9 +157,9 @@ static struct global *parse_command_line(struct global *g, int argc, char **argv if (c == 'b') g->options.n[BLOCKSIZE] = to_bytes(g, optarg, RETURN_SECTORS); else if (c == 's') - g->options.n[POOLSIZE] = to_bytes(g, optarg, RETURN_SECTORS); + g->options.n[POOLSIZE] = to_bytes(g, optarg, RETURN_SECTORS); else if (c == 'm') - g->options.n[MAXTHINS] = to_bytes(g, optarg, RETURN_BYTES); + g->options.n[MAXTHINS] = to_bytes(g, optarg, RETURN_BYTES); else if (c == 'u') check_unit(g, optarg); else if (c == 'n') From 69ff5d5513fc8b07c3e85b8f8cb15e03e667bb8a Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Mon, 15 Jul 2013 16:48:36 +0200 Subject: [PATCH 05/13] autconf: support build of thin_metadata_size.c --- Makefile.in | 28 ++++++++++++++++--- configure.in | 1 + thin-provisioning/thin_metadata_size.c | 1 - ...in_metadata_size => thin_metadata_size.rb} | 0 4 files changed, 25 insertions(+), 5 deletions(-) rename thin-provisioning/{thin_metadata_size => thin_metadata_size.rb} (100%) diff --git a/Makefile.in b/Makefile.in index 8cda0c3..f5e2d1d 100644 --- a/Makefile.in +++ b/Makefile.in @@ -24,7 +24,8 @@ PROGRAMS=\ thin_dump \ thin_restore \ thin_repair \ - thin_rmap + thin_rmap \ + thin_metadata_size all: $(PROGRAMS) @@ -73,10 +74,15 @@ PROGRAM_SOURCE=\ thin-provisioning/thin_repair.cc \ thin-provisioning/thin_rmap.cc +C_PROGRAM_SOURCE=\ + thin-provisioning/thin_metadata_size.c + +CC:=@CC@ CXX:=@CXX@ OBJECTS:=$(subst .cc,.o,$(SOURCE)) TOP_DIR:=@top_srcdir@ TOP_BUILDDIR:=@top_builddir@ +CFLAGS+=-g -Wall -O3 CXXFLAGS+=-std=c++11 -g -Wall -fno-strict-aliasing CXXFLAGS+=@CXXOPTIMISE_FLAG@ CXXFLAGS+=@CXXDEBUG_FLAG@ @@ -104,6 +110,14 @@ endif .SUFFIXES: .d +%.o: %.c + @echo " [CC] $<" + $(V) $(CC) -c $(INCLUDES) $(CFLAGS) -o $@ $< + @echo " [DEP] $<" + $(V) $(CC) -MM -MT $(subst .c,.o,$<) $(INCLUDES) $(CFLAGS) $< > $*.$$$$; \ + sed 's,\([^ :]*\)\.o[ :]*,\1.o \1.gmo $* : Makefile ,g' < $*.$$$$ > $*.d; \ + $(RM) $*.$$$$ + %.o: %.cc @echo " [CXX] $<" $(V) $(CXX) -c $(INCLUDES) $(CXXFLAGS) -o $@ $< @@ -195,6 +209,10 @@ thin_rmap: $(THIN_RMAP_OBJECTS) thin-provisioning/thin_rmap.o @echo " [LD] $@" $(V) $(CXX) $(CXXFLAGS) -o $@ $+ $(LIBS) +thin_metadata_size: thin-provisioning/thin_metadata_size.o + @echo " [LD] $@" + $(V) $(CC) $(CFLAGS) -o $@ $+ -lm + #---------------------------------------------------------------- # Cache tools @@ -221,14 +239,16 @@ cache_check: $(CACHE_CHECK_OBJECTS) cache/check.o DEPEND_FILES=\ $(subst .cc,.d,$(SOURCE)) \ $(subst .cc,.d,$(TEST_SOURCE)) \ - $(subst .cc,.d,$(PROGRAM_SOURCE)) + $(subst .cc,.d,$(PROGRAM_SOURCE)) \ + $(subst .c,.d,$(C_PROGRAM_SOURCE)) .PHONY: clean distclean clean: find . -name \*.o -delete find . -name \*.gmo -delete - $(RM) $(DEPEND_FILES) $(TEST_PROGRAMS) $(PROGRAMS) $(GMOCK_OBJECTS) lib/*.a + find . -name \*.d -delete + $(RM) $(TEST_PROGRAMS) $(PROGRAMS) $(GMOCK_OBJECTS) lib/*.a distclean: clean $(RM) config.cache config.log config.status configure.h version.h Makefile unit-tests/Makefile @@ -240,7 +260,7 @@ install: $(PROGRAMS) $(INSTALL_PROGRAM) -s thin_repair $(BINDIR) $(INSTALL_PROGRAM) -s thin_restore $(BINDIR) $(INSTALL_PROGRAM) -s thin_rmap $(BINDIR) - $(INSTALL_PROGRAM) thin-provisioning/thin_metadata_size $(BINDIR) + $(INSTALL_PROGRAM) -s thin_metadata_size $(BINDIR) $(INSTALL_DIR) $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_check.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_dump.8 $(MANPATH)/man8 diff --git a/configure.in b/configure.in index 78d88c1..8f25002 100644 --- a/configure.in +++ b/configure.in @@ -30,6 +30,7 @@ dnl -- Setup the directory where autoconf has auxilary files AC_CONFIG_AUX_DIR(autoconf) AC_CANONICAL_TARGET([]) AC_PROG_CXX([g++]) +AC_PROG_CC([gcc]) AC_LANG(C++) ################################################################ diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index e798b0c..e5952fe 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -190,7 +190,6 @@ static void printf_precision(double r, int full, char *unit_str) { double rtrunc = truncl(r); - /* FIXME: correct output */ if (full) printf("%s - estimated metadata area size is ", prg); diff --git a/thin-provisioning/thin_metadata_size b/thin-provisioning/thin_metadata_size.rb similarity index 100% rename from thin-provisioning/thin_metadata_size rename to thin-provisioning/thin_metadata_size.rb From d4e9875758c1f6f68581558e1a03e337d3d9a917 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Tue, 16 Jul 2013 15:33:38 +0200 Subject: [PATCH 06/13] Makefile.in: fluff --- Makefile.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile.in b/Makefile.in index f5e2d1d..2368f9b 100644 --- a/Makefile.in +++ b/Makefile.in @@ -65,7 +65,7 @@ SOURCE=\ PDATA_OBJECTS=$(subst .cc,.o,$(SOURCE)) -PROGRAM_SOURCE=\ +CXX_PROGRAM_SOURCE=\ cache/check.cc \ \ thin-provisioning/thin_check.cc \ @@ -239,7 +239,7 @@ cache_check: $(CACHE_CHECK_OBJECTS) cache/check.o DEPEND_FILES=\ $(subst .cc,.d,$(SOURCE)) \ $(subst .cc,.d,$(TEST_SOURCE)) \ - $(subst .cc,.d,$(PROGRAM_SOURCE)) \ + $(subst .cc,.d,$(CXX_PROGRAM_SOURCE)) \ $(subst .c,.d,$(C_PROGRAM_SOURCE)) .PHONY: clean distclean From 1b6f9255a18aa14073322805fb3bda1cfb1bdbe2 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Tue, 16 Jul 2013 17:39:40 +0200 Subject: [PATCH 07/13] thin_dump: support --metadata-snap block# --- man8/thin_dump.8 | 3 +++ thin-provisioning/metadata.cc | 13 ++----------- thin-provisioning/metadata.h | 5 +++-- thin-provisioning/superblock.cc | 9 +++++++-- thin-provisioning/superblock.h | 1 + thin-provisioning/thin_dump.cc | 4 ++-- thin-provisioning/thin_metadata_size.c | 1 - 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/man8/thin_dump.8 b/man8/thin_dump.8 index 697df83..07da225 100644 --- a/man8/thin_dump.8 +++ b/man8/thin_dump.8 @@ -22,6 +22,9 @@ Print output in XML or human readable format. .IP "\fB\-r, \-\-repair\fP". +.IP "\fB\-m, \-\-metadata_snap\fP block#". +Dump metadata snapshot at block# + .IP "\fB\-h, \-\-help\fP". Print help and exit. diff --git a/thin-provisioning/metadata.cc b/thin-provisioning/metadata.cc index c841614..771325a 100644 --- a/thin-provisioning/metadata.cc +++ b/thin-provisioning/metadata.cc @@ -57,15 +57,6 @@ namespace { return tm; } - superblock - read_superblock(block_manager<>::ptr bm, block_address location = SUPERBLOCK_LOCATION) { - superblock sb; - block_manager<>::read_ref r = bm->read_lock(location, superblock_validator()); - superblock_disk const *sbd = reinterpret_cast(&r.data()); - superblock_traits::unpack(*sbd, sb); - return sb; - } - void copy_space_maps(space_map::ptr lhs, space_map::ptr rhs) { for (block_address b = 0; b < rhs->get_nr_blocks(); b++) { @@ -149,10 +140,10 @@ metadata::metadata(std::string const &dev_path, open_type ot, } } -metadata::metadata(std::string const &dev_path) +metadata::metadata(std::string const &dev_path, block_address metadata_snap) { tm_ = open_tm(open_bm(dev_path, false)); - sb_ = read_superblock(tm_->get_bm()); + sb_ = read_superblock(tm_->get_bm(), metadata_snap); // We don't open the metadata sm for a held root //metadata_sm_ = open_metadata_sm(tm_, &sb_.metadata_space_map_root_); diff --git a/thin-provisioning/metadata.h b/thin-provisioning/metadata.h index 250c216..9749acb 100644 --- a/thin-provisioning/metadata.h +++ b/thin-provisioning/metadata.h @@ -62,10 +62,11 @@ namespace thin_provisioning { // Deprecated: it would be better if we passed in an already // constructed block_manager. metadata(std::string const &dev_path, open_type ot, - sector_t data_block_size = 128, + sector_t data_block_size = 128, // Only used if CREATE block_address nr_data_blocks = 0); // Only used if CREATE - metadata(std::string const &dev_path); + metadata(std::string const &dev_path, + block_address metadata_snap = 0); // ... use these instead ... metadata(block_manager<>::ptr bm, open_type ot, diff --git a/thin-provisioning/superblock.cc b/thin-provisioning/superblock.cc index c23fbc1..bf9544b 100644 --- a/thin-provisioning/superblock.cc +++ b/thin-provisioning/superblock.cc @@ -126,17 +126,22 @@ namespace thin_provisioning { } } - superblock_detail::superblock read_superblock(block_manager<>::ptr bm) + superblock_detail::superblock read_superblock(block_manager<>::ptr bm, block_address location) { using namespace superblock_detail; superblock sb; - auto r = bm->read_lock(SUPERBLOCK_LOCATION, superblock_validator()); + auto r = bm->read_lock(location, superblock_validator()); superblock_disk const *sbd = reinterpret_cast(&r.data()); superblock_traits::unpack(*sbd, sb); return sb; } + superblock_detail::superblock read_superblock(block_manager<>::ptr bm) + { + return read_superblock(bm, SUPERBLOCK_LOCATION); + } + void check_superblock(block_manager<>::ptr bm, superblock_detail::damage_visitor &visitor) { diff --git a/thin-provisioning/superblock.h b/thin-provisioning/superblock.h index e993497..a9377b0 100644 --- a/thin-provisioning/superblock.h +++ b/thin-provisioning/superblock.h @@ -123,6 +123,7 @@ namespace thin_provisioning { persistent_data::block_manager<>::validator::ptr superblock_validator(); superblock_detail::superblock read_superblock(persistent_data::block_manager<>::ptr bm); + superblock_detail::superblock read_superblock(persistent_data::block_manager<>::ptr bm, persistent_data::block_address location); void check_superblock(persistent_data::block_manager<>::ptr bm, superblock_detail::damage_visitor &visitor); } diff --git a/thin-provisioning/thin_dump.cc b/thin-provisioning/thin_dump.cc index a4bcf66..029a635 100644 --- a/thin-provisioning/thin_dump.cc +++ b/thin-provisioning/thin_dump.cc @@ -35,7 +35,7 @@ namespace { int dump(string const &path, ostream &out, string const &format, bool repair, block_address metadata_snap = 0) { try { - metadata::ptr md(new metadata(path, metadata::OPEN)); + metadata::ptr md(metadata_snap ? new metadata(path, metadata_snap) : new metadata(path, metadata::OPEN, 0, 0)); emitter::ptr e; if (format == "xml") @@ -63,7 +63,7 @@ namespace { << " {-h|--help}" << endl << " {-f|--format} {xml|human_readable}" << endl << " {-r|--repair}" << endl - << " {-m|--metadata-snap}" << endl + << " {-m|--metadata-snap} block#" << endl << " {-o }" << endl << " {-V|--version}" << endl; } diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index e5952fe..51e9454 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -3,7 +3,6 @@ * * This file is released under the GPL * - * * Calculates device-mapper thin privisioning * metadata device size based on pool, block size and * maximum expected thin provisioned devices and snapshots. From 5a7188bbd2f6652db1b7ba5014ab5083a5a52641 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Wed, 17 Jul 2013 13:21:11 +0200 Subject: [PATCH 08/13] New manual pages and fixes --- man8/thin_check.8 | 3 ++ man8/thin_dump.8 | 6 ++-- man8/thin_metadata_size.8 | 71 +++++++++++++++++++++++++++++++++++++++ man8/thin_repair.8 | 54 +++++++++++++++++++++++++++++ man8/thin_restore.8 | 5 ++- man8/thin_rmap.8 | 44 ++++++++++++++++++++++++ 6 files changed, 180 insertions(+), 3 deletions(-) create mode 100644 man8/thin_metadata_size.8 create mode 100644 man8/thin_repair.8 create mode 100644 man8/thin_rmap.8 diff --git a/man8/thin_check.8 b/man8/thin_check.8 index f9606e0..1489078 100644 --- a/man8/thin_check.8 +++ b/man8/thin_check.8 @@ -55,7 +55,10 @@ returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_dump(8) +.B thin_repair(8) .B thin_restore(8) +.B thin_rmap(8) +.B thin_metadata_size(8) .SH AUTHOR Joe Thornber diff --git a/man8/thin_dump.8 b/man8/thin_dump.8 index 07da225..5d2f6ba 100644 --- a/man8/thin_dump.8 +++ b/man8/thin_dump.8 @@ -9,7 +9,7 @@ thin_dump \- dump thin provisioning metadata from device or file to standard out .SH DESCRIPTION .B thin_dump -dumps thin provisioning metadata created by the device-mapper +dumps binary thin provisioning metadata created by the device-mapper thin provisioning target on a device or file to standard output for analysis or postprocessing in either XML or human readable format. XML formated metadata can be fed into thin_restore (see @@ -48,8 +48,10 @@ returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_check(8) +.B thin_repair(8) .B thin_restore(8) - +.B thin_rmap(8) +.B thin_metadata_size(8) .SH AUTHOR Joe Thornber .br diff --git a/man8/thin_metadata_size.8 b/man8/thin_metadata_size.8 new file mode 100644 index 0000000..bfe7787 --- /dev/null +++ b/man8/thin_metadata_size.8 @@ -0,0 +1,71 @@ +.TH THIN_METADATA_SIZE 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- +.SH NAME +thin_metadata_size \- thin provisioning metadata file/device size calculator. + +.SH SYNOPSIS +.B thin_metadata_size +.RB [ options ] + +.SH DESCRIPTION +.B thin_metadata_size +calculates the size of the thin provisioning metadata based on the block size +of the thin provisioned devices, the size of the thin provisioning pool and +the maximum number of all thin prisioned devices and snapshots. + +.IP "\fB\-b, \-\-block-size\fP \fIBLOCKSIZE[bskKmMgGtTpPeEzZyY]\fP" +Block size of thin provisioned devices in units of bytes,sectors,kilobytes,kibibytes,... respectively. +Default is in sectors without a block size unit specifier. + +.IP "\fB\-s, \-\-pool-size\fP \fIPOOLSIZE[bskKmMgGtTpPeEzZyY]\fP" +Thin provisioning pool size in units of bytes,sectors,kilobytes,kibibytes,... respectively. +Default is in sectors without a pool size unit specifier. + +.IP "\fB\-m, \-\-max-thins\fP \fI#[bskKmMgGtTpPeEzZyY]\fP" +Maximum sum of all thin provisioned devices and snapshots. +Unit identifier supported to allow for convenient entry of large quantities, eg. 1000000 = 1M. +Default is absolut quantity without a number unit specifier. + +.IP "\fB\-u, \-\-unit\fP \fI[bskKmMgGtTpPeEzZyY]\fP" +Output unit specifier in units of bytes,sectors,kilobytes,kibibytes,... respectively. +Default is in sectors without an output unit specifier. + +.IP "\fB\-n[u], \-\-numeric-only[=unit]\fP" +Limit output to just the size number with the optional unit specifier character. + +.IP "\fB\-h, \-\-help\fP" +Print help and exit. + +.IP "\fB\-V, \-\-version\fP" +Output version information and exit. + +.SH EXAMPLES +Calculates the thin privisioning metadata device size for block size 64 kilobytes, +pool size 1 terabytes and maximum number of thin provisioned devices and snapshots of 1000 +in units of sectors with long output. +.sp +.B thin_metadata_size -b64k -s1t -m1000 + +Or (using the long options inmstead) for block size 1 gigabyte, pool size 1 petabytes and maximum number of thin provisioned devices +and snapshots of 1 million in units of gigabytes with numeric only output. +.sp +.B thin_metadata_size --block-size=1g --pool-size=1p --max-thins=1M --unit=g --numeric-only + +Same as before (1g,1p,1M,numeric-only) but with unit specifier character appended. +.sp +.B thin_metadata_size --block-size=1g --pool-size=1p --max-thins=1M --unit=g --numeric-only=unit + +.SH DIAGNOSTICS +.B thin_metadata_size +returns an exit code of 0 for success or 1 for error. + +.SH SEE ALSO +.B thin_dump(8) +.B thin_check(8) +.B thin_repair(8) +.B thin_restore(8) +.B thin_rmap(8) + +.SH AUTHOR +Joe Thornber +.br +Heinz Mauelshagen diff --git a/man8/thin_repair.8 b/man8/thin_repair.8 new file mode 100644 index 0000000..69cddea --- /dev/null +++ b/man8/thin_repair.8 @@ -0,0 +1,54 @@ +.TH THIN_REPAIR 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- +.SH NAME +thin_repair \- repair thin provisioning binary metadata from device/file to device/file + +.SH SYNOPSIS +.B thin_repair +.RB [ options ] +.RB -i +.I {device|file} +.RB -o +.I {device|file} + +.SH DESCRIPTION +.B thin_repair +repairs binary thin provisioning metadata created by the +respective device-mapper target processing to another device or file. +If repaired to a metadata device, the metadata can be processed +by the device-mapper target. + +.IP "\fB\-i, \-\-input\fP \fI{device|file}\fP" +Input file or device with binary metadata. + +.IP "\fB\-o, \-\-output\fP \fI{device|file}\fP" +Output file or device for repaired binary metadata. + +.IP "\fB\-h, \-\-help\fP" +Print help and exit. + +.IP "\fB\-V, \-\-version\fP" +Output version information and exit. + +.SH EXAMPLE +Repairs the binary thin provisioning metadata on file +.B metadata +to logical volume /dev/vg/metadata for further processing by the +respective device-mapper target: +.sp +.B thin_repair -i metadata -o /dev/vg/metadata + +.SH DIAGNOSTICS +.B thin_repair +returns an exit code of 0 for success or 1 for error. + +.SH SEE ALSO +.B thin_dump(8) +.B thin_check(8) +.B thin_restore(8) +.B thin_rmap(8) +.B thin_metadata_size(8) + +.SH AUTHOR +Joe Thornber +.br +Heinz Mauelshagen diff --git a/man8/thin_restore.8 b/man8/thin_restore.8 index b4a07aa..8ab2976 100644 --- a/man8/thin_restore.8 +++ b/man8/thin_restore.8 @@ -40,12 +40,15 @@ respective device-mapper target: .B thin_restore -i metadata -o /dev/vg/metadata .SH DIAGNOSTICS -.B thin_dump +.B thin_restore returns an exit code of 0 for success or 1 for error. .SH SEE ALSO .B thin_dump(8) .B thin_check(8) +.B thin_repair(8) +.B thin_rmap(8) +.B thin_metadata_size(8) .SH AUTHOR Joe Thornber diff --git a/man8/thin_rmap.8 b/man8/thin_rmap.8 new file mode 100644 index 0000000..d68defb --- /dev/null +++ b/man8/thin_rmap.8 @@ -0,0 +1,44 @@ +.TH THIN_DUMP 8 "Thin Provisioning Tools" "Red Hat, Inc." \" -*- nroff -*- +.SH NAME +thin_rmap \- output reverse map of a thin provisioned region of blocks + +.SH SYNOPSIS +.B thin_rmap +.RB [options] +.I {metadata device|file} + +.SH DESCRIPTION +.B thin_rmap +outputs the reverse mapping for a region of thin provisioned pool blocks +to the respective thin provisioned devices. + +.IP "\fB\\-\-region\fP \fI\fP". +output reverse map + +.IP "\fB\-h, \-\-help\fP". +Print help and exit. + +.IP "\fB\-V, \-\-version\fP". +Output version information and exit. + +.SH EXAMPLES +output reverse map for pool blocks 5..45 (denotes blocks 5 to 44 inclusive, but not block 45) + +.sp +.B thin_rmap -r 5..45 /dev/vg/pool + +.SH DIAGNOSTICS +.B thin_rmap +returns an exit code of 0 for success or 1 for error. + +.SH SEE ALSO +.B thin_check(8) +.B thin_dump(8) +.B thin_repair(8) +.B thin_restore(8) +.B thin_metadata_size(8) + +.SH AUTHOR +Joe Thornber +.br +Heinz Mauelshagen From 4ba612f5064843db7bbcf8713ea5a592fb6ec933 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Wed, 17 Jul 2013 13:25:03 +0200 Subject: [PATCH 09/13] thin_metadata_size.c: support -V option; support -n option argument for unit specifier; add input parameter set to long output --- thin-provisioning/thin_metadata_size.c | 130 ++++++++++++++++++------- 1 file changed, 96 insertions(+), 34 deletions(-) diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index 51e9454..68eb3e3 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -1,12 +1,26 @@ /* * Copyright (C) 2013 Red Hat, GmbH * - * This file is released under the GPL - * * Calculates device-mapper thin privisioning * metadata device size based on pool, block size and * maximum expected thin provisioned devices and snapshots. * + * This file is part of the thin-provisioning-tools source. + * + * thin-provisioning-tools is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * thin-provisioning-tools is distributed in the hope that it will be + * useful, but WITHOUT ANY WARRANTY; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with thin-provisioning-tools. If not, see + * . + * */ #include @@ -15,6 +29,7 @@ #include #include #include +#include "version.h" /*----------------------------------------------------------------*/ @@ -32,14 +47,15 @@ struct global { struct options { unsigned long long n[OPT_END]; + char *s[OPT_END]; char unit; } options; }; #define bytes_per_sector g->unit.factors[1] -static struct global *init(void) +static struct global *init_prg(void) { - unsigned u; + unsigned u = 0; static struct global r; static char *unit_strings[] = { "bytes", "sectors", "kilobytes", "kibibytes", "megabytes", "mebibytes", @@ -48,9 +64,7 @@ static struct global *init(void) "zetabytes", "zebibytes", "yottabytes", "yobibytes" }; memset(&r, 0, sizeof(r)); - r.unit.chars = "bskKmMgGtTpPeEzZyY"; - u = 0; r.unit.factors[u++] = 1; r.unit.factors[u++] = 512; r.unit.factors[u++] = 1024; @@ -68,6 +82,16 @@ static struct global *init(void) return &r; } +static void exit_prg(struct global *g) +{ + unsigned u; + + for (u = OPT_END; u--; ) { + if (g->options.s[u]) + free(g->options.s[u]); + } +} + static unsigned get_index(struct global *g, char unit_char) { char *o = strchr(g->unit.chars, unit_char); @@ -114,64 +138,94 @@ static void printf_aligned(struct global *g, char *a, char *b, char *c, int unit if (units) strcat(buf, "["), strcat(buf, g->unit.chars), strcat(buf, "]"); - printf("\t%-4s%-45s%s\n", a, buf, c); + printf("\t%-4s%-44s%s\n", a, buf, c); } static void help(struct global *g) { - printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [opts]\n", prg); + printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [options]\n", prg); printf_aligned(g, "-b", "--block-size BLOCKSIZE", "Block size of thin provisioned devices.", 1); printf_aligned(g, "-s", "--pool-size SIZE", "Size of pool device.", 1); printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", 1); printf_aligned(g, "-u", "--unit ", "Output unit specifier.", 1); - printf_aligned(g, "-n", "--numeric-only", "Output numeric value only.", 0); + printf_aligned(g, "-n", "--numeric-only[=unit]", "Output numeric value only (optionally with unit identifier).", 0); printf_aligned(g, "-h", "--help", "This help.", 0); + printf_aligned(g, "-V", "--version", "Print thin provisioning tools version.", 0); exit(0); } static void check_unit(struct global *g, char *arg) { if (*(arg + 1)) - abort_prg("only one unit specifier allowed!"); + abort_prg("only one unit specifier character allowed!"); else if (!strchr(g->unit.chars, *arg)) - abort_prg("output unit specifier invalid!"); + abort_prg("output unit specifier character invalid!"); g->options.unit = *arg; } -static struct global *parse_command_line(struct global *g, int argc, char **argv) +static void check_numeric_option(struct global *g, char *arg) +{ + if (g->options.n[NUMERIC]) + abort_prg("-n already given!"); + + g->options.n[NUMERIC] = 1; + + if (arg) { + if (!*arg || strncmp("unit", arg, strlen(arg))) + abort_prg("-n invalid option argument"); + + g->options.n[NUMERIC]++; + } +} + +static void check_size(struct global *g, enum numeric_options o, enum return_units unit, char *arg) +{ + if (g->options.n[o]) + abort_prg("option already given!"); + + g->options.s[o] = strdup(arg); + if (!g->options.s[o]) + abort_prg("failed to allocate string!"); + + g->options.n[o] = to_bytes(g, arg, unit); +} + +static void parse_command_line(struct global *g, int argc, char **argv) { int c; static struct option long_options[] = { - {"block-size", required_argument, 0, 'b' }, - {"pool-size", required_argument, 0, 's' }, - {"max-thins", required_argument, 0, 'm' }, - {"unit", required_argument, 0, 'u' }, - {"numeric-only",required_argument, 0, 'n' }, - {"help", no_argument, 0, 'h' }, - {NULL, 0, 0, 0 } + {"block-size", required_argument, NULL, 'b' }, + {"pool-size", required_argument, NULL, 's' }, + {"max-thins", required_argument, NULL, 'm' }, + {"unit", required_argument, NULL, 'u' }, + {"numeric-only",optional_argument, NULL, 'n' }, + {"help", no_argument, NULL, 'h' }, + {"version", no_argument, NULL, 'V' }, + {NULL, 0, NULL, 0 } }; - while ((c = getopt_long(argc, argv, "b:s:m:u:nh", long_options, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "b:s:m:u:n::hV", long_options, NULL)) != -1) { if (c == 'b') - g->options.n[BLOCKSIZE] = to_bytes(g, optarg, RETURN_SECTORS); + check_size(g, BLOCKSIZE, RETURN_SECTORS, optarg); else if (c == 's') - g->options.n[POOLSIZE] = to_bytes(g, optarg, RETURN_SECTORS); + check_size(g, POOLSIZE, RETURN_SECTORS, optarg); else if (c == 'm') - g->options.n[MAXTHINS] = to_bytes(g, optarg, RETURN_BYTES); + check_size(g, MAXTHINS, RETURN_BYTES, optarg); else if (c == 'u') check_unit(g, optarg); else if (c == 'n') - g->options.n[NUMERIC] = 1; + check_numeric_option(g, optarg); else if (c == 'h') help(g); - else + else if (c == 'V') { + printf("%s\n", THIN_PROVISIONING_TOOLS_VERSION); + exit(0); + } else abort_prg("Invalid option!"); } check_opts(&g->options); - - return g; } static const unsigned mappings_per_block(void) @@ -185,12 +239,14 @@ static const unsigned mappings_per_block(void) return (btree_size.node - btree_size.node_header) / btree_size.entry; } -static void printf_precision(double r, int full, char *unit_str) +static void printf_precision(struct global *g, double r, unsigned idx) { + int full = !g->options.n[NUMERIC]; double rtrunc = truncl(r); if (full) - printf("%s - estimated metadata area size is ", prg); + printf("%s - estimated metadata area size [blocksize=%s,poolsize=%s,maxthins=%s] is ", + prg, g->options.s[BLOCKSIZE], g->options.s[POOLSIZE], g->options.s[MAXTHINS]); if (r == rtrunc) printf("%llu", (unsigned long long) r); @@ -198,12 +254,14 @@ static void printf_precision(double r, int full, char *unit_str) printf(r - truncl(r) < 1E-2 ? "%0.2e" : "%0.2f", r); if (full) - printf(" %s", unit_str); + printf(" %s", g->unit.strings[idx]); + else if (g->options.n[NUMERIC] > 1) + printf("%c", g->unit.chars[idx]); putchar('\n'); } -static void estimated_result(struct global *g) +static void print_estimated_result(struct global *g) { unsigned idx = get_index(g, g->options.unit); double r; @@ -212,12 +270,16 @@ static void estimated_result(struct global *g) r = (1.0 + (2 * g->options.n[POOLSIZE] / g->options.n[BLOCKSIZE] / mappings_per_block() + g->options.n[MAXTHINS])) * 8 * bytes_per_sector; /* in bytes! */ r /= g->unit.factors[idx]; /* in requested unit */ - printf_precision(r, !g->options.n[NUMERIC], g->unit.strings[idx]); + printf_precision(g, r, idx); } int main(int argc, char **argv) { - prg = basename(*argv); - estimated_result(parse_command_line(init(), argc, argv)); + struct global *g = init_prg(); + + prg = basename(argv[0]); + parse_command_line(g, argc, argv); + print_estimated_result(g); + exit_prg(g); return 0; } From ffb585cbc5e7d1ca75becff0fdcf98a2898d4c69 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Wed, 17 Jul 2013 16:00:39 +0200 Subject: [PATCH 10/13] thin_metadata_size: support long unit specifiers; make sure exit_prg() is being called; update manual page --- man8/thin_metadata_size.8 | 4 +- thin-provisioning/thin_metadata_size.c | 235 ++++++++++++++++--------- 2 files changed, 150 insertions(+), 89 deletions(-) diff --git a/man8/thin_metadata_size.8 b/man8/thin_metadata_size.8 index bfe7787..fe84c2e 100644 --- a/man8/thin_metadata_size.8 +++ b/man8/thin_metadata_size.8 @@ -10,7 +10,9 @@ thin_metadata_size \- thin provisioning metadata file/device size calculator. .B thin_metadata_size calculates the size of the thin provisioning metadata based on the block size of the thin provisioned devices, the size of the thin provisioning pool and -the maximum number of all thin prisioned devices and snapshots. +the maximum number of all thin prisioned devices and snapshots. Size/number +option arguments can be followed by unit specifiers in short one character +and long form (eg. -b1m or -b1megabytes). .IP "\fB\-b, \-\-block-size\fP \fIBLOCKSIZE[bskKmMgGtTpPeEzZyY]\fP" Block size of thin provisioned devices in units of bytes,sectors,kilobytes,kibibytes,... respectively. diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index 68eb3e3..d3b4ff1 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -33,11 +33,11 @@ /*----------------------------------------------------------------*/ -static char *prg; /* program name */ - enum numeric_options { BLOCKSIZE, POOLSIZE, MAXTHINS, NUMERIC, OPT_END}; enum return_units { RETURN_BYTES, RETURN_SECTORS }; struct global { + char *prg; /* program name */ + #define UNIT_ARRAY_SZ 18 struct { char *chars; @@ -46,88 +46,132 @@ struct global { } unit; struct options { - unsigned long long n[OPT_END]; + char *unit; char *s[OPT_END]; - char unit; + unsigned long long n[OPT_END]; } options; }; -#define bytes_per_sector g->unit.factors[1] -static struct global *init_prg(void) +static void exit_prg(struct global *g, int ret) +{ + if (g) { + unsigned u; + + if (g->options.unit) + free(g->options.unit); + + for (u = OPT_END; u--; ) { + if (g->options.s[u]) + free(g->options.s[u]); + } + + free(g); + } + + exit(ret); +} + +static void abort_prg(struct global *g, const char *msg) +{ + fprintf(stderr, "%s - %s\n", g->prg, msg); + exit_prg(g, 1); +} + +static struct global *init_prg(char *prg_path) { unsigned u = 0; - static struct global r; static char *unit_strings[] = { "bytes", "sectors", "kilobytes", "kibibytes", "megabytes", "mebibytes", "gigabytes", "gibibytes", "terabytes", "tebibytes", "petabytes", "pebibytes", "exabytes", "ebibytes", "zetabytes", "zebibytes", "yottabytes", "yobibytes" }; + struct global *r = malloc(sizeof(*r)); - memset(&r, 0, sizeof(r)); - r.unit.chars = "bskKmMgGtTpPeEzZyY"; - r.unit.factors[u++] = 1; - r.unit.factors[u++] = 512; - r.unit.factors[u++] = 1024; - r.unit.factors[u++] = 1000; + if (!r) + abort_prg(r, "failed to allocate global context!"); + + memset(r, 0, sizeof(*r)); + r->prg = basename(prg_path); + r->unit.chars = "bskKmMgGtTpPeEzZyY"; + r->unit.factors[u++] = 1; + r->unit.factors[u++] = 512; + r->unit.factors[u++] = 1024; + r->unit.factors[u++] = 1000; for ( ; u < UNIT_ARRAY_SZ; u += 2) { - r.unit.factors[u] = r.unit.factors[2] * r.unit.factors[u - 2]; - r.unit.factors[u+1] = r.unit.factors[3] * r.unit.factors[u - 1]; + r->unit.factors[u] = r->unit.factors[2] * r->unit.factors[u - 2]; + r->unit.factors[u+1] = r->unit.factors[3] * r->unit.factors[u - 1]; } for (u = UNIT_ARRAY_SZ; u--; ) - r.unit.strings[u] = unit_strings[u]; + r->unit.strings[u] = unit_strings[u]; - r.options.unit = 's'; - - return &r; + return r; } +#define bytes_per_sector(g) (g)->unit.factors[1] -static void exit_prg(struct global *g) +static int get_index(struct global *g, char *unit_string) { - unsigned u; + unsigned len, u; - for (u = OPT_END; u--; ) { - if (g->options.s[u]) - free(g->options.s[u]); + if (!unit_string) + return get_index(g, "sectors"); + + len = strlen(unit_string); + if (len == 1) { + char *o = strchr(g->unit.chars, *unit_string); + + if (o) + return o - g->unit.chars; + + } else { + for (u = UNIT_ARRAY_SZ; u--; ) + if (!strncmp(g->unit.strings[u], unit_string, len)) + return u; } + + return -1; } -static unsigned get_index(struct global *g, char unit_char) +static void check_opts(struct global *g) { - char *o = strchr(g->unit.chars, unit_char); + struct options *o = &g->options; - return o ? o - g->unit.chars : 1; + if (!o->n[BLOCKSIZE] || !o->n[POOLSIZE] || !o->n[MAXTHINS]) + abort_prg(g, "3 arguments required!"); + else if (o->n[BLOCKSIZE] & (o->n[BLOCKSIZE] - 1)) + abort_prg(g, "block size must be 2^^N"); + else if (o->n[POOLSIZE] <= o->n[BLOCKSIZE]) + abort_prg(g, "POOLSIZE must be larger than BLOCKSIZE"); + else if (!o->n[MAXTHINS]) + abort_prg(g, "maximum number of thin provisioned devices must be > 0"); } -static void abort_prg(const char *msg) +static unsigned long long to_bytes(struct global *g, char *sz, enum return_units unit, int *index) { - fprintf(stderr, "%s - %s\n", prg, msg); - exit(1); -} - -static void check_opts(struct options *options) -{ - if (!options->n[BLOCKSIZE] || !options->n[POOLSIZE] || !options->n[MAXTHINS]) - abort_prg("3 arguments required!"); - else if (options->n[BLOCKSIZE] & (options->n[BLOCKSIZE] - 1)) - abort_prg("block size must be 2^^N"); - else if (options->n[POOLSIZE] < options->n[BLOCKSIZE]) - abort_prg("POOLSIZE must be much larger than BLOCKSIZE"); - else if (!options->n[MAXTHINS]) - abort_prg("maximum number of thin provisioned devices must be > 0"); -} - -static unsigned long long to_bytes(struct global *g, char *sz, enum return_units unit) -{ - unsigned len = strlen(sz); + int idx; unsigned long long r; - char uc = 's', *us = strchr(g->unit.chars, sz[len-1]); + char *us; - if (us) - uc = *us, sz[len-1] = 0; + for (us = sz; *us; us++) { + if (!isdigit(*us)) + break; + } - r = atoll(sz) * g->unit.factors[get_index(g, uc)]; - return (!us || unit == RETURN_SECTORS) ? r / bytes_per_sector : r; + if (*us) { + idx = get_index(g, us); + if (idx < 0) + abort_prg(g, "Invalid unit specifier!"); + + *us = 0; + *index = idx; + } else { + idx = get_index(g, NULL); + us = NULL; + *index = -1; + } + + r = atoll(sz) * g->unit.factors[idx]; + return (!us || unit == RETURN_SECTORS) ? r / bytes_per_sector(g) : r; } static void printf_aligned(struct global *g, char *a, char *b, char *c, int units) @@ -143,7 +187,7 @@ static void printf_aligned(struct global *g, char *a, char *b, char *c, int unit static void help(struct global *g) { - printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [options]\n", prg); + printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [options]\n", g->prg); printf_aligned(g, "-b", "--block-size BLOCKSIZE", "Block size of thin provisioned devices.", 1); printf_aligned(g, "-s", "--pool-size SIZE", "Size of pool device.", 1); printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", 1); @@ -151,44 +195,54 @@ static void help(struct global *g) printf_aligned(g, "-n", "--numeric-only[=unit]", "Output numeric value only (optionally with unit identifier).", 0); printf_aligned(g, "-h", "--help", "This help.", 0); printf_aligned(g, "-V", "--version", "Print thin provisioning tools version.", 0); - exit(0); + exit_prg(g, 0); +} + +static void version(struct global *g) +{ + printf("%s\n", THIN_PROVISIONING_TOOLS_VERSION); + exit_prg(g, 1); } static void check_unit(struct global *g, char *arg) { - if (*(arg + 1)) - abort_prg("only one unit specifier character allowed!"); - else if (!strchr(g->unit.chars, *arg)) - abort_prg("output unit specifier character invalid!"); + if (get_index(g, arg) < 0) + abort_prg(g, "output unit specifier invalid!"); - g->options.unit = *arg; + g->options.unit = strdup(arg); } static void check_numeric_option(struct global *g, char *arg) { if (g->options.n[NUMERIC]) - abort_prg("-n already given!"); + abort_prg(g, "-n already given!"); g->options.n[NUMERIC] = 1; if (arg) { if (!*arg || strncmp("unit", arg, strlen(arg))) - abort_prg("-n invalid option argument"); + abort_prg(g, "-n invalid option argument"); g->options.n[NUMERIC]++; } } -static void check_size(struct global *g, enum numeric_options o, enum return_units unit, char *arg) +static void check_size(struct global *g, enum numeric_options o, char *arg) { + int idx; + if (g->options.n[o]) - abort_prg("option already given!"); + abort_prg(g, "option already given!"); - g->options.s[o] = strdup(arg); + g->options.n[o] = to_bytes(g, arg, o == MAXTHINS ? RETURN_BYTES : RETURN_SECTORS, &idx); + g->options.s[o] = malloc(strlen(arg) + (idx > -1) ? strlen(g->unit.strings[idx]) : 0 + 1); if (!g->options.s[o]) - abort_prg("failed to allocate string!"); + abort_prg(g, "failed to allocate string!"); + + strcpy(g->options.s[o], arg); + if (idx > -1) + strcat(g->options.s[o], g->unit.strings[idx]); - g->options.n[o] = to_bytes(g, arg, unit); } static void parse_command_line(struct global *g, int argc, char **argv) @@ -206,26 +260,32 @@ static void parse_command_line(struct global *g, int argc, char **argv) }; while ((c = getopt_long(argc, argv, "b:s:m:u:n::hV", long_options, NULL)) != -1) { - if (c == 'b') - check_size(g, BLOCKSIZE, RETURN_SECTORS, optarg); - else if (c == 's') - check_size(g, POOLSIZE, RETURN_SECTORS, optarg); - else if (c == 'm') - check_size(g, MAXTHINS, RETURN_BYTES, optarg); - else if (c == 'u') + switch (c) { + case 'b': + check_size(g, BLOCKSIZE, optarg); + break; + case 's': + check_size(g, POOLSIZE, optarg); + break; + case 'm': + check_size(g, MAXTHINS, optarg); + break; + case 'u': check_unit(g, optarg); - else if (c == 'n') + break; + case 'n': check_numeric_option(g, optarg); - else if (c == 'h') - help(g); - else if (c == 'V') { - printf("%s\n", THIN_PROVISIONING_TOOLS_VERSION); - exit(0); - } else - abort_prg("Invalid option!"); + break; + case 'h': + help(g); /* exits */ + case 'V': + version(g); /* exits */ + default: + abort_prg(g, "Invalid option!"); + } } - check_opts(&g->options); + check_opts(g); } static const unsigned mappings_per_block(void) @@ -246,7 +306,7 @@ static void printf_precision(struct global *g, double r, unsigned idx) if (full) printf("%s - estimated metadata area size [blocksize=%s,poolsize=%s,maxthins=%s] is ", - prg, g->options.s[BLOCKSIZE], g->options.s[POOLSIZE], g->options.s[MAXTHINS]); + g->prg, g->options.s[BLOCKSIZE], g->options.s[POOLSIZE], g->options.s[MAXTHINS]); if (r == rtrunc) printf("%llu", (unsigned long long) r); @@ -267,7 +327,7 @@ static void print_estimated_result(struct global *g) double r; /* double-fold # of nodes, because they aren't fully populated in average */ - r = (1.0 + (2 * g->options.n[POOLSIZE] / g->options.n[BLOCKSIZE] / mappings_per_block() + g->options.n[MAXTHINS])) * 8 * bytes_per_sector; /* in bytes! */ + r = (1.0 + (2 * g->options.n[POOLSIZE] / g->options.n[BLOCKSIZE] / mappings_per_block() + g->options.n[MAXTHINS])) * 8 * bytes_per_sector(g); /* in bytes! */ r /= g->unit.factors[idx]; /* in requested unit */ printf_precision(g, r, idx); @@ -275,11 +335,10 @@ static void print_estimated_result(struct global *g) int main(int argc, char **argv) { - struct global *g = init_prg(); + struct global *g = init_prg(*argv); - prg = basename(argv[0]); parse_command_line(g, argc, argv); print_estimated_result(g); - exit_prg(g); - return 0; + exit_prg(g, 0); + return 0; /* Doesn't get here... */ } From 175c70ecf2a81ca380df57ce576955b230e404ff Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Wed, 17 Jul 2013 17:24:55 +0200 Subject: [PATCH 11/13] thin_metadata_size: remove superfluous array; streamline --- thin-provisioning/thin_metadata_size.c | 67 +++++++++++--------------- 1 file changed, 29 insertions(+), 38 deletions(-) diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index d3b4ff1..dbb6eb5 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -38,15 +38,14 @@ enum return_units { RETURN_BYTES, RETURN_SECTORS }; struct global { char *prg; /* program name */ - #define UNIT_ARRAY_SZ 18 struct { char *chars; - char *strings[UNIT_ARRAY_SZ]; - unsigned long long factors[UNIT_ARRAY_SZ]; + char **strings; + unsigned long long *factors; } unit; struct options { - char *unit; + unsigned unit_idx; char *s[OPT_END]; unsigned long long n[OPT_END]; } options; @@ -54,19 +53,8 @@ struct global { static void exit_prg(struct global *g, int ret) { - if (g) { - unsigned u; - - if (g->options.unit) - free(g->options.unit); - - for (u = OPT_END; u--; ) { - if (g->options.s[u]) - free(g->options.s[u]); - } - + if (g) free(g); - } exit(ret); } @@ -79,39 +67,38 @@ static void abort_prg(struct global *g, const char *msg) static struct global *init_prg(char *prg_path) { - unsigned u = 0; + unsigned u; + static char *unit_chars = "bskKmMgGtTpPeEzZyY"; static char *unit_strings[] = { "bytes", "sectors", "kilobytes", "kibibytes", "megabytes", "mebibytes", "gigabytes", "gibibytes", "terabytes", "tebibytes", "petabytes", "pebibytes", "exabytes", "ebibytes", - "zetabytes", "zebibytes", "yottabytes", "yobibytes" }; + "zetabytes", "zebibytes", "yottabytes", "yobibytes", NULL }; + static unsigned long long unit_factors[18] = { 1, 512, 1024, 1000 }; struct global *r = malloc(sizeof(*r)); if (!r) abort_prg(r, "failed to allocate global context!"); memset(r, 0, sizeof(*r)); - r->prg = basename(prg_path); - r->unit.chars = "bskKmMgGtTpPeEzZyY"; - r->unit.factors[u++] = 1; - r->unit.factors[u++] = 512; - r->unit.factors[u++] = 1024; - r->unit.factors[u++] = 1000; - for ( ; u < UNIT_ARRAY_SZ; u += 2) { - r->unit.factors[u] = r->unit.factors[2] * r->unit.factors[u - 2]; - r->unit.factors[u+1] = r->unit.factors[3] * r->unit.factors[u - 1]; + + for (u = 4; unit_strings[u]; u += 2) { + unit_factors[u] = unit_factors[u-2] * unit_factors[2]; + unit_factors[u+1] = unit_factors[u-1] * unit_factors[3]; } - for (u = UNIT_ARRAY_SZ; u--; ) - r->unit.strings[u] = unit_strings[u]; + r->prg = basename(prg_path); + r->unit.chars = unit_chars; + r->unit.strings = unit_strings; + r->unit.factors = unit_factors; return r; } -#define bytes_per_sector(g) (g)->unit.factors[1] +#define bytes_per_sector(g) (g)->unit.factors[get_index(g, "sectors")] static int get_index(struct global *g, char *unit_string) { - unsigned len, u; + unsigned len; if (!unit_string) return get_index(g, "sectors"); @@ -124,9 +111,11 @@ static int get_index(struct global *g, char *unit_string) return o - g->unit.chars; } else { - for (u = UNIT_ARRAY_SZ; u--; ) - if (!strncmp(g->unit.strings[u], unit_string, len)) - return u; + char **s; + + for (s = g->unit.strings; *s; s++) + if (!strncmp(*s, unit_string, len)) + return s - g->unit.strings; } return -1; @@ -206,10 +195,12 @@ static void version(struct global *g) static void check_unit(struct global *g, char *arg) { - if (get_index(g, arg) < 0) + int idx = get_index(g, arg); + + if (idx < 0) abort_prg(g, "output unit specifier invalid!"); - g->options.unit = strdup(arg); + g->options.unit_idx = idx; } static void check_numeric_option(struct global *g, char *arg) @@ -235,7 +226,7 @@ static void check_size(struct global *g, enum numeric_options o, char *arg) abort_prg(g, "option already given!"); g->options.n[o] = to_bytes(g, arg, o == MAXTHINS ? RETURN_BYTES : RETURN_SECTORS, &idx); - g->options.s[o] = malloc(strlen(arg) + (idx > -1) ? strlen(g->unit.strings[idx]) : 0 + 1); + g->options.s[o] = malloc(strlen(arg) + ((idx > -1) ? strlen(g->unit.strings[idx]) : 0) + 1); if (!g->options.s[o]) abort_prg(g, "failed to allocate string!"); @@ -323,7 +314,7 @@ static void printf_precision(struct global *g, double r, unsigned idx) static void print_estimated_result(struct global *g) { - unsigned idx = get_index(g, g->options.unit); + unsigned idx = g->options.unit_idx; double r; /* double-fold # of nodes, because they aren't fully populated in average */ From 3ee6985bbc1bccae80bb4c236577ce091f197d96 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Thu, 18 Jul 2013 14:03:27 +0200 Subject: [PATCH 12/13] thin_metadata_size: support short/long --numeric-only options; man page adjustment; change long output; stremaline --- man8/thin_metadata_size.8 | 20 +-- thin-provisioning/thin_metadata_size.c | 189 +++++++++++++++---------- 2 files changed, 124 insertions(+), 85 deletions(-) diff --git a/man8/thin_metadata_size.8 b/man8/thin_metadata_size.8 index fe84c2e..33b36b3 100644 --- a/man8/thin_metadata_size.8 +++ b/man8/thin_metadata_size.8 @@ -27,12 +27,12 @@ Maximum sum of all thin provisioned devices and snapshots. Unit identifier supported to allow for convenient entry of large quantities, eg. 1000000 = 1M. Default is absolut quantity without a number unit specifier. -.IP "\fB\-u, \-\-unit\fP \fI[bskKmMgGtTpPeEzZyY]\fP" +.IP "\fB\-u, \-\-unit\fP \fI{bskKmMgGtTpPeEzZyY}\fP" Output unit specifier in units of bytes,sectors,kilobytes,kibibytes,... respectively. Default is in sectors without an output unit specifier. -.IP "\fB\-n[u], \-\-numeric-only[=unit]\fP" -Limit output to just the size number with the optional unit specifier character. +.IP "\fB\-n, \-\-numeric-only [short|long]\fP" +Limit output to just the size number with the optional unit specifier character/string. .IP "\fB\-h, \-\-help\fP" Print help and exit. @@ -43,18 +43,22 @@ Output version information and exit. .SH EXAMPLES Calculates the thin privisioning metadata device size for block size 64 kilobytes, pool size 1 terabytes and maximum number of thin provisioned devices and snapshots of 1000 -in units of sectors with long output. +in units of sectors with long output: .sp .B thin_metadata_size -b64k -s1t -m1000 -Or (using the long options inmstead) for block size 1 gigabyte, pool size 1 petabytes and maximum number of thin provisioned devices -and snapshots of 1 million in units of gigabytes with numeric only output. +Or (using the long options instead) for block size 1 gigabyte, pool size 1 petabytes and maximum number of thin provisioned devices +and snapshots of 1 million with numeric only output in units of gigabytes: .sp .B thin_metadata_size --block-size=1g --pool-size=1p --max-thins=1M --unit=g --numeric-only -Same as before (1g,1p,1M,numeric-only) but with unit specifier character appended. +Same as before (1g,1p,1M,numeric-only) but with unit specifier character appended: .sp -.B thin_metadata_size --block-size=1g --pool-size=1p --max-thins=1M --unit=g --numeric-only=unit +.B thin_metadata_size --block-size=1giga --pool-size=1petabytes --max-thins=1mebi --unit=g --numeric-only=short + +Or with unit specifier string appended: +.sp +.B thin_metadata_size --block-size=1giga --pool-size=1petabytes --max-thins=1mebi --unit=g -nlong .SH DIAGNOSTICS .B thin_metadata_size diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index dbb6eb5..d042dde 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -31,19 +31,26 @@ #include #include "version.h" +#include + /*----------------------------------------------------------------*/ enum numeric_options { BLOCKSIZE, POOLSIZE, MAXTHINS, NUMERIC, OPT_END}; enum return_units { RETURN_BYTES, RETURN_SECTORS }; +enum numeric_type { NO_NUMBER, NUMBER, NUMBER_SHORT, NUMBER_LONG }; +typedef unsigned bool; +enum bool_value { false = 0, true = 1}; struct global { char *prg; /* program name */ + /* Unit representations in characters, strings and numeric factors. */ struct { char *chars; char **strings; unsigned long long *factors; } unit; + /* Command line option properties. */ struct options { unsigned unit_idx; char *s[OPT_END]; @@ -53,55 +60,32 @@ struct global { static void exit_prg(struct global *g, int ret) { - if (g) + if (g) { + unsigned u = OPT_END; + + while (u--) { + if (g->options.s[u]) + free (g->options.s[u]); + } + free(g); + } exit(ret); } static void abort_prg(struct global *g, const char *msg) { - fprintf(stderr, "%s - %s\n", g->prg, msg); + fprintf(stderr, "%s - %s\n", g ? g->prg : "fatal", msg); exit_prg(g, 1); } -static struct global *init_prg(char *prg_path) -{ - unsigned u; - static char *unit_chars = "bskKmMgGtTpPeEzZyY"; - static char *unit_strings[] = { "bytes", "sectors", - "kilobytes", "kibibytes", "megabytes", "mebibytes", - "gigabytes", "gibibytes", "terabytes", "tebibytes", - "petabytes", "pebibytes", "exabytes", "ebibytes", - "zetabytes", "zebibytes", "yottabytes", "yobibytes", NULL }; - static unsigned long long unit_factors[18] = { 1, 512, 1024, 1000 }; - struct global *r = malloc(sizeof(*r)); - - if (!r) - abort_prg(r, "failed to allocate global context!"); - - memset(r, 0, sizeof(*r)); - - for (u = 4; unit_strings[u]; u += 2) { - unit_factors[u] = unit_factors[u-2] * unit_factors[2]; - unit_factors[u+1] = unit_factors[u-1] * unit_factors[3]; - } - - r->prg = basename(prg_path); - r->unit.chars = unit_chars; - r->unit.strings = unit_strings; - r->unit.factors = unit_factors; - - return r; -} -#define bytes_per_sector(g) (g)->unit.factors[get_index(g, "sectors")] - -static int get_index(struct global *g, char *unit_string) +static int unit_index(struct global *g, char *unit_string) { unsigned len; if (!unit_string) - return get_index(g, "sectors"); + return unit_index(g, "sectors"); len = strlen(unit_string); if (len == 1) { @@ -121,40 +105,76 @@ static int get_index(struct global *g, char *unit_string) return -1; } +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) +static struct global *init_prg(char *prg_path) +{ + unsigned u; + static char *unit_chars = "bskKmMgGtTpPeEzZyY"; + static char *unit_strings[] = { "bytes", "sectors", + "kilobytes", "kibibytes", "megabytes", "mebibytes", + "gigabytes", "gibibytes", "terabytes", "tebibytes", + "petabytes", "pebibytes", "exabytes", "ebibytes", + "zetabytes", "zebibytes", "yottabytes", "yobibytes", NULL }; + static unsigned long long unit_factors[ARRAY_SIZE(unit_strings) - 1] = { 1, 512, 1024, 1000 }; + struct global *r = malloc(sizeof(*r)); + + if (!r) + abort_prg(r, "failed to allocate global context!"); + + memset(r, 0, sizeof(*r)); + + for (u = 4; unit_strings[u]; u += 2) { + unit_factors[u] = unit_factors[u-2] * unit_factors[2]; + unit_factors[u+1] = unit_factors[u-1] * unit_factors[3]; + } + + r->prg = basename(prg_path); + r->unit.chars = unit_chars; + r->unit.strings = unit_strings; + r->unit.factors = unit_factors; + r->options.unit_idx = unit_index(r, NULL); + + return r; +} + +static unsigned long long bytes_per_sector(struct global *g) +{ + return g->unit.factors[unit_index(g, "sectors")]; +} + static void check_opts(struct global *g) { struct options *o = &g->options; - if (!o->n[BLOCKSIZE] || !o->n[POOLSIZE] || !o->n[MAXTHINS]) - abort_prg(g, "3 arguments required!"); + if (!o->n[BLOCKSIZE]) + abort_prg(g, "block size required!"); + else if (!o->n[POOLSIZE]) + abort_prg(g, "pool size required!"); + else if (!o->n[MAXTHINS]) + abort_prg(g, "max thins required!"); else if (o->n[BLOCKSIZE] & (o->n[BLOCKSIZE] - 1)) abort_prg(g, "block size must be 2^^N"); else if (o->n[POOLSIZE] <= o->n[BLOCKSIZE]) - abort_prg(g, "POOLSIZE must be larger than BLOCKSIZE"); - else if (!o->n[MAXTHINS]) - abort_prg(g, "maximum number of thin provisioned devices must be > 0"); + abort_prg(g, "pool size must be larger than block size"); } static unsigned long long to_bytes(struct global *g, char *sz, enum return_units unit, int *index) { int idx; unsigned long long r; - char *us; - - for (us = sz; *us; us++) { - if (!isdigit(*us)) - break; - } + char *us = sz; + /* Get pointer to unit identifier. */ + us += strspn(sz, "0123456789"); if (*us) { - idx = get_index(g, us); + idx = unit_index(g, us); if (idx < 0) abort_prg(g, "Invalid unit specifier!"); *us = 0; *index = idx; } else { - idx = get_index(g, NULL); + idx = unit_index(g, NULL); us = NULL; *index = -1; } @@ -163,13 +183,13 @@ static unsigned long long to_bytes(struct global *g, char *sz, enum return_units return (!us || unit == RETURN_SECTORS) ? r / bytes_per_sector(g) : r; } -static void printf_aligned(struct global *g, char *a, char *b, char *c, int units) +static void printf_aligned(struct global *g, char *a, char *b, char *c, bool units, bool mandatory) { char buf[80]; strcpy(buf, b); if (units) - strcat(buf, "["), strcat(buf, g->unit.chars), strcat(buf, "]"); + strcat(buf, mandatory ? "{" :"["), strcat(buf, g->unit.chars), strcat(buf, mandatory ? "}" : "]"); printf("\t%-4s%-44s%s\n", a, buf, c); } @@ -177,13 +197,13 @@ static void printf_aligned(struct global *g, char *a, char *b, char *c, int unit static void help(struct global *g) { printf ("Thin Provisioning Metadata Device Size Calculator.\nUsage: %s [options]\n", g->prg); - printf_aligned(g, "-b", "--block-size BLOCKSIZE", "Block size of thin provisioned devices.", 1); - printf_aligned(g, "-s", "--pool-size SIZE", "Size of pool device.", 1); - printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", 1); - printf_aligned(g, "-u", "--unit ", "Output unit specifier.", 1); - printf_aligned(g, "-n", "--numeric-only[=unit]", "Output numeric value only (optionally with unit identifier).", 0); - printf_aligned(g, "-h", "--help", "This help.", 0); - printf_aligned(g, "-V", "--version", "Print thin provisioning tools version.", 0); + printf_aligned(g, "-b", "--block-size BLOCKSIZE", "Block size of thin provisioned devices.", true, false); + printf_aligned(g, "-s", "--pool-size SIZE", "Size of pool device.", true, false); + printf_aligned(g, "-m", "--max-thins #MAXTHINS", "Maximum sum of all thin devices and snapshots.", true, false); + printf_aligned(g, "-u", "--unit ", "Output unit specifier.", true, true); + printf_aligned(g, "-n", "--numeric-only [short|long]", "Output numeric value only (optionally with short/long unit identifier).", false, false); + printf_aligned(g, "-h", "--help", "This help.", false, false); + printf_aligned(g, "-V", "--version", "Print thin provisioning tools version.", false, false); exit_prg(g, 0); } @@ -195,7 +215,7 @@ static void version(struct global *g) static void check_unit(struct global *g, char *arg) { - int idx = get_index(g, arg); + int idx = unit_index(g, arg); if (idx < 0) abort_prg(g, "output unit specifier invalid!"); @@ -205,33 +225,41 @@ static void check_unit(struct global *g, char *arg) static void check_numeric_option(struct global *g, char *arg) { - if (g->options.n[NUMERIC]) + if (g->options.n[NUMERIC] != NO_NUMBER) abort_prg(g, "-n already given!"); - g->options.n[NUMERIC] = 1; + g->options.n[NUMERIC] = NUMBER; if (arg) { - if (!*arg || strncmp("unit", arg, strlen(arg))) + bool unit_long = !strncmp("long", arg, strlen(arg)); + + if (!*arg || (strncmp("short", arg, strlen(arg)) && !unit_long)) abort_prg(g, "-n invalid option argument"); - g->options.n[NUMERIC]++; + g->options.n[NUMERIC] = unit_long ? NUMBER_LONG : NUMBER_SHORT; } } static void check_size(struct global *g, enum numeric_options o, char *arg) { int idx; + bool valid_index = true; if (g->options.n[o]) abort_prg(g, "option already given!"); g->options.n[o] = to_bytes(g, arg, o == MAXTHINS ? RETURN_BYTES : RETURN_SECTORS, &idx); - g->options.s[o] = malloc(strlen(arg) + ((idx > -1) ? strlen(g->unit.strings[idx]) : 0) + 1); + if (idx < 0) { + valid_index = false; + idx = g->options.unit_idx; + } + + g->options.s[o] = malloc(strlen(arg) + strlen(g->unit.strings[idx]) + 1); if (!g->options.s[o]) abort_prg(g, "failed to allocate string!"); strcpy(g->options.s[o], arg); - if (idx > -1) + if (o != MAXTHINS || valid_index) strcat(g->options.s[o], g->unit.strings[idx]); } @@ -247,7 +275,7 @@ static void parse_command_line(struct global *g, int argc, char **argv) {"numeric-only",optional_argument, NULL, 'n' }, {"help", no_argument, NULL, 'h' }, {"version", no_argument, NULL, 'V' }, - {NULL, 0, NULL, 0 } + {NULL, 0, NULL, 0 } }; while ((c = getopt_long(argc, argv, "b:s:m:u:n::hV", long_options, NULL)) != -1) { @@ -272,7 +300,7 @@ static void parse_command_line(struct global *g, int argc, char **argv) case 'V': version(g); /* exits */ default: - abort_prg(g, "Invalid option!"); + exit_prg(g, 1); } } @@ -290,38 +318,45 @@ static const unsigned mappings_per_block(void) return (btree_size.node - btree_size.node_header) / btree_size.entry; } -static void printf_precision(struct global *g, double r, unsigned idx) +static void print_precision(struct global *g, double r, unsigned idx) { - int full = !g->options.n[NUMERIC]; + bool full = !g->options.n[NUMERIC]; double rtrunc = truncl(r); if (full) - printf("%s - estimated metadata area size [blocksize=%s,poolsize=%s,maxthins=%s] is ", - g->prg, g->options.s[BLOCKSIZE], g->options.s[POOLSIZE], g->options.s[MAXTHINS]); + printf("%s - ", g->prg); if (r == rtrunc) printf("%llu", (unsigned long long) r); else - printf(r - truncl(r) < 1E-2 ? "%0.2e" : "%0.2f", r); + printf(r - rtrunc < 1E-2 ? "%0.2e" : "%0.2f", r); if (full) printf(" %s", g->unit.strings[idx]); - else if (g->options.n[NUMERIC] > 1) - printf("%c", g->unit.chars[idx]); + else if (g->options.n[NUMERIC] > NUMBER) { + if (g->options.n[NUMERIC] == NUMBER_SHORT) + printf("%c", g->unit.chars[idx]); + else + printf("%s", g->unit.strings[idx]); + } + + if (full) + printf(" estimated metadata area size for \"--block-size=%s --pool-size=%s --max-thins=%s\"", + g->options.s[BLOCKSIZE], g->options.s[POOLSIZE], g->options.s[MAXTHINS]); putchar('\n'); } static void print_estimated_result(struct global *g) { - unsigned idx = g->options.unit_idx; double r; /* double-fold # of nodes, because they aren't fully populated in average */ - r = (1.0 + (2 * g->options.n[POOLSIZE] / g->options.n[BLOCKSIZE] / mappings_per_block() + g->options.n[MAXTHINS])) * 8 * bytes_per_sector(g); /* in bytes! */ - r /= g->unit.factors[idx]; /* in requested unit */ + r = (1.0 + (2 * g->options.n[POOLSIZE] / g->options.n[BLOCKSIZE] / mappings_per_block() + g->options.n[MAXTHINS])); /* in 4k blocks */ + r *= 8 * bytes_per_sector(g); /* in bytes! */ + r /= g->unit.factors[g->options.unit_idx]; /* in requested unit */ - printf_precision(g, r, idx); + print_precision(g, r, g->options.unit_idx); } int main(int argc, char **argv) From 9fac224f250ee2d6642d673d7d65afe346d68af5 Mon Sep 17 00:00:00 2001 From: Heinz Mauelshagen Date: Thu, 18 Jul 2013 14:19:06 +0200 Subject: [PATCH 13/13] thin_metadata_size: use NOO_NUMBER whilst defining full bool --- Makefile.in | 4 ++++ thin-provisioning/thin_metadata_size.c | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile.in b/Makefile.in index 2368f9b..fb64cf8 100644 --- a/Makefile.in +++ b/Makefile.in @@ -264,7 +264,11 @@ install: $(PROGRAMS) $(INSTALL_DIR) $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_check.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_dump.8 $(MANPATH)/man8 + $(INSTALL_DATA) man8/thin_metadata_size.8 $(MANPATH)/man8 + $(INSTALL_DATA) man8/thin_repair.8 $(MANPATH)/man8 $(INSTALL_DATA) man8/thin_restore.8 $(MANPATH)/man8 + $(INSTALL_DATA) man8/thin_rmap.8 $(MANPATH)/man8 + .PHONY: install ifeq ("@TESTING@", "yes") diff --git a/thin-provisioning/thin_metadata_size.c b/thin-provisioning/thin_metadata_size.c index d042dde..1f52d51 100755 --- a/thin-provisioning/thin_metadata_size.c +++ b/thin-provisioning/thin_metadata_size.c @@ -320,7 +320,7 @@ static const unsigned mappings_per_block(void) static void print_precision(struct global *g, double r, unsigned idx) { - bool full = !g->options.n[NUMERIC]; + bool full = g->options.n[NUMERIC] == NO_NUMBER; double rtrunc = truncl(r); if (full)