master - report: select: add --select arg to pvdisplay, vgdisplay and lvdisplay
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=fe952e735ae260...
Commit: fe952e735ae260849a9a9c04f38bbb08f8e6c22b
Parent: 5b734a0ea1ab5ef3c757ec51dcadb4837fe7f936
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:39:11 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add --select arg to pvdisplay, vgdisplay and lvdisplay
---
tools/commands.h | 11 +++++++----
tools/lvdisplay.c | 1 +
tools/pvdisplay.c | 1 +
tools/vgdisplay.c | 1 +
4 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/tools/commands.h b/tools/commands.h
index f8eece9..4504126 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -371,6 +371,7 @@ xx(lvdisplay,
"\t[--nosuffix]\n"
"\t[-o|--options [+]Field[,Field]]\n"
"\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[-S|--select Selection]\n"
"\t[-P|--partial] " "\n"
"\t[--readonly]\n"
"\t[--segments]\n"
@@ -384,7 +385,7 @@ xx(lvdisplay,
aligned_ARG, all_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG,
ignoreskippedcluster_ARG, maps_ARG, noheadings_ARG, nosuffix_ARG,
options_ARG, sort_ARG, partial_ARG, readonly_ARG, segments_ARG,
- separator_ARG, unbuffered_ARG, units_ARG)
+ select_ARG, separator_ARG, unbuffered_ARG, units_ARG)
xx(lvextend,
"Add space to a logical volume",
@@ -743,6 +744,7 @@ xx(pvdisplay,
"\t[--nosuffix]\n"
"\t[-o|--options [+]Field[,Field]]\n"
"\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
+ "\t[-S|--select Selection]\n"
"\t[--readonly]\n"
"\t[--separator Separator]\n"
"\t[--unbuffered]\n"
@@ -753,7 +755,7 @@ xx(pvdisplay,
aligned_ARG, all_ARG, colon_ARG, columns_ARG, ignorelockingfailure_ARG,
ignoreskippedcluster_ARG, maps_ARG, noheadings_ARG, nosuffix_ARG,
- options_ARG, readonly_ARG, separator_ARG, short_ARG, sort_ARG,
+ options_ARG, readonly_ARG, select_ARG, separator_ARG, short_ARG, sort_ARG,
unbuffered_ARG, units_ARG)
xx(pvmove,
@@ -1034,6 +1036,7 @@ xx(vgdisplay,
"\t[-o|--options [+]Field[,Field]]\n"
"\t[-O|--sort [+|-]key1[,[+|-]key2[,...]]]\n"
"\t[-P|--partial] " "\n"
+ "\t[-S|--select Selection]\n"
"\t[--readonly]\n"
"\t[--separator Separator]\n"
"\t[--unbuffered]\n"
@@ -1044,8 +1047,8 @@ xx(vgdisplay,
activevolumegroups_ARG, aligned_ARG, colon_ARG, columns_ARG,
ignorelockingfailure_ARG, ignoreskippedcluster_ARG, noheadings_ARG,
- nosuffix_ARG, options_ARG, partial_ARG, readonly_ARG, short_ARG,
- separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
+ nosuffix_ARG, options_ARG, partial_ARG, readonly_ARG, select_ARG,
+ short_ARG, separator_ARG, sort_ARG, unbuffered_ARG, units_ARG)
xx(vgexport,
"Unregister volume group(s) from the system",
diff --git a/tools/lvdisplay.c b/tools/lvdisplay.c
index 1f40f09..185e539 100644
--- a/tools/lvdisplay.c
+++ b/tools/lvdisplay.c
@@ -45,6 +45,7 @@ int lvdisplay(struct cmd_context *cmd, int argc, char **argv)
if (arg_count(cmd, aligned_ARG) ||
arg_count(cmd, noheadings_ARG) ||
arg_count(cmd, options_ARG) ||
+ arg_count(cmd, select_ARG) ||
arg_count(cmd, separator_ARG) ||
arg_count(cmd, sort_ARG) ||
arg_count(cmd, unbuffered_ARG)) {
diff --git a/tools/pvdisplay.c b/tools/pvdisplay.c
index 3de7969..773d9a9 100644
--- a/tools/pvdisplay.c
+++ b/tools/pvdisplay.c
@@ -104,6 +104,7 @@ int pvdisplay(struct cmd_context *cmd, int argc, char **argv)
arg_count(cmd, all_ARG) ||
arg_count(cmd, noheadings_ARG) ||
arg_count(cmd, options_ARG) ||
+ arg_count(cmd, select_ARG) ||
arg_count(cmd, separator_ARG) ||
arg_count(cmd, sort_ARG) ||
arg_count(cmd, unbuffered_ARG)) {
diff --git a/tools/vgdisplay.c b/tools/vgdisplay.c
index 81ffbd9..a739d11 100644
--- a/tools/vgdisplay.c
+++ b/tools/vgdisplay.c
@@ -65,6 +65,7 @@ int vgdisplay(struct cmd_context *cmd, int argc, char **argv)
} else if (arg_count(cmd, aligned_ARG) ||
arg_count(cmd, noheadings_ARG) ||
arg_count(cmd, options_ARG) ||
+ arg_count(cmd, select_ARG) ||
arg_count(cmd, separator_ARG) ||
arg_count(cmd, sort_ARG) || arg_count(cmd, unbuffered_ARG)) {
log_error("Incompatible options selected");
8 years, 11 months
master - report: select: add --select arg to pvs, vgs and lvs
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=5b734a0ea1ab5e...
Commit: 5b734a0ea1ab5ef3c757ec51dcadb4837fe7f936
Parent: 3a1c7e5d785a75016f5326ed6464da3b5e2d6a8a
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:38:59 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add --select arg to pvs, vgs and lvs
---
lib/report/report.c | 9 +++++----
lib/report/report.h | 2 +-
tools/args.h | 1 +
tools/commands.h | 24 ++++++++++++------------
tools/reporter.c | 7 +++++--
5 files changed, 24 insertions(+), 19 deletions(-)
diff --git a/lib/report/report.c b/lib/report/report.c
index 2f340ed..8a87bd2 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -1234,7 +1234,7 @@ static const struct dm_report_field_type _devtypes_fields[] = {
void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
report_type_t *report_type, const char *separator,
int aligned, int buffered, int headings, int field_prefixes,
- int quoted, int columns_as_rows)
+ int quoted, int columns_as_rows, const char *selection)
{
uint32_t report_flags = 0;
int devtypes_report = *report_type & DEVTYPES ? 1 : 0;
@@ -1258,9 +1258,10 @@ void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
if (columns_as_rows)
report_flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
- rh = dm_report_init(report_type, devtypes_report ? _devtypes_report_types : _report_types,
- devtypes_report ? _devtypes_fields : _fields, format,
- separator, report_flags, keys, cmd);
+ rh = dm_report_init_with_selection(report_type,
+ devtypes_report ? _devtypes_report_types : _report_types,
+ devtypes_report ? _devtypes_fields : _fields, format,
+ separator, report_flags, keys, selection, cmd);
if (rh && field_prefixes)
dm_report_set_output_field_name_prefix(rh, "lvm2_");
diff --git a/lib/report/report.h b/lib/report/report.h
index 2c093b0..a89a637 100644
--- a/lib/report/report.h
+++ b/lib/report/report.h
@@ -38,7 +38,7 @@ typedef int (*field_report_fn) (struct report_handle * dh, struct field * field,
void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
report_type_t *report_type, const char *separator,
int aligned, int buffered, int headings, int field_prefixes,
- int quoted, int columns_as_rows);
+ int quoted, int columns_as_rows, const char *selection);
void report_free(void *handle);
int report_object(void *handle, struct volume_group *vg,
struct logical_volume *lv, struct physical_volume *pv,
diff --git a/tools/args.h b/tools/args.h
index 6a594c3..0ee380a 100644
--- a/tools/args.h
+++ b/tools/args.h
@@ -174,6 +174,7 @@ arg(physicalextentsize_ARG, 's', "physicalextentsize", size_mb_arg, 0)
arg(stdin_ARG, 's', "stdin", NULL, 0)
arg(snapshot_ARG, 's', "snapshot", NULL, 0)
arg(short_ARG, 's', "short", NULL, 0)
+arg(select_ARG, 'S', "select", string_arg, 0)
arg(thin_ARG, 'T', "thin", NULL, 0)
arg(test_ARG, 't', "test", NULL, 0)
arg(uuid_ARG, 'u', "uuid", NULL, 0)
diff --git a/tools/commands.h b/tools/commands.h
index 0fa028d..f8eece9 100644
--- a/tools/commands.h
+++ b/tools/commands.h
@@ -574,6 +574,7 @@ xx(lvs,
"\t[--readonly]\n"
"\t[--rows]\n"
"\t[--segments]\n"
+ "\t[-S|--select Selection]\n"
"\t[--separator Separator]\n"
"\t[--trustcache]\n"
"\t[--unbuffered]\n"
@@ -584,11 +585,10 @@ xx(lvs,
"\t[LogicalVolume[Path] [LogicalVolume[Path]...]]\n",
aligned_ARG, all_ARG, ignorelockingfailure_ARG, ignoreskippedcluster_ARG,
- nameprefixes_ARG,
- noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG,
- readonly_ARG,
- rows_ARG, segments_ARG, separator_ARG, sort_ARG, trustcache_ARG,
- unbuffered_ARG, units_ARG, unquoted_ARG)
+ nameprefixes_ARG, noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG,
+ partial_ARG, readonly_ARG, rows_ARG, segments_ARG, select_ARG,
+ separator_ARG, sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG,
+ unquoted_ARG)
xx(lvscan,
"List all logical volumes in all volume groups",
@@ -816,6 +816,7 @@ xx(pvs,
"\t[--readonly]\n"
"\t[--rows]\n"
"\t[--segments]\n"
+ "\t[-S|--select Selection]\n"
"\t[--separator Separator]\n"
"\t[--trustcache]\n"
"\t[--unbuffered]\n"
@@ -827,8 +828,8 @@ xx(pvs,
aligned_ARG, all_ARG, ignorelockingfailure_ARG, ignoreskippedcluster_ARG,
nameprefixes_ARG, noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG,
- partial_ARG, readonly_ARG, rows_ARG, segments_ARG, separator_ARG, sort_ARG,
- trustcache_ARG, unbuffered_ARG, units_ARG, unquoted_ARG)
+ partial_ARG, readonly_ARG, rows_ARG, segments_ARG, select_ARG, separator_ARG,
+ sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG, unquoted_ARG)
xx(pvscan,
"List all physical volumes",
@@ -1202,6 +1203,7 @@ xx(vgs,
"\t[-P|--partial] " "\n"
"\t[--readonly]\n"
"\t[--rows]\n"
+ "\t[-S|--select Selection]\n"
"\t[--separator Separator]\n"
"\t[--trustcache]\n"
"\t[--unbuffered]\n"
@@ -1212,11 +1214,9 @@ xx(vgs,
"\t[VolumeGroupName [VolumeGroupName...]]\n",
aligned_ARG, all_ARG, ignorelockingfailure_ARG, ignoreskippedcluster_ARG,
- nameprefixes_ARG,
- noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG, partial_ARG,
- readonly_ARG,
- rows_ARG, separator_ARG, sort_ARG, trustcache_ARG, unbuffered_ARG, units_ARG,
- unquoted_ARG)
+ nameprefixes_ARG, noheadings_ARG, nolocking_ARG, nosuffix_ARG, options_ARG,
+ partial_ARG, readonly_ARG, rows_ARG, select_ARG, separator_ARG, sort_ARG,
+ trustcache_ARG, unbuffered_ARG, units_ARG, unquoted_ARG)
xx(vgscan,
"Search for all volume groups",
diff --git a/tools/reporter.c b/tools/reporter.c
index b20b8ed..56980cf 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -235,7 +235,7 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
void *report_handle;
const char *opts;
char *str;
- const char *keys = NULL, *options = NULL, *separator;
+ const char *keys = NULL, *options = NULL, *selection = NULL, *separator;
int r = ECMD_PROCESSED;
int aligned, buffered, headings, field_prefixes, quoted;
int columns_as_rows;
@@ -348,10 +348,13 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
if (arg_count(cmd, rows_ARG))
columns_as_rows = 1;
+ if (arg_count(cmd, select_ARG))
+ selection = arg_str_value(cmd, select_ARG, NULL);
+
if (!(report_handle = report_init(cmd, options, keys, &report_type,
separator, aligned, buffered,
headings, field_prefixes, quoted,
- columns_as_rows))) {
+ columns_as_rows, selection))) {
if ( (!strcasecmp(options, DM_REPORT_FIELD_RESERVED_NAME_HELP) ||
!strcmp(options, DM_REPORT_FIELD_RESERVED_NAME_HELP_ALT)) ||
(!strcasecmp(keys, DM_REPORT_FIELD_RESERVED_NAME_HELP) ||
8 years, 11 months
master - report: select: add --select arg to dmsetup
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=3a1c7e5d785a75...
Commit: 3a1c7e5d785a75016f5326ed6464da3b5e2d6a8a
Parent: bc6458de878af27667612ff7873243454bb63566
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:38:49 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add --select arg to dmsetup
---
tools/dmsetup.c | 21 ++++++++++++++++-----
1 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index fd87d42..1a5e068 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -120,6 +120,7 @@ enum {
ADD_NODE_ON_RESUME_ARG,
CHECKS_ARG,
COLS_ARG,
+ SELECT_ARG,
EXEC_ARG,
FORCE_ARG,
GID_ARG,
@@ -2846,6 +2847,7 @@ static int _report_init(const struct command *cmd)
char *options = (char *) default_report_options;
const char *keys = "";
const char *separator = " ";
+ const char *selection = NULL;
int aligned = 1, headings = 1, buffered = 1, field_prefixes = 0;
int quoted = 1, columns_as_rows = 0;
uint32_t flags = 0;
@@ -2909,6 +2911,9 @@ static int _report_init(const struct command *cmd)
aligned = 0;
}
+ if (_switches[SELECT_ARG] && _string_args[SELECT_ARG])
+ selection = _string_args[SELECT_ARG];
+
if (aligned)
flags |= DM_REPORT_OUTPUT_ALIGNED;
@@ -2927,9 +2932,9 @@ static int _report_init(const struct command *cmd)
if (columns_as_rows)
flags |= DM_REPORT_OUTPUT_COLUMNS_AS_ROWS;
- if (!(_report = dm_report_init(&_report_type,
- _report_types, _report_fields,
- options, separator, flags, keys, NULL)))
+ if (!(_report = dm_report_init_with_selection(&_report_type, _report_types,
+ _report_fields, options, separator, flags, keys,
+ selection, NULL)))
goto out;
if ((_report_type & DR_TREE) && !_build_whole_deptree(cmd)) {
@@ -3111,7 +3116,8 @@ static void _usage(FILE *out)
" [--udevcookie [cookie]] [--noudevrules] [--noudevsync] [--verifyudev]\n"
" [-y|--yes] [--readahead [+]<sectors>|auto|none] [--retry]\n"
" [-c|-C|--columns] [-o <fields>] [-O|--sort <sort_fields>]\n"
- " [--nameprefixes] [--noheadings] [--separator <separator>]\n\n");
+ " [-S|--select <selection>] [--nameprefixes] [--noheadings]\n"
+ " [--separator <separator>]\n\n");
for (i = 0; _commands[i].name; i++)
fprintf(out, "\t%s %s\n", _commands[i].name, _commands[i].help);
fprintf(out, "\n<device> may be device name or -u <uuid> or "
@@ -3518,6 +3524,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
{"readonly", 0, &ind, READ_ONLY},
{"checks", 0, &ind, CHECKS_ARG},
{"columns", 0, &ind, COLS_ARG},
+ {"select", 1, &ind, SELECT_ARG},
{"exec", 1, &ind, EXEC_ARG},
{"force", 0, &ind, FORCE_ARG},
{"gid", 1, &ind, GID_ARG},
@@ -3615,7 +3622,7 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
optarg = 0;
optind = OPTIND_INIT;
- while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:ru:U:vy",
+ while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfG:hj:m:M:no:O:rS:u:U:vy",
long_options, NULL)) != -1) {
if (c == ':' || c == '?')
return 0;
@@ -3649,6 +3656,10 @@ static int _process_switches(int *argc, char ***argv, const char *dev_dir)
_switches[SORT_ARG]++;
_string_args[SORT_ARG] = optarg;
}
+ if (c == 'S' || ind == SELECT_ARG) {
+ _switches[SELECT_ARG]++;
+ _string_args[SELECT_ARG] = optarg;
+ }
if (c == 'v' || ind == VERBOSE_ARG)
_switches[VERBOSE_ARG]++;
if (c == 'u' || ind == UUID_ARG) {
8 years, 11 months
master - report: select: use _check_report_selection in dm_report_object to report only objects that satisfy the report selection
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=bc6458de878af2...
Commit: bc6458de878af27667612ff7873243454bb63566
Parent: d33280a978c3176e5c589c9cd477b766204e4914
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:38:36 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: use _check_report_selection in dm_report_object to report only objects that satisfy the report selection
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html
This activates the actual selection process in dm_report_object.
---
libdm/libdm-report.c | 39 +++++++++++++++++++++++++++------------
1 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 51224f1..93cba9f 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -953,19 +953,20 @@ static int _check_report_selection(struct dm_report *rh, struct dm_list *fields)
int dm_report_object(struct dm_report *rh, void *object)
{
struct field_properties *fp;
- struct row *row;
+ struct row *row = NULL;
struct dm_report_field *field;
void *data = NULL;
int len;
+ int r = 0;
if (!rh) {
log_error(INTERNAL_ERROR "dm_report handler is NULL.");
- return 0;
+ goto out;
}
if (!(row = dm_pool_zalloc(rh->mem, sizeof(*row)))) {
log_error("dm_report_object: struct row allocation failed");
- return 0;
+ goto out;
}
row->rh = rh;
@@ -976,25 +977,25 @@ int dm_report_object(struct dm_report *rh, void *object)
rh->keys_count))) {
log_error("dm_report_object: "
"row sort value structure allocation failed");
- return 0;
+ goto out;
}
dm_list_init(&row->fields);
- dm_list_add(&rh->rows, &row->list);
/* For each field to be displayed, call its report_fn */
dm_list_iterate_items(fp, &rh->field_props) {
if (!(field = dm_pool_zalloc(rh->mem, sizeof(*field)))) {
log_error("dm_report_object: "
"struct dm_report_field allocation failed");
- return 0;
+ goto out;
}
field->props = fp;
if (!(data = _report_get_field_data(rh, fp, object))) {
- log_error("dm_report_object: no data for field %s",
+ log_error("dm_report_object: "
+ "no data assigned to field %s",
rh->fields[fp->field_num].id);
- return 0;
+ goto out;
}
if (!rh->fields[fp->field_num].report_fn(rh, rh->mem,
@@ -1003,24 +1004,38 @@ int dm_report_object(struct dm_report *rh, void *object)
log_error("dm_report_object: "
"report function failed for field %s",
rh->fields[fp->field_num].id);
- return 0;
+ goto out;
}
+ dm_list_add(&row->fields, &field->list);
+ }
+
+ if (!_check_report_selection(rh, &row->fields)) {
+ r = 1;
+ goto out;
+ }
+
+ dm_list_add(&rh->rows, &row->list);
+
+ dm_list_iterate_items(field, &row->fields) {
len = (int) strlen(field->report_string);
- if (len > field->props->width)
+ if ((len > field->props->width))
field->props->width = len;
if ((rh->flags & RH_SORT_REQUIRED) &&
(field->props->flags & FLD_SORT_KEY)) {
(*row->sort_fields)[field->props->sort_posn] = field;
}
- dm_list_add(&row->fields, &field->list);
}
if (!(rh->flags & DM_REPORT_OUTPUT_BUFFERED))
return dm_report_output(rh);
- return 1;
+ r = 1;
+out:
+ if (!r)
+ dm_pool_free(rh->mem, row);
+ return r;
}
/*
8 years, 11 months
master - report: select: add _check_selection fn to support checking fields against given selections
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=d33280a978c317...
Commit: d33280a978c3176e5c589c9cd477b766204e4914
Parent: 0103738ef5ed5dc165d9b1d29ccc4902bda5998f
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:38:22 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add _check_selection fn to support checking fields against given selections
This is rebased and edited versions of the original design and
patch proposed by Jun'ichi Nomura:
http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html
The _check_selection implements the actual field checking against the
selection tree.
---
libdm/libdm-report.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 155 insertions(+), 1 deletions(-)
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 1d00c51..51224f1 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -16,6 +16,8 @@
#include "dmlib.h"
#include <ctype.h>
+#include <math.h> /* fabs() */
+#include <float.h> /* DBL_EPSILON */
/*
* Internal flags
@@ -797,6 +799,157 @@ static void *_report_get_field_data(struct dm_report *rh,
return (void *)(ret + rh->fields[fp->field_num].offset);
}
+static int _cmp_field_int(const char *field_id, uint64_t a, uint64_t b, uint32_t flags)
+{
+ switch(flags & FLD_CMP_MASK) {
+ case FLD_CMP_EQUAL:
+ return a == b;
+ case FLD_CMP_NOT|FLD_CMP_EQUAL:
+ return a != b;
+ case FLD_CMP_NUMBER|FLD_CMP_GT:
+ return a > b;
+ case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
+ return a >= b;
+ case FLD_CMP_NUMBER|FLD_CMP_LT:
+ return a < b;
+ case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
+ return a <= b;
+ default:
+ log_error(INTERNAL_ERROR "_cmp_field_int: unsupported number "
+ "comparison type for field %s", field_id);
+ }
+
+ return 0;
+}
+
+static int _close_enough(double d1, double d2)
+{
+ return fabs(d1 - d2) < DBL_EPSILON;
+}
+
+static int _cmp_field_double(const char *field_id, double a, double b, uint32_t flags)
+{
+ switch(flags & FLD_CMP_MASK) {
+ case FLD_CMP_EQUAL:
+ return _close_enough(a, b);
+ case FLD_CMP_NOT|FLD_CMP_EQUAL:
+ return !_close_enough(a, b);
+ case FLD_CMP_NUMBER|FLD_CMP_GT:
+ return (a > b) && !_close_enough(a, b);
+ case FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL:
+ return (a > b) || _close_enough(a, b);
+ case FLD_CMP_NUMBER|FLD_CMP_LT:
+ return (a < b) && !_close_enough(a, b);
+ case FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL:
+ return a < b || _close_enough(a, b);
+ default:
+ log_error(INTERNAL_ERROR "_cmp_field_double: unsupported number "
+ "comparison type for selection field %s", field_id);
+ }
+
+ return 0;
+}
+
+static int _cmp_field_string(const char *field_id, const char *a, const char *b, uint32_t flags)
+{
+ switch (flags & FLD_CMP_MASK) {
+ case FLD_CMP_EQUAL:
+ return !strcmp(a, b);
+ case FLD_CMP_NOT|FLD_CMP_EQUAL:
+ return strcmp(a, b);
+ default:
+ log_error(INTERNAL_ERROR "_cmp_field_string: unsupported string "
+ "comparison type for selection field %s", field_id);
+ }
+
+ return 0;
+}
+
+static int _cmp_field_regex(const char *s, struct dm_regex *r, uint32_t flags)
+{
+ int match = dm_regex_match(r, s) >= 0;
+ return flags & FLD_CMP_NOT ? !match : match;
+}
+
+static int _compare_selection_field(struct dm_report *rh,
+ struct dm_report_field *f,
+ struct field_selection *fs)
+{
+ const char *field_id = rh->fields[f->props->field_num].id;
+ int r = 0;
+
+ if (!f->sort_value) {
+ log_error("_compare_selection_field: field without value :%d",
+ f->props->field_num);
+ return 0;
+ }
+
+ if (fs->flags & FLD_CMP_REGEX)
+ r = _cmp_field_regex((const char *) f->sort_value, fs->v.r, fs->flags);
+ else {
+ switch(f->props->flags & DM_REPORT_FIELD_TYPE_MASK) {
+ case DM_REPORT_FIELD_TYPE_NUMBER:
+ r = _cmp_field_int(field_id, *(const uint64_t *) f->sort_value, fs->v.i, fs->flags);
+ break;
+ case DM_REPORT_FIELD_TYPE_SIZE:
+ r = _cmp_field_double(field_id, *(const uint64_t *) f->sort_value, fs->v.d, fs->flags);
+ break;
+ case DM_REPORT_FIELD_TYPE_STRING:
+ r = _cmp_field_string(field_id, (const char *) f->sort_value, fs->v.s, fs->flags);
+ break;
+ default:
+ log_error(INTERNAL_ERROR "_compare_selection_field: unknown field type for field %s", field_id);
+ }
+ }
+
+ return r;
+}
+
+static int _check_selection(struct dm_report *rh, struct selection_node *sn,
+ struct dm_list *fields)
+{
+ int r;
+ struct selection_node *iter_n;
+ struct dm_report_field *f;
+
+ switch (sn->type & SEL_MASK) {
+ case SEL_ITEM:
+ r = 1;
+ dm_list_iterate_items(f, fields) {
+ if (sn->selection.item->fp != f->props)
+ continue;
+ if (!_compare_selection_field(rh, f, sn->selection.item))
+ r = 0;
+ }
+ break;
+ case SEL_OR:
+ r = 0;
+ dm_list_iterate_items(iter_n, &sn->selection.set)
+ if ((r |= _check_selection(rh, iter_n, fields)))
+ break;
+ break;
+ case SEL_AND:
+ r = 1;
+ dm_list_iterate_items(iter_n, &sn->selection.set)
+ if (!(r &= _check_selection(rh, iter_n, fields)))
+ break;
+ break;
+ default:
+ log_error("Unsupported selection type");
+ return 0;
+ }
+
+ return (sn->type & SEL_MODIFIER_NOT) ? !r : r;
+}
+
+static int _check_report_selection(struct dm_report *rh, struct dm_list *fields)
+{
+ if (!rh->selection_root)
+ return 1;
+
+ return _check_selection(rh, rh->selection_root, fields);
+}
+
int dm_report_object(struct dm_report *rh, void *object)
{
struct field_properties *fp;
@@ -1356,7 +1509,8 @@ static struct selection_node *_parse_selection(struct dm_report *rh,
if (!(last = _tok_value_regex(ft, last, &vs, &ve, &flags)))
goto_bad;
} else {
- if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE)
+ if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE ||
+ ft->flags == DM_REPORT_FIELD_TYPE_NUMBER)
custom = &factor;
else
custom = NULL;
8 years, 11 months
master - report: select: add dm_report_init_with_selection to libdm
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=0103738ef5ed5d...
Commit: 0103738ef5ed5dc165d9b1d29ccc4902bda5998f
Parent: 2c3e84a68d1f991bfe47637017723b7cf0435dff
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:38:08 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add dm_report_init_with_selection to libdm
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html
The dm_report_init_with_selection is the same as dm_report_init
but it contains an additional argument to set the selection
in the form of a string that contains field names to check against and
selection operators. The selection string is parsend and a selection
tree is composed for use in the checks against individual fields when
the report is processed. The parsed selection tree is stored in dm_report
structure as "selection_root".
---
libdm/libdevmapper.h | 11 ++
libdm/libdm-report.c | 434 ++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 436 insertions(+), 9 deletions(-)
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 3a51e14..319b07c 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1641,7 +1641,18 @@ struct dm_report *dm_report_init(uint32_t *report_types,
uint32_t output_flags,
const char *sort_keys,
void *private_data);
+struct dm_report *dm_report_init_with_selection(uint32_t *report_types,
+ const struct dm_report_object_type *types,
+ const struct dm_report_field_type *fields,
+ const char *output_fields,
+ const char *output_separator,
+ uint32_t output_flags,
+ const char *sort_keys,
+ const char *selection,
+ void *private_data);
int dm_report_object(struct dm_report *rh, void *object);
+int dm_report_set_output_selection(struct dm_report *rh, uint32_t *report_types,
+ const char *selection);
int dm_report_output(struct dm_report *rh);
void dm_report_free(struct dm_report *rh);
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index 882bf3e..1d00c51 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -48,6 +48,8 @@ struct dm_report {
/* To store caller private data */
void *private;
+
+ struct selection_node *selection_root;
};
/*
@@ -496,6 +498,23 @@ static int _add_all_fields(struct dm_report *rh, uint32_t type)
return 1;
}
+static int _get_field(struct dm_report *rh, const char *field, size_t flen, uint32_t *f_ret)
+{
+ uint32_t f;
+
+ if (!flen)
+ return 0;
+
+ for (f = 0; rh->fields[f].report_fn; f++) {
+ if (_is_same_field(rh->fields[f].id, field, flen, rh->field_prefix)) {
+ *f_ret = f;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int _field_match(struct dm_report *rh, const char *field, size_t flen,
unsigned report_type_only)
{
@@ -504,15 +523,13 @@ static int _field_match(struct dm_report *rh, const char *field, size_t flen,
if (!flen)
return 0;
- for (f = 0; rh->fields[f].report_fn; f++)
- if (_is_same_field(rh->fields[f].id, field, flen,
- rh->field_prefix)) {
- if (report_type_only) {
- rh->report_types |= rh->fields[f].type;
- return 1;
- } else
- return _add_field(rh, f, 0) ? 1 : 0;
- }
+ if ((_get_field(rh, field, flen, &f))) {
+ if (report_type_only) {
+ rh->report_types |= rh->fields[f].type;
+ return 1;
+ } else
+ return _add_field(rh, f, 0) ? 1 : 0;
+ }
if ((type = _all_match(rh, field, flen))) {
if (report_type_only) {
@@ -1096,6 +1113,13 @@ static const char *_tok_value(const struct dm_report_field_type *ft,
*flags |= DM_REPORT_FIELD_TYPE_NUMBER;
} else {
s = tmp;
+ /*
+ * If size unit is not defined in the selection
+ * use use 'm' (1 MiB) by default. This is the
+ * same behaviour as seen in lvcreate -L <size>.
+ */
+ if (!*factor)
+ *factor = 1024*1024;
*flags |= DM_REPORT_FIELD_TYPE_SIZE;
}
}
@@ -1128,7 +1152,399 @@ static const char *_tok_field_name(const char *s,
return s;
}
+static struct field_selection *_create_field_selection(struct dm_report *rh,
+ uint32_t field_num,
+ const char *v,
+ size_t len,
+ uint32_t flags,
+ void *custom)
+{
+ static const char *_out_of_range_msg = "Field selection value %s out of supported range for field %s.";
+ struct field_properties *fp, *found = NULL;
+ struct field_selection *fs;
+ const char *field_id;
+ uint64_t factor;
+ char *s;
+
+ dm_list_iterate_items(fp, &rh->field_props) {
+ if (fp->field_num == field_num) {
+ found = fp;
+ break;
+ }
+ }
+
+ /* The field is neither used in display options nor sort keys. */
+ if (!found) {
+ if (!(found = _add_field(rh, field_num, FLD_HIDDEN)))
+ return NULL;
+ rh->report_types |= rh->fields[field_num].type;
+ }
+
+ field_id = rh->fields[found->field_num].id;
+
+ if (!(found->flags & flags & DM_REPORT_FIELD_TYPE_MASK)) {
+ log_error("dm_report: incompatible comparison "
+ "type for selection field %s", field_id);
+ return NULL;
+ }
+
+ /* set up selection */
+ if (!(fs = dm_pool_zalloc(rh->mem, sizeof(struct field_selection)))) {
+ log_error("dm_report: struct field_selection "
+ "allocation failed for selection field %s", field_id);
+ return NULL;
+ }
+ fs->fp = found;
+ fs->flags = flags;
+
+ /* store comparison operand */
+ if (flags & FLD_CMP_REGEX) {
+ /* REGEX */
+ if (!(s = dm_malloc(len + 1))) {
+ log_error("dm_report: dm_malloc failed to store "
+ "regex value for selection field %s", field_id);
+ goto error;
+ }
+ memcpy(s, v, len);
+ s[len] = '\0';
+
+ fs->v.r = dm_regex_create(rh->mem, (const char **) &s, 1);
+ dm_free(s);
+ if (!fs->v.r) {
+ log_error("dm_report: failed to create regex "
+ "matcher for selection field %s", field_id);
+ goto error;
+ }
+ } else {
+ /* STRING, NUMBER or SIZE */
+ if (!(s = dm_pool_alloc(rh->mem, len + 1))) {
+ log_error("dm_report: dm_pool_alloc failed to store "
+ "value for selection field %s", field_id);
+ goto error;
+ }
+ memcpy(s, v, len);
+ s[len] = '\0';
+
+ switch (flags & DM_REPORT_FIELD_TYPE_MASK) {
+ case DM_REPORT_FIELD_TYPE_STRING:
+ fs->v.s = s;
+ break;
+ case DM_REPORT_FIELD_TYPE_NUMBER:
+ if (((fs->v.i = strtoull(s, NULL, 10)) == ULLONG_MAX) &&
+ (errno == ERANGE)) {
+ log_error(_out_of_range_msg, s, field_id);
+ goto error;
+ }
+ dm_pool_free(rh->mem, s);
+ break;
+ case DM_REPORT_FIELD_TYPE_SIZE:
+ fs->v.d = strtod(s, NULL);
+ if (errno == ERANGE) {
+ log_error(_out_of_range_msg, s, field_id);
+ goto error;
+ }
+ if (custom && (factor = *((uint64_t *)custom)))
+ fs->v.d *= factor;
+ fs->v.d /= 512; /* store size in sectors! */
+ dm_pool_free(rh->mem, s);
+ break;
+ default:
+ log_error(INTERNAL_ERROR "_create_field_selection: "
+ "unknown type of selection field %s", field_id);
+ goto error;
+ }
+ }
+
+ return fs;
+error:
+ dm_pool_free(rh->mem, fs);
+ return NULL;
+}
+
+static struct selection_node *_alloc_selection_node(struct dm_pool *mem, uint32_t type)
+{
+ struct selection_node *sn;
+
+ if (!(sn = dm_pool_zalloc(mem, sizeof(struct selection_node)))) {
+ log_error("dm_report: struct selection_node allocation failed");
+ return NULL;
+ }
+
+ dm_list_init(&sn->list);
+ sn->type = type;
+ if (!(type & SEL_ITEM))
+ dm_list_init(&sn->selection.set);
+
+ return sn;
+}
+
+static char _sel_syntax_error_at_msg[] = "Selection syntax error at '%s'.";
+
+/*
+ * Selection parser
+ *
+ * _parse_* functions
+ *
+ * Input:
+ * s - a pointer to the parsed string
+ * Output:
+ * next - a pointer used for next _parse_*'s input,
+ * next == s if return value is NULL
+ * return value - a filter node pointer,
+ * NULL if s doesn't match
+ */
+
+/*
+ * SELECTION := FIELD_NAME OP_CMP STRING |
+ * FIELD_NAME OP_CMP NUMBER |
+ * FIELD_NAME OP_REGEX REGEX
+ */
+static struct selection_node *_parse_selection(struct dm_report *rh,
+ const char *s,
+ const char **next)
+{
+ struct field_selection *fs;
+ struct selection_node *sn;
+ const char *ws, *we; /* field name */
+ const char *vs, *ve; /* value */
+ const char *last;
+ uint32_t flags, field_num;
+ const struct dm_report_field_type *ft;
+ uint64_t factor;
+ void *custom;
+ char *tmp;
+ char c;
+
+ /* field name */
+ if (!(last = _tok_field_name(s, &ws, &we))) {
+ log_error("Expecting field name");
+ goto bad;
+ }
+
+ /* check if the field with given name exists */
+ if (!_get_field(rh, ws, (size_t) (we - ws), &field_num)) {
+ c = we[0];
+ tmp = (char *) we;
+ tmp[0] = '\0';
+ log_error("Unrecognised selection field: %s", ws);
+ tmp[0] = c;
+ goto bad;
+ }
+
+ ft = &rh->fields[field_num];
+
+ /* comparison operator */
+ if (!(flags = _tok_op_cmp(we, &last))) {
+ log_error("Unrecognised comparison operator: %s", we);
+ goto bad;
+ }
+ if (!last) {
+ log_error("Missing value after operator");
+ goto bad;
+ }
+
+ /* some operators can compare only numeric fields */
+ if ((flags & FLD_CMP_NUMBER) &&
+ (ft->flags != DM_REPORT_FIELD_TYPE_NUMBER) &&
+ (ft->flags != DM_REPORT_FIELD_TYPE_SIZE)) {
+ log_error("Operator can be used only with numeric or size fields: %s", ws);
+ goto bad;
+ }
+
+ /* comparison value */
+ if (flags & FLD_CMP_REGEX) {
+ if (!(last = _tok_value_regex(ft, last, &vs, &ve, &flags)))
+ goto_bad;
+ } else {
+ if (ft->flags == DM_REPORT_FIELD_TYPE_SIZE)
+ custom = &factor;
+ else
+ custom = NULL;
+ if (!(last = _tok_value(ft, last, &vs, &ve, &flags, rh->mem, custom)))
+ goto_bad;
+ }
+
+ *next = _skip_space(last);
+
+ /* create selection */
+ if (!(fs = _create_field_selection(rh, field_num, vs, (size_t) (ve - vs), flags, custom)))
+ return_NULL;
+
+ /* create selection node */
+ if (!(sn = _alloc_selection_node(rh->mem, SEL_ITEM)))
+ return_NULL;
+
+ /* add selection to selection node */
+ sn->selection.item = fs;
+
+ return sn;
+bad:
+ log_error(_sel_syntax_error_at_msg, s);
+ *next = s;
+ return NULL;
+}
+
+static struct selection_node *_parse_or_ex(struct dm_report *rh,
+ const char *s,
+ const char **next,
+ struct selection_node *or_sn);
+static struct selection_node *_parse_ex(struct dm_report *rh,
+ const char *s,
+ const char **next)
+{
+ static const char _ps_expected_msg[] = "Syntax error: left parenthesis expected at \'%s\'";
+ static const char _pe_expected_msg[] = "Syntax error: right parenthesis expected at \'%s\'";
+ struct selection_node *sn = NULL;
+ uint32_t t;
+ const char *tmp;
+
+ t = _tok_op_log(s, next, SEL_MODIFIER_NOT | SEL_PRECEDENCE_PS);
+ if (t == SEL_MODIFIER_NOT) {
+ /* '!' '(' EXPRESSION ')' */
+ if (!_tok_op_log(*next, &tmp, SEL_PRECEDENCE_PS)) {
+ log_error(_ps_expected_msg, *next);
+ goto error;
+ }
+ if (!(sn = _parse_or_ex(rh, tmp, next, NULL)))
+ goto error;
+ sn->type |= SEL_MODIFIER_NOT;
+ if (!_tok_op_log(*next, &tmp, SEL_PRECEDENCE_PE)) {
+ log_error(_pe_expected_msg, *next);
+ goto error;
+ }
+ *next = tmp;
+ } else if (t == SEL_PRECEDENCE_PS) {
+ /* '(' EXPRESSION ')' */
+ if (!(sn = _parse_or_ex(rh, *next, &tmp, NULL)))
+ goto error;
+ if (!_tok_op_log(tmp, next, SEL_PRECEDENCE_PE)) {
+ log_error(_pe_expected_msg, *next);
+ goto error;
+ }
+ } else if ((s = _skip_space(s))) {
+ /* SELECTION */
+ sn = _parse_selection(rh, s, next);
+ } else {
+ sn = NULL;
+ *next = s;
+ }
+
+ return sn;
+error:
+ *next = s;
+ return NULL;
+}
+
+/* AND_EXPRESSION := EX (AND_OP AND_EXPRSSION) */
+static struct selection_node *_parse_and_ex(struct dm_report *rh,
+ const char *s,
+ const char **next,
+ struct selection_node *and_sn)
+{
+ struct selection_node *n;
+ const char *tmp;
+
+ n = _parse_ex(rh, s, next);
+ if (!n)
+ goto error;
+
+ if (!_tok_op_log(*next, &tmp, SEL_AND)) {
+ if (!and_sn)
+ return n;
+ dm_list_add(&and_sn->selection.set, &n->list);
+ return and_sn;
+ }
+
+ if (!and_sn) {
+ if (!(and_sn = _alloc_selection_node(rh->mem, SEL_AND)))
+ goto error;
+ }
+ dm_list_add(&and_sn->selection.set, &n->list);
+
+ return _parse_and_ex(rh, tmp, next, and_sn);
+error:
+ *next = s;
+ return NULL;
+}
+
+/* OR_EXPRESSION := AND_EXPRESSION (OR_OP OR_EXPRESSION) */
+static struct selection_node *_parse_or_ex(struct dm_report *rh,
+ const char *s,
+ const char **next,
+ struct selection_node *or_sn)
+{
+ struct selection_node *n;
+ const char *tmp;
+
+ n = _parse_and_ex(rh, s, next, NULL);
+ if (!n)
+ goto error;
+
+ if (!_tok_op_log(*next, &tmp, SEL_OR)) {
+ if (!or_sn)
+ return n;
+ dm_list_add(&or_sn->selection.set, &n->list);
+ return or_sn;
+ }
+
+ if (!or_sn) {
+ if (!(or_sn = _alloc_selection_node(rh->mem, SEL_OR)))
+ goto error;
+ }
+ dm_list_add(&or_sn->selection.set, &n->list);
+
+ return _parse_or_ex(rh, tmp, next, or_sn);
+error:
+ *next = s;
+ return NULL;
+}
+
+struct dm_report *dm_report_init_with_selection(uint32_t *report_types,
+ const struct dm_report_object_type *types,
+ const struct dm_report_field_type *fields,
+ const char *output_fields,
+ const char *output_separator,
+ uint32_t output_flags,
+ const char *sort_keys,
+ const char *selection,
+ void *private_data)
+{
+ struct dm_report *rh;
+ struct selection_node *root = NULL;
+ const char *fin, *next;
+
+ if (!(rh = dm_report_init(report_types, types, fields, output_fields,
+ output_separator, output_flags, sort_keys, private_data)))
+ return NULL;
+
+ if (!selection || !selection[0]) {
+ rh->selection_root = NULL;
+ return rh;
+ }
+
+ if (!(root = _alloc_selection_node(rh->mem, SEL_OR)))
+ return_0;
+
+ if (!_parse_or_ex(rh, selection, &fin, root))
+ goto error;
+
+ next = _skip_space(fin);
+ if (*next) {
+ log_error("Expecting logical operator");
+ log_error(_sel_syntax_error_at_msg, next);
+ goto error;
+ }
+
+ if (report_types)
+ *report_types = rh->report_types;
+
+ rh->selection_root = root;
+ return rh;
+error:
+ dm_report_free(rh);
+ return NULL;
+}
/*
* Print row of headings
8 years, 11 months
master - report: select: add supporting infrastucture for token parsing in report selections
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2c3e84a68d1f99...
Commit: 2c3e84a68d1f991bfe47637017723b7cf0435dff
Parent: 4118dd8da3d2603bafffb024739e5033e9f6543d
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:37:54 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add supporting infrastucture for token parsing in report selections
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html
Add support for parsing numbers, strings (quoted or unquoted), regexes
and operators amogst these operands in selection condition supplied.
---
libdm/libdm-report.c | 281 +++++++++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 279 insertions(+), 2 deletions(-)
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index ae1c701..882bf3e 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -102,8 +102,8 @@ static struct op_def _op_cmp[] = {
{ "!=", FLD_CMP_NOT|FLD_CMP_EQUAL, "Not equal to." },
{ ">=", FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL, "Greater than or equal to." },
{ ">", FLD_CMP_NUMBER|FLD_CMP_GT, "Greater than" },
- { "<=", FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL, "Lesser than or equal to." },
- { "<", FLD_CMP_NUMBER|FLD_CMP_LT, "Lesser than." },
+ { "<=", FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL, "Less than or equal to." },
+ { "<", FLD_CMP_NUMBER|FLD_CMP_LT, "Less than." },
{ NULL, 0, NULL }
};
@@ -854,6 +854,283 @@ int dm_report_object(struct dm_report *rh, void *object)
}
/*
+ * Selection parsing
+ */
+
+/*
+ * Other tokens (FIELD, VALUE, STRING, NUMBER, REGEX)
+ * FIELD := <strings of alphabet, number and '_'>
+ * VALUE := NUMBER | STRING
+ * REGEX := <strings quoted by '"', '\'', '(', '{', '[' or unquoted>
+ * NUMBER := <strings of [0-9]> (because sort_value is unsigned)
+ * STRING := <strings quoted by '"', '\'' or unquoted>
+ */
+
+static const char * _skip_space(const char *s)
+{
+ while (*s && isspace(*s))
+ s++;
+ return s;
+}
+
+static int _tok_op(struct op_def *t, const char *s, const char **end,
+ uint32_t expect)
+{
+ size_t len;
+
+ s = _skip_space(s);
+
+ for (; t->string; t++) {
+ if (expect && !(t->flags & expect))
+ continue;
+
+ len = strlen(t->string);
+ if (!strncmp(s, t->string, len)) {
+ if (end)
+ *end = s + len;
+ return t->flags;
+ }
+ }
+
+ if (end)
+ *end = s;
+ return 0;
+}
+
+static int _tok_op_log(const char *s, const char **end, uint32_t expect)
+{
+ return _tok_op(_op_log, s, end, expect);
+}
+
+static int _tok_op_cmp(const char *s, const char **end)
+{
+ return _tok_op(_op_cmp, s, end, 0);
+}
+
+ /*
+ *
+ * Input:
+ * s - a pointer to the parsed string
+ * Output:
+ * begin - a pointer to the beginning of the token
+ * end - a pointer to the end of the token + 1
+ * or undefined if return value is NULL
+ * return value - a starting point of the next parsing or
+ * NULL if 's' doesn't match with token type
+ * (the parsing should be terminated)
+ */
+static const char *_tok_value_number(const char *s,
+ const char **begin, const char **end)
+
+{
+ int is_float = 0;
+
+ *begin = s;
+ while (*s && ((!is_float && *s=='.' && (is_float=1)) || isdigit(*s)))
+ s++;
+ *end = s;
+
+ if (*begin == *end)
+ return NULL;
+
+ return s;
+}
+
+/*
+ * Input:
+ * s - a pointer to the parsed string
+ * endchar - terminating character
+ * end_op_flags - terminating operator flags (see _op_log)
+ * (if endchar is non-zero then endflags is ignored)
+ * Output:
+ * begin - a pointer to the beginning of the token
+ * end - a pointer to the end of the token + 1
+ * end_op_flag_hit - the flag from endflags hit during parsing
+ * return value - a starting point of the next parsing
+ */
+static const char *_tok_value_string(const char *s,
+ const char **begin, const char **end,
+ const char endchar, uint32_t end_op_flags,
+ uint32_t *end_op_flag_hit)
+{
+ uint32_t flag_hit = 0;
+
+ *begin = s;
+
+ /*
+ * If endchar is defined, scan the string till
+ * the endchar or the end of string is hit.
+ * This is in case the string is quoted and we
+ * know exact character that is the stopper.
+ */
+ if (endchar) {
+ while (*s && *s != endchar)
+ s++;
+ if (*s != endchar) {
+ log_error("Missing end quote.");
+ return NULL;
+ }
+ *end = s;
+ s++;
+ } else {
+ /*
+ * If endchar is not defined then endchar is/are the
+ * operator/s as defined by 'endflags' arg or space char.
+ * This is in case the string is not quoted and
+ * we don't know which character is the exact stopper.
+ */
+ while (*s) {
+ if ((flag_hit = _tok_op(_op_log, s, NULL, end_op_flags)) || *s == ' ')
+ break;
+ s++;
+ }
+ *end = s;
+ /*
+ * If we hit one of the strings as defined by 'endflags'
+ * and if 'endflag_hit' arg is provided, save the exact
+ * string flag that was hit.
+ */
+ if (end_op_flag_hit)
+ *end_op_flag_hit = flag_hit;
+ }
+
+ return s;
+}
+
+/*
+ * Input:
+ * ft - field type for which the value is parsed
+ * s - a pointer to the parsed string
+ * Output:
+ * begin - a pointer to the beginning of the token
+ * end - a pointer to the end of the token + 1
+ * flags - parsing flags
+ */
+static const char *_tok_value_regex(const struct dm_report_field_type *ft,
+ const char *s, const char **begin,
+ const char **end, uint32_t *flags)
+{
+ char c;
+
+ s = _skip_space(s);
+
+ if (!*s) {
+ log_error("Regular expression expected for selection field %s", ft->id);
+ return NULL;
+ }
+
+ switch (*s) {
+ case '(': c = ')'; break;
+ case '{': c = '}'; break;
+ case '[': c = ']'; break;
+ case '"':
+ case '\'': c = *s; break;
+ default: c = 0;
+ }
+
+ if (!(s = _tok_value_string(c ? s + 1 : s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
+ log_error("Failed to parse regex value for selection field %s.", ft->id);
+ return NULL;
+ }
+
+ *flags |= DM_REPORT_FIELD_TYPE_STRING;
+ return s;
+}
+
+/*
+ * Input:
+ * ft - field type for which the value is parsed
+ * s - a pointer to the parsed string
+ * mem - memory pool to allocate from
+ * Output:
+ * begin - a pointer to the beginning of the token
+ * end - a pointer to the end of the token + 1
+ * flags - parsing flags
+ * custom - custom data specific to token type
+ * (e.g. size unit factor)
+ */
+static const char *_tok_value(const struct dm_report_field_type *ft,
+ const char *s, const char **begin,
+ const char **end, uint32_t *flags,
+ struct dm_pool *mem, void *custom)
+{
+ int expected_type = ft->flags & DM_REPORT_FIELD_TYPE_MASK;
+ uint64_t *factor;
+ const char *tmp;
+ char c = 0;
+
+ s = _skip_space(s);
+
+ switch (expected_type) {
+
+ case DM_REPORT_FIELD_TYPE_STRING:
+ if (*s == '"' || *s == '\'') {
+ c = *s;
+ s++;
+ }
+ if (!(s = _tok_value_string(s, begin, end, c, SEL_AND | SEL_OR | SEL_PRECEDENCE_PE, NULL))) {
+ log_error("Failed to parse string value "
+ "for selection field %s.", ft->id);
+ return NULL;
+ }
+ *flags |= DM_REPORT_FIELD_TYPE_STRING;
+ break;
+
+ case DM_REPORT_FIELD_TYPE_NUMBER:
+ case DM_REPORT_FIELD_TYPE_SIZE:
+ if (!(s = _tok_value_number(s, begin, end))) {
+ log_error("Failed to parse numeric value "
+ "for selection field %s.", ft->id);
+ return NULL;
+ }
+ factor = (uint64_t *) custom;
+ *factor = dm_units_to_factor(s, &c, 0, &tmp);
+
+ if (expected_type == DM_REPORT_FIELD_TYPE_NUMBER) {
+ if (*factor) {
+ log_error("Found size unit specifier but "
+ "only numeric value expected for "
+ "selection field %s.",ft->id);
+ return NULL;
+ }
+ *flags |= DM_REPORT_FIELD_TYPE_NUMBER;
+ } else {
+ s = tmp;
+ *flags |= DM_REPORT_FIELD_TYPE_SIZE;
+ }
+ }
+
+ return s;
+}
+
+/*
+ * Input:
+ * s - a pointer to the parsed string
+ * Output:
+ * begin - a pointer to the beginning of the token
+ * end - a pointer to the end of the token + 1
+ */
+static const char *_tok_field_name(const char *s,
+ const char **begin, const char **end)
+{
+ char c;
+ s = _skip_space(s);
+
+ *begin = s;
+ while ((c = *s) &&
+ (isalnum(c) || c == '_' || c == '-'))
+ s++;
+ *end = s;
+
+ if (*begin == *end)
+ return NULL;
+
+ return s;
+}
+
+
+
+/*
* Print row of headings
*/
static int _report_headings(struct dm_report *rh)
8 years, 11 months
master - report: select: add structs for report selection
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4118dd8da3d260...
Commit: 4118dd8da3d2603bafffb024739e5033e9f6543d
Parent: 7dbbc05a69c4cb9756464720cad29e3c1ed971c3
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:37:41 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add structs for report selection
This is rebased and edited version of the original design and
patch proposed by Jun'ichi Nomura:
http://www.redhat.com/archives/dm-devel/2007-April/msg00025.html
This patch defines operators and structures that will be used
to store the report selection against which the actual values
reported will be checked.
Selection operators
-------------------
Comparison operators:
=~ - Matching regular expression.
!~ - Not matching regular expression.
= - Equal to.
!= - Not equal to.
>= - Greater than or equal to.
> - Greater than
<= - Less than or equal to.
< - Less than.
Logical and grouping operators:
&& - All fields must match
, - All fields must match
|| - At least one field must match
# - At least one field must match
! - Logical negation
( - Left parenthesis
) - Right parenthesis
---
libdm/libdm-report.c | 83 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 83 insertions(+), 0 deletions(-)
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index e0c6b1d..ae1c701 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -68,6 +68,89 @@ struct field_properties {
};
/*
+ * Report selection
+ */
+struct op_def {
+ const char *string;
+ uint32_t flags;
+ const char *desc;
+};
+
+#define FLD_CMP_MASK 0x000FF000
+#define FLD_CMP_EQUAL 0x00001000
+#define FLD_CMP_NOT 0x00002000
+#define FLD_CMP_GT 0x00004000
+#define FLD_CMP_LT 0x00008000
+#define FLD_CMP_REGEX 0x00010000
+#define FLD_CMP_NUMBER 0x00020000
+/*
+ * #define FLD_CMP_STRING 0x00040000
+ * We could defined FLD_CMP_STRING here for completeness here,
+ * but it's not needed - we can check operator compatibility with
+ * field type by using FLD_CMP_REGEX and FLD_CMP_NUMBER flags only.
+ */
+
+/*
+ * When defining operators, always define longer one before
+ * shorter one if one is a prefix of another!
+ * (e.g. =~ comes before =)
+*/
+static struct op_def _op_cmp[] = {
+ { "=~", FLD_CMP_REGEX, "Matching regular expression." },
+ { "!~", FLD_CMP_REGEX|FLD_CMP_NOT, "Not matching regular expression." },
+ { "=", FLD_CMP_EQUAL, "Equal to." },
+ { "!=", FLD_CMP_NOT|FLD_CMP_EQUAL, "Not equal to." },
+ { ">=", FLD_CMP_NUMBER|FLD_CMP_GT|FLD_CMP_EQUAL, "Greater than or equal to." },
+ { ">", FLD_CMP_NUMBER|FLD_CMP_GT, "Greater than" },
+ { "<=", FLD_CMP_NUMBER|FLD_CMP_LT|FLD_CMP_EQUAL, "Lesser than or equal to." },
+ { "<", FLD_CMP_NUMBER|FLD_CMP_LT, "Lesser than." },
+ { NULL, 0, NULL }
+};
+
+#define SEL_MASK 0x000000FF
+#define SEL_ITEM 0x00000001
+#define SEL_AND 0x00000002
+#define SEL_OR 0x00000004
+
+#define SEL_MODIFIER_MASK 0x00000F00
+#define SEL_MODIFIER_NOT 0x00000100
+
+#define SEL_PRECEDENCE_MASK 0x0000F000
+#define SEL_PRECEDENCE_PS 0x00001000
+#define SEL_PRECEDENCE_PE 0x00002000
+
+static struct op_def _op_log[] = {
+ { "&&", SEL_AND, "All fields must match" },
+ { ",", SEL_AND, "All fields must match" },
+ { "||", SEL_OR, "At least one field must match" },
+ { "#", SEL_OR, "At least one field must match" },
+ { "!", SEL_MODIFIER_NOT, "Logical negation" },
+ { "(", SEL_PRECEDENCE_PS, "Left parenthesis" },
+ { ")", SEL_PRECEDENCE_PE, "Right parenthesis" },
+ { NULL, 0, NULL},
+};
+
+struct field_selection {
+ struct field_properties *fp;
+ uint32_t flags;
+ union {
+ const char *s;
+ uint64_t i;
+ double d;
+ struct dm_regex *r;
+ } v;
+};
+
+struct selection_node {
+ struct dm_list list;
+ uint32_t type;
+ union {
+ struct field_selection *item;
+ struct dm_list set;
+ } selection;
+};
+
+/*
* Report data field
*/
struct dm_report_field {
8 years, 11 months
master - report: select: add DM_REPORT_FIELD_TYPE_SIZE to make a difference between NUMBER and SIZE
by Peter Rajnoha
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=7dbbc05a69c4cb...
Commit: 7dbbc05a69c4cb9756464720cad29e3c1ed971c3
Parent: 378fa9d1585941a8492830d866377e5f29dff29c
Author: Peter Rajnoha <prajnoha(a)redhat.com>
AuthorDate: Thu May 29 09:37:22 2014 +0200
Committer: Peter Rajnoha <prajnoha(a)redhat.com>
CommitterDate: Tue Jun 17 16:27:20 2014 +0200
report: select: add DM_REPORT_FIELD_TYPE_SIZE to make a difference between NUMBER and SIZE
This makes it easier to check against the fields (following patches for
report selection) and check whether size units are allowed or not
with the field value.
---
lib/properties/prop_common.h | 1 +
lib/report/columns.h | 48 +++++++++++++++++++++---------------------
lib/report/properties.c | 2 +
lib/report/report.c | 2 +
libdm/libdevmapper.h | 1 +
libdm/libdm-report.c | 6 +++-
tools/dmsetup.c | 2 +
7 files changed, 36 insertions(+), 26 deletions(-)
diff --git a/lib/properties/prop_common.h b/lib/properties/prop_common.h
index 6c89ad6..d6a0bb7 100644
--- a/lib/properties/prop_common.h
+++ b/lib/properties/prop_common.h
@@ -122,6 +122,7 @@ static int _ ## NAME ## _get (const void *obj, struct lvm_property_type *prop) \
#define STR 1
#define NUM 2
+#define SIZ 3
#define FIELD_MODIFIABLE 0x00000001
#define FIELD(type, strct, field_type, head, field, width, fn, id, desc, settable) \
diff --git a/lib/report/columns.h b/lib/report/columns.h
index 7c36d10..8328321 100644
--- a/lib/report/columns.h
+++ b/lib/report/columns.h
@@ -35,15 +35,15 @@ FIELD(LVS, lv, STR, "Attr", lvid, 4, lvstatus, lv_attr, "Various attributes - se
FIELD(LVS, lv, STR, "Active", lvid, 6, lvactive, lv_active, "Active state of the LV.", 0)
FIELD(LVS, lv, NUM, "Maj", major, 3, int32, lv_major, "Persistent major number or -1 if not persistent.", 0)
FIELD(LVS, lv, NUM, "Min", minor, 3, int32, lv_minor, "Persistent minor number or -1 if not persistent.", 0)
-FIELD(LVS, lv, NUM, "Rahead", lvid, 6, lvreadahead, lv_read_ahead, "Read ahead setting in current units.", 0)
+FIELD(LVS, lv, SIZ, "Rahead", lvid, 6, lvreadahead, lv_read_ahead, "Read ahead setting in current units.", 0)
FIELD(LVS, lv, NUM, "KMaj", lvid, 4, lvkmaj, lv_kernel_major, "Currently assigned major number or -1 if LV is not active.", 0)
FIELD(LVS, lv, NUM, "KMin", lvid, 4, lvkmin, lv_kernel_minor, "Currently assigned minor number or -1 if LV is not active.", 0)
-FIELD(LVS, lv, NUM, "KRahead", lvid, 7, lvkreadahead, lv_kernel_read_ahead, "Currently-in-use read ahead setting in current units.", 0)
-FIELD(LVS, lv, NUM, "LSize", size, 5, size64, lv_size, "Size of LV in current units.", 0)
-FIELD(LVS, lv, NUM, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thin pools, the size of the LV that holds the metadata.", 0)
+FIELD(LVS, lv, SIZ, "KRahead", lvid, 7, lvkreadahead, lv_kernel_read_ahead, "Currently-in-use read ahead setting in current units.", 0)
+FIELD(LVS, lv, SIZ, "LSize", size, 5, size64, lv_size, "Size of LV in current units.", 0)
+FIELD(LVS, lv, SIZ, "MSize", lvid, 6, lvmetadatasize, lv_metadata_size, "For thin pools, the size of the LV that holds the metadata.", 0)
FIELD(LVS, lv, NUM, "#Seg", lvid, 4, lvsegcount, seg_count, "Number of segments in LV.", 0)
FIELD(LVS, lv, STR, "Origin", lvid, 6, origin, origin, "For snapshots, the origin device of this LV.", 0)
-FIELD(LVS, lv, NUM, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0)
+FIELD(LVS, lv, SIZ, "OSize", lvid, 5, originsize, origin_size, "For snapshots, the size of the origin device of this LV.", 0)
FIELD(LVS, lv, NUM, "Data%", lvid, 6, datapercent, data_percent, "For snapshot and thin pools and volumes, the percentage full if LV is active.", 0)
FIELD(LVS, lv, NUM, "Snap%", lvid, 6, snpercent, snap_percent, "For snapshots, the percentage full if LV is active.", 0)
FIELD(LVS, lv, NUM, "Meta%", lvid, 6, metadatapercent, metadata_percent, "For thin pools, the percentage of metadata full if LV is active.", 0)
@@ -68,15 +68,15 @@ FIELD(LVS, lv, STR, "Modules", lvid, 7, modules, lv_modules, "Kernel device-mapp
FIELD(LABEL, label, STR, "Fmt", type, 3, pvfmt, pv_fmt, "Type of metadata.", 0)
FIELD(LABEL, label, STR, "PV UUID", type, 38, pvuuid, pv_uuid, "Unique identifier.", 0)
-FIELD(LABEL, label, NUM, "DevSize", dev, 7, devsize, dev_size, "Size of underlying device in current units.", 0)
+FIELD(LABEL, label, SIZ, "DevSize", dev, 7, devsize, dev_size, "Size of underlying device in current units.", 0)
FIELD(LABEL, label, STR, "PV", dev, 10, dev_name, pv_name, "Name.", 0)
-FIELD(LABEL, label, NUM, "PMdaFree", type, 9, pvmdafree, pv_mda_free, "Free metadata area space on this device in current units.", 0)
-FIELD(LABEL, label, NUM, "PMdaSize", type, 9, pvmdasize, pv_mda_size, "Size of smallest metadata area on this device in current units.", 0)
+FIELD(LABEL, label, SIZ, "PMdaFree", type, 9, pvmdafree, pv_mda_free, "Free metadata area space on this device in current units.", 0)
+FIELD(LABEL, label, SIZ, "PMdaSize", type, 9, pvmdasize, pv_mda_size, "Size of smallest metadata area on this device in current units.", 0)
FIELD(PVS, pv, NUM, "1st PE", pe_start, 7, size64, pe_start, "Offset to the start of data on the underlying device.", 0)
-FIELD(PVS, pv, NUM, "PSize", id, 5, pvsize, pv_size, "Size of PV in current units.", 0)
-FIELD(PVS, pv, NUM, "PFree", id, 5, pvfree, pv_free, "Total amount of unallocated space in current units.", 0)
-FIELD(PVS, pv, NUM, "Used", id, 4, pvused, pv_used, "Total amount of allocated space in current units.", 0)
+FIELD(PVS, pv, SIZ, "PSize", id, 5, pvsize, pv_size, "Size of PV in current units.", 0)
+FIELD(PVS, pv, SIZ, "PFree", id, 5, pvfree, pv_free, "Total amount of unallocated space in current units.", 0)
+FIELD(PVS, pv, SIZ, "Used", id, 4, pvused, pv_used, "Total amount of allocated space in current units.", 0)
FIELD(PVS, pv, STR, "Attr", id, 4, pvstatus, pv_attr, "Various attributes - see man page.", 0)
FIELD(PVS, pv, NUM, "PE", pe_count, 3, uint32, pv_pe_count, "Total number of Physical Extents.", 0)
FIELD(PVS, pv, NUM, "Alloc", pe_alloc_count, 5, uint32, pv_pe_alloc_count, "Total number of allocated Physical Extents.", 0)
@@ -84,16 +84,16 @@ FIELD(PVS, pv, STR, "PV Tags", tags, 7, tags, pv_tags, "Tags, if any.", 0)
FIELD(PVS, pv, NUM, "#PMda", id, 5, pvmdas, pv_mda_count, "Number of metadata areas on this device.", 0)
FIELD(PVS, pv, NUM, "#PMdaUse", id, 8, pvmdasused, pv_mda_used_count, "Number of metadata areas in use on this device.", 0)
FIELD(PVS, pv, NUM, "BA start", ba_start, 8, size64, pv_ba_start, "Offset to the start of PV Bootloader Area on the underlying device in current units.", 0)
-FIELD(PVS, pv, NUM, "BA size", ba_size, 7, size64, pv_ba_size, "Size of PV Bootloader Area in current units.", 0)
+FIELD(PVS, pv, SIZ, "BA size", ba_size, 7, size64, pv_ba_size, "Size of PV Bootloader Area in current units.", 0)
FIELD(VGS, vg, STR, "Fmt", cmd, 3, vgfmt, vg_fmt, "Type of metadata.", 0)
FIELD(VGS, vg, STR, "VG UUID", id, 38, uuid, vg_uuid, "Unique identifier.", 0)
FIELD(VGS, vg, STR, "VG", name, 4, string, vg_name, "Name.", 0)
FIELD(VGS, vg, STR, "Attr", cmd, 5, vgstatus, vg_attr, "Various attributes - see man page.", 0)
-FIELD(VGS, vg, NUM, "VSize", cmd, 5, vgsize, vg_size, "Total size of VG in current units.", 0)
+FIELD(VGS, vg, SIZ, "VSize", cmd, 5, vgsize, vg_size, "Total size of VG in current units.", 0)
FIELD(VGS, vg, NUM, "VFree", cmd, 5, vgfree, vg_free, "Total amount of free space in current units.", 0)
FIELD(VGS, vg, STR, "SYS ID", system_id, 6, string, vg_sysid, "System ID indicating when and where it was created.", 0)
-FIELD(VGS, vg, NUM, "Ext", extent_size, 3, size32, vg_extent_size, "Size of Physical Extents in current units.", 0)
+FIELD(VGS, vg, SIZ, "Ext", extent_size, 3, size32, vg_extent_size, "Size of Physical Extents in current units.", 0)
FIELD(VGS, vg, NUM, "#Ext", extent_count, 4, uint32, vg_extent_count, "Total number of Physical Extents.", 0)
FIELD(VGS, vg, NUM, "Free", free_count, 4, uint32, vg_free_count, "Total number of unallocated Physical Extents.", 0)
FIELD(VGS, vg, NUM, "MaxLV", max_lv, 5, uint32, max_lv, "Maximum number of LVs allowed in VG or 0 if unlimited.", 0)
@@ -106,18 +106,18 @@ FIELD(VGS, vg, STR, "VG Tags", tags, 7, tags, vg_tags, "Tags, if any.", 0)
FIELD(VGS, vg, STR, "VProfile", cmd, 8, vgprofile, vg_profile, "Configuration profile attached to this VG.", 0)
FIELD(VGS, vg, NUM, "#VMda", cmd, 5, vgmdas, vg_mda_count, "Number of metadata areas on this VG.", 0)
FIELD(VGS, vg, NUM, "#VMdaUse", cmd, 8, vgmdasused, vg_mda_used_count, "Number of metadata areas in use on this VG.", 0)
-FIELD(VGS, vg, NUM, "VMdaFree", cmd, 9, vgmdafree, vg_mda_free, "Free metadata area space for this VG in current units.", 0)
-FIELD(VGS, vg, NUM, "VMdaSize", cmd, 9, vgmdasize, vg_mda_size, "Size of smallest metadata area for this VG in current units.", 0)
+FIELD(VGS, vg, SIZ, "VMdaFree", cmd, 9, vgmdafree, vg_mda_free, "Free metadata area space for this VG in current units.", 0)
+FIELD(VGS, vg, SIZ, "VMdaSize", cmd, 9, vgmdasize, vg_mda_size, "Size of smallest metadata area for this VG in current units.", 0)
FIELD(VGS, vg, NUM, "#VMdaCps", cmd, 8, vgmdacopies, vg_mda_copies, "Target number of in use metadata areas in the VG.", 1)
FIELD(SEGS, seg, STR, "Type", list, 4, segtype, segtype, "Type of LV segment.", 0)
FIELD(SEGS, seg, NUM, "#Str", area_count, 4, uint32, stripes, "Number of stripes or mirror legs.", 0)
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, stripesize, "For stripes, amount of data placed on one device before switching to the next.", 0)
-FIELD(SEGS, seg, NUM, "Stripe", stripe_size, 6, size32, stripe_size, "For stripes, amount of data placed on one device before switching to the next.", 0)
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, regionsize, "For mirrors, the unit of data copied when synchronising devices.", 0)
-FIELD(SEGS, seg, NUM, "Region", region_size, 6, size32, region_size, "For mirrors, the unit of data copied when synchronising devices.", 0)
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunksize, "For snapshots, the unit of data used when tracking changes.", 0)
-FIELD(SEGS, seg, NUM, "Chunk", list, 5, chunksize, chunk_size, "For snapshots, the unit of data used when tracking changes.", 0)
+FIELD(SEGS, seg, SIZ, "Stripe", stripe_size, 6, size32, stripesize, "For stripes, amount of data placed on one device before switching to the next.", 0)
+FIELD(SEGS, seg, SIZ, "Stripe", stripe_size, 6, size32, stripe_size, "For stripes, amount of data placed on one device before switching to the next.", 0)
+FIELD(SEGS, seg, SIZ, "Region", region_size, 6, size32, regionsize, "For mirrors, the unit of data copied when synchronising devices.", 0)
+FIELD(SEGS, seg, SIZ, "Region", region_size, 6, size32, region_size, "For mirrors, the unit of data copied when synchronising devices.", 0)
+FIELD(SEGS, seg, SIZ, "Chunk", list, 5, chunksize, chunksize, "For snapshots, the unit of data used when tracking changes.", 0)
+FIELD(SEGS, seg, SIZ, "Chunk", list, 5, chunksize, chunk_size, "For snapshots, the unit of data used when tracking changes.", 0)
FIELD(SEGS, seg, NUM, "#Thins", list, 4, thincount, thin_count, "For thin pools, the number of thin volumes in this pool.", 0)
FIELD(SEGS, seg, STR, "Discards", list, 8, discards, discards, "For thin pools, how discards are handled.", 0)
FIELD(SEGS, seg, NUM, "Zero", list, 4, thinzero, zero, "For thin pools, if zeroing is enabled.", 0)
@@ -125,8 +125,8 @@ FIELD(SEGS, seg, NUM, "TransId", list, 4, transactionid, transaction_id, "For th
FIELD(SEGS, seg, NUM, "ThId", list, 4, thinid, thin_id, "For thin volume, the thin device id.", 0)
FIELD(SEGS, seg, NUM, "Start", list, 5, segstart, seg_start, "Offset within the LV to the start of the segment in current units.", 0)
FIELD(SEGS, seg, NUM, "Start", list, 5, segstartpe, seg_start_pe, "Offset within the LV to the start of the segment in physical extents.", 0)
-FIELD(SEGS, seg, NUM, "SSize", list, 5, segsize, seg_size, "Size of segment in current units.", 0)
-FIELD(SEGS, seg, NUM, "SSize", list, 5, segsizepe, seg_size_pe, "Size of segment in physical extents.", 0)
+FIELD(SEGS, seg, SIZ, "SSize", list, 5, segsize, seg_size, "Size of segment in current units.", 0)
+FIELD(SEGS, seg, SIZ, "SSize", list, 5, segsizepe, seg_size_pe, "Size of segment in physical extents.", 0)
FIELD(SEGS, seg, STR, "Seg Tags", tags, 8, tags, seg_tags, "Tags, if any.", 0)
FIELD(SEGS, seg, STR, "PE Ranges", list, 9, peranges, seg_pe_ranges, "Ranges of Physical Extents of underlying devices in command line format.", 0)
FIELD(SEGS, seg, STR, "Devices", list, 7, devices, devices, "Underlying devices used with starting extent numbers.", 0)
diff --git a/lib/report/properties.c b/lib/report/properties.c
index c6ccb72..876a408 100644
--- a/lib/report/properties.c
+++ b/lib/report/properties.c
@@ -334,6 +334,7 @@ GET_PVSEG_NUM_PROPERTY_FN(pvseg_start, pvseg->pe)
GET_PVSEG_NUM_PROPERTY_FN(pvseg_size, (SECTOR_SIZE * pvseg->len))
#define _pvseg_size_set prop_not_implemented_set
+
struct lvm_property_type _properties[] = {
#include "columns.h"
{ 0, "", 0, 0, 0, { .integer = 0 }, prop_not_implemented_get, prop_not_implemented_set },
@@ -341,6 +342,7 @@ struct lvm_property_type _properties[] = {
#undef STR
#undef NUM
+#undef SIZ
#undef FIELD
int lvseg_get_property(const struct lv_segment *lvseg,
diff --git a/lib/report/report.c b/lib/report/report.c
index 6b32bee..2f340ed 100644
--- a/lib/report/report.c
+++ b/lib/report/report.c
@@ -1202,6 +1202,7 @@ static const struct dm_report_object_type _devtypes_report_types[] = {
#define STR DM_REPORT_FIELD_TYPE_STRING
#define NUM DM_REPORT_FIELD_TYPE_NUMBER
+#define SIZ DM_REPORT_FIELD_TYPE_SIZE
#define FIELD(type, strct, sorttype, head, field, width, func, id, desc, writeable) \
{type, sorttype, offsetof(type_ ## strct, field), width, \
#id, head, &_ ## func ## _disp, desc},
@@ -1227,6 +1228,7 @@ static const struct dm_report_field_type _devtypes_fields[] = {
#undef STR
#undef NUM
+#undef SIZ
#undef FIELD
void *report_init(struct cmd_context *cmd, const char *format, const char *keys,
diff --git a/libdm/libdevmapper.h b/libdm/libdevmapper.h
index 386ef07..3a51e14 100644
--- a/libdm/libdevmapper.h
+++ b/libdm/libdevmapper.h
@@ -1597,6 +1597,7 @@ struct dm_report_field;
#define DM_REPORT_FIELD_TYPE_MASK 0x000000F0
#define DM_REPORT_FIELD_TYPE_STRING 0x00000010
#define DM_REPORT_FIELD_TYPE_NUMBER 0x00000020
+#define DM_REPORT_FIELD_TYPE_SIZE 0x00000040
#define DM_REPORT_FIELD_TYPE_ID_LEN 32
#define DM_REPORT_FIELD_TYPE_HEADING_LEN 32
diff --git a/libdm/libdm-report.c b/libdm/libdm-report.c
index bdc293b..e0c6b1d 100644
--- a/libdm/libdm-report.c
+++ b/libdm/libdm-report.c
@@ -862,7 +862,8 @@ static int _row_compare(const void *a, const void *b)
for (cnt = 0; cnt < rowa->rh->keys_count; cnt++) {
sfa = (*rowa->sort_fields)[cnt];
sfb = (*rowb->sort_fields)[cnt];
- if (sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) {
+ if ((sfa->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
+ (sfa->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) {
const uint64_t numa =
*(const uint64_t *) sfa->sort_value;
const uint64_t numb =
@@ -972,7 +973,8 @@ static int _output_field(struct dm_report *rh, struct dm_report_field *field)
}
} else {
if (!(align = field->props->flags & DM_REPORT_FIELD_ALIGN_MASK))
- align = (field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ?
+ align = ((field->props->flags & DM_REPORT_FIELD_TYPE_NUMBER) ||
+ (field->props->flags & DM_REPORT_FIELD_TYPE_SIZE)) ?
DM_REPORT_FIELD_ALIGN_RIGHT : DM_REPORT_FIELD_ALIGN_LEFT;
/* Including trailing '\0'! */
diff --git a/tools/dmsetup.c b/tools/dmsetup.c
index f84d1a8..fd87d42 100644
--- a/tools/dmsetup.c
+++ b/tools/dmsetup.c
@@ -2786,6 +2786,7 @@ static const struct dm_report_object_type _report_types[] = {
#define OFFSET_OF(strct, field) (((char*)&((struct strct*)0)->field) - (char*)0)
#define STR (DM_REPORT_FIELD_TYPE_STRING)
#define NUM (DM_REPORT_FIELD_TYPE_NUMBER)
+#define SIZ (DM_REPORT_FIELD_TYPE_SIZE)
#define FIELD_O(type, strct, sorttype, head, field, width, func, id, desc) {DR_ ## type, sorttype, OFFSET_OF(strct, field), width, id, head, &_ ## func ## _disp, desc},
#define FIELD_F(type, sorttype, head, width, func, id, desc) {DR_ ## type, sorttype, 0, width, id, head, &_ ## func ## _disp, desc},
@@ -2833,6 +2834,7 @@ FIELD_O(NAME, dm_split_name, STR, "LVLayer", lv_layer, 7, dm_lv_layer_name, "lv_
#undef STR
#undef NUM
+#undef SIZ
#undef FIELD_O
#undef FIELD_F
8 years, 11 months
master - tests: check new snapshot skills
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=378fa9d1585941...
Commit: 378fa9d1585941a8492830d866377e5f29dff29c
Parent: 8403bbd4adabb6718f45f67e5a4a98f6de26dbb6
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Tue Jun 17 13:35:40 2014 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Tue Jun 17 13:43:05 2014 +0200
tests: check new snapshot skills
---
test/shell/snapshot-merge.sh | 2 +-
test/shell/snapshot-usage.sh | 42 ++++++++++++++++++++++++++++++++++++++----
2 files changed, 39 insertions(+), 5 deletions(-)
diff --git a/test/shell/snapshot-merge.sh b/test/shell/snapshot-merge.sh
index bebc9de..0117cdc 100644
--- a/test/shell/snapshot-merge.sh
+++ b/test/shell/snapshot-merge.sh
@@ -33,7 +33,7 @@ setup_merge_() {
if [ $NUM_EXTRA_SNAPS -gt 0 ]; then
for i in $(seq 1 $NUM_EXTRA_SNAPS); do
- lvcreate -s -n ${BASE_SNAP_LV_NAME}_${i} -l 20%FREE ${VG_NAME}/${LV_NAME}
+ lvcreate -s -n ${BASE_SNAP_LV_NAME}_${i} -l 20%ORIGIN ${VG_NAME}/${LV_NAME}
done
fi
}
diff --git a/test/shell/snapshot-usage.sh b/test/shell/snapshot-usage.sh
index 3fc40e3..c0a14c6 100644
--- a/test/shell/snapshot-usage.sh
+++ b/test/shell/snapshot-usage.sh
@@ -17,7 +17,8 @@ MKFS=mkfs.ext2
which $MKFS || skip
fill() {
- dd if=/dev/zero of="$DM_DEV_DIR/$vg1/lvol0" bs=$1 count=1
+ dd if=/dev/zero of="$DM_DEV_DIR/${2:-$vg1/lvol0}" bs=$1 count=1 oflag=direct || \
+ die "Snapshot does not fit $1"
}
# Wait until device is opened
@@ -39,9 +40,6 @@ cleanup_tail()
aux teardown
}
-aux prepare_pvs 1
-vgcreate -s 4M $vg $(cat DEVICES)
-
TSIZE=15P
aux can_use_16T || TSIZE=15T
@@ -64,6 +62,21 @@ if aux target_at_least dm-snapshot 1 10 0 ; then
fi
fi
+aux prepare_pvs 1
+vgcreate -s 4M $vg $(cat DEVICES)
+
+# Play with 1 extent
+lvcreate -aey -l1 -n $lv $vg
+# 100%LV is not supported for snapshot
+fail lvcreate -s -l 100%LV -n snap $vg/$lv |& tee out
+grep 'Please express size as %ORIGIN, %VG, %PVS, or %FREE' out
+# 100%ORIGIN needs to have enough space for all data and needs to round-up
+lvcreate -s -l 100%ORIGIN -n $lv1 $vg/$lv
+# everything needs to fit
+fill 4M $vg/$lv1
+lvremove -f $vg
+
+
# Automatically activates exclusively in cluster
lvcreate -s -l 100%FREE -n $lv $vg --virtualsize $TSIZE
@@ -76,6 +89,27 @@ pvcreate --setphysicalvolumesize 4T "$DM_DEV_DIR/$vg/$lv"
trap 'cleanup_tail' EXIT
vgcreate -s 1K $vg1 "$DM_DEV_DIR/$vg/$lv"
+
+# Play with small 1k 128 extents
+lvcreate -aey -L128K -n $lv $vg1
+# 100%ORIGIN needs to have enough space for all data
+lvcreate -s -l 100%ORIGIN -n snap100 $vg1/$lv
+# everything needs to fit
+fill 128k $vg1/snap100
+
+# 50%ORIGIN needs to have enough space for 50% of data
+lvcreate -s -l 50%ORIGIN -n snap50 $vg1/$lv
+fill 64k $vg1/snap50
+
+lvcreate -s -l 25%ORIGIN -n snap25 $vg1/$lv
+fill 32k $vg1/snap25
+
+# Check we do not provide too much extra space
+not fill 33k $vg1/snap25
+
+lvs -a $vg1
+lvremove -f $vg1
+
# Test virtual snapshot over /dev/zero
lvcreate -V50 -L10 -n $lv1 -s $vg1
CHECK_ACTIVE="active"
8 years, 11 months