Skip to contentSkip to conversation

libdevmapper: (0/6) Filtering feature in dm_report

PATCH New Jun'ichi Nomura 1 participant 10 messages Apr 18, 2007

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 libdevmapper: (0/6) Filtering feature in dm_report

Hi,

This series of patches enables dmsetup to control which types of devices are listed.
For example, "dmsetup info -c -o name --filter 'parents_count == 0'" will display top-level dm devices and
"dmsetup info -c --filter 'uuid !~ /^LVM/'" will display dm devices which are not LVM2 volumes.

As the feature is implemented in libdevmapper, LVM2 is easily made to use it, too. The patch will be posted to lvm-devel.

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America
#1 lore raw

PATCH 1/1 libdevmapper: (1/6) Tidy up _field_match() and _key_match()

Hi,

This patch cleans up _field_match() and _key_match() by separating common operations out.

No effect on functionality.

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

Tidy up _field_match() and _key_match()

* Add _add_field() function for flag setting, alloc, copy, and list_add of struct field_properties
* Add _is_same_field() for lengthy test to check field name abbreviation

---
 lib/libdm-report.c |  101 +++++++++++++++++++++++++++++------------------------
 1 file changed, 56 insertions(+), 45 deletions(-)
lib/libdm-report.c +56 -45
Index: device-mapper.work/lib/libdm-report.c
===================================================================
@@ -296,35 +296,62 @@ static int _copy_field(struct dm_report 
 	return 1;
 }
 
-static int _field_match(struct dm_report *rh, const char *field, size_t flen)
+static struct field_properties * _add_field(struct dm_report *rh,
+					    uint32_t field_num, uint32_t flags)
 {
-	uint32_t f, l;
 	struct field_properties *fp;
 
+	rh->report_types |= rh->fields[field_num].type;
+	if (!(fp = dm_pool_zalloc(rh->mem, sizeof(struct field_properties)))) {
+		log_error("dm_report: "
+			  "struct field_properties allocation failed");
+		return NULL;
+	}
+	if (!_copy_field(rh, fp, field_num)) {
+		dm_pool_free(rh->mem, fp);
+		return NULL;
+	}
+
+	/* Add additional flags */
+	fp->flags |= flags;
+
+	list_add(&rh->field_props, &fp->list);
+	return fp;
+}
+
+/*
+ * compare name1 and name2 (or prefix+name2)
+ *   name2 is not \0 terminated. len is the length of name2.
+ */
+static int _is_same_field(const char *name1, const char *name2,
+                         size_t len, const char *prefix)
+{
+	size_t l;
+
+	/* name1 == name2 */
+	if (!strncasecmp(name1, name2, len) && strlen(name1) == len)
+		return 1;
+
+	/* name1 == name2 */
+	l = strlen(prefix);
+	if (!strncasecmp(prefix, name1, l) &&
+	    !strncasecmp(name1 + l, name2, len) && strlen(name1) == l + len)
+		return 1;
+
+	return 0;
+}
+
+static int _field_match(struct dm_report *rh, const char *field, size_t flen)
+{
+	uint32_t f;
+
 	if (!flen)
 		return 0;
 
-	for (f = 0; rh->fields[f].report_fn; f++) {
-		if ((!strncasecmp(rh->fields[f].id, field, flen) &&
-		     strlen(rh->fields[f].id) == flen) ||
-		    (l = strlen(rh->field_prefix),
-		     !strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
-		     !strncasecmp(rh->fields[f].id + l, field, flen) &&
-		     strlen(rh->fields[f].id) == l + flen)) {
-			rh->report_types |= rh->fields[f].type;
-			if (!(fp = dm_pool_zalloc(rh->mem, sizeof(*fp)))) {
-				log_error("dm_report: "
-					  "struct field_properties allocation "
-					  "failed");
-				return 0;
-			}
-			if (!_copy_field(rh, fp, f))
-				return 0;
-
-			list_add(&rh->field_props, &fp->list);
-			return 1;
-		}
-	}
+	for (f = 0; rh->fields[f].report_fn; f++)
+		if (_is_same_field(rh->fields[f].id,
+				   field, flen, rh->field_prefix))
+			return (_add_field(rh, f, 0) != NULL);
 
 	return 0;
 }
@@ -342,19 +369,9 @@ static int _add_sort_key(struct dm_repor
 	}
 
 	if (!found) {
-		rh->report_types |= rh->fields[field_num].type;
-		if (!(found = dm_pool_zalloc(rh->mem, sizeof(*found)))) {
-			log_error("dm_report: "
-				  "struct field_properties allocation failed");
-			return 0;
-		}
-		if (!_copy_field(rh, found, field_num))
-			return 0;
-
 		/* Add as a non-display field */
-		found->flags |= FLD_HIDDEN;
-
-		list_add(&rh->field_props, &found->list);
+		if (!(found = _add_field(rh, field_num, FLD_HIDDEN)))
+			return 0;
 	}
 
 	if (found->flags & FLD_SORT_KEY) {
@@ -372,7 +389,7 @@ static int _add_sort_key(struct dm_repor
 
 static int _key_match(struct dm_report *rh, const char *key, size_t len)
 {
-	uint32_t f, l;
+	uint32_t f;
 	uint32_t flags;
 
 	if (!len)
@@ -394,16 +411,10 @@ static int _key_match(struct dm_report *
 		return 0;
 	}
 
-	for (f = 0; rh->fields[f].report_fn; f++) {
-		if ((!strncasecmp(rh->fields[f].id, key, len) &&
-		     strlen(rh->fields[f].id) == len) ||
-		    (l = strlen(rh->field_prefix),
-		     !strncasecmp(rh->field_prefix, rh->fields[f].id, l) &&
-		     !strncasecmp(rh->fields[f].id + l, key, len) &&
-		     strlen(rh->fields[f].id) == l + len)) {
+	for (f = 0; rh->fields[f].report_fn; f++)
+		if (_is_same_field(rh->fields[f].id,
+				   key, len, rh->field_prefix))
 			return _add_sort_key(rh, f, flags);
-		}
-	}
 
 	return 0;
 }
#2 lore raw

PATCH 1/1 libdevmapper: (2/6) Fix trailing separator

In reply to Jun'ichi Nomura

Hi,

This patch fixes dm_report_output() so that it can correctly check the end of the row.

It uses list_end() but trailing fields may have HIDDEN flag and not be printed.

For example,

# dmsetup info -c -o name -O minor VG0-lv0
Name
VG0-lv0
# dmsetup info -c -o name -O minor --noheadings VG0-lv0
VG0-lv0:
# dmsetup info -c -o name --noheadings VG0-lv0
VG0-lv0

The patch fixes it by inserting hidden fields at the head of the list.

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

Later, dm_report_output() loops through rh->field_props list and checks the end of the list by list_end() whether to display the separator or not.
The check doesn't work if hidden field is on the tail.

For example, try 'dmsetup info -c -o name -O minor' and compare the results with and without '--noheadings'.

---
 lib/libdm-report.c |    7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
lib/libdm-report.c +6 -1
Index: device-mapper.work/lib/libdm-report.c
===================================================================
@@ -315,7 +315,12 @@ static struct field_properties * _add_fi
 	/* Add additional flags */
 	fp->flags |= flags;
 
-	list_add(&rh->field_props, &fp->list);
+	/* Hidden field must come first, otherwise list_end() doesn't work
+	   as expected */
+	if (fp->flags & FLD_HIDDEN)
+		list_add_h(&rh->field_props, &fp->list);
+	else
+		list_add(&rh->field_props, &fp->list);
 	return fp;
 }
 
#3 lore raw

PATCH 1/1 libdevmapper: (3/6) Move lib/regex from LVM2

In reply to Jun'ichi Nomura

Hi,

This patch just moves lib/regex from LVM2 as a preparation for the filtering feature of dm_report.

Now, the following functions are exported:
- dm_regex_create()
- dm_regex_match()

Corresponding patch to LVM2 will be posted to lvm-devel.

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

Moved lib/regex from LVM2

Exported functions and a structure are renamed:
- matcher_create() -> dm_regex_create()
- matcher_run() -> dm_regex_match()
- struct matcher -> struct dm_regex

---
 lib/.exported_symbols |    2 
 lib/Makefile.in       |    3 
 lib/libdevmapper.h    |    7 
 lib/regex/matcher.c   |  366 ++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/regex/parse_rx.c  |  360 +++++++++++++++++++++++++++++++++++++++++++++++++
 lib/regex/parse_rx.h  |   52 +++++++
 lib/regex/ttree.c     |  117 +++++++++++++++
 lib/regex/ttree.h     |   26 +++
 8 files changed, 933 insertions(+)
lib/.exported_symbols +2 -0
Index: device-mapper.work/lib/.exported_symbols
===================================================================
@@ -127,3 +127,5 @@ dm_report_field_int32
 dm_report_field_uint32
 dm_report_field_uint64
 dm_report_field_set_value
+dm_regex_create
+dm_regex_match
lib/libdevmapper.h +7 -0
Index: device-mapper.work/lib/libdevmapper.h
===================================================================
@@ -711,4 +711,11 @@ int dm_report_field_uint64(struct dm_rep
 void dm_report_field_set_value(struct dm_report_field *field, const void *value,
 			       const void *sortvalue);
 
+/*
+ * dm_regex
+ */
+struct dm_regex;
+struct dm_regex *dm_regex_create(struct dm_pool *mem, const char **patterns,
+				 unsigned num);
+int dm_regex_match(struct dm_regex *regex, const char *s);
 #endif				/* LIB_DEVICE_MAPPER_H */
lib/regex/matcher.c new file +366 -0

366 lines not on this page · raw message

lib/regex/parse_rx.c new file +360 -0

360 lines not on this page · raw message

lib/regex/parse_rx.h new file +52 -0

52 lines not on this page · raw message

lib/regex/ttree.c new file +117 -0

117 lines not on this page · raw message

lib/regex/ttree.h new file +26 -0
Index: device-mapper.work/lib/regex/ttree.h
===================================================================
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
+ * Copyright (C) 2004 Red Hat, Inc. All rights reserved.
+ *
+ * This file is part of the device-mapper userspace tools.
+ *
+ * This copyrighted material is made available to anyone wishing to use,
+ * modify, copy, or redistribute it subject to the terms and conditions
+ * of the GNU General Public License v.2.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _LVM_TTREE_H
+#define _LVM_TTREE_H
+
+struct ttree;
+
+struct ttree *ttree_create(struct dm_pool *mem, unsigned int klen);
+
+void *ttree_lookup(struct ttree *tt, unsigned *key);
+int ttree_insert(struct ttree *tt, unsigned *key, void *data);
+
+#endif
lib/Makefile.in +3 -0
Index: device-mapper.work/lib/Makefile.in
===================================================================
@@ -25,6 +25,9 @@ SOURCES =\
 	libdm-deptree.c \
 	libdm-string.c \
 	libdm-report.c \
+	regex/matcher.c \
+	regex/parse_rx.c \
+	regex/ttree.c \
 	mm/dbg_malloc.c \
 	mm/pool.c \
 	$(interface)/libdm-iface.c
#4 lore raw

PATCH 1/1 LVM2: (1/2) Use dm_regex

Hi,

This patch removes lib/regex from LVM2 and uses dm_regex, instead.

Corresponding patch for libdevmapper is this:
[PATCH] libdevmapper: (3/6) Move lib/regex from LVM2
https://www.redhat.com/archives/dm-devel/2007-April/msg00028.html

No change in functionality.

Thanks,

Signature · 8 lines
Jun'ichi Nomura, NEC Corporation of America
-------------- next part --------------
A non-text attachment was scrubbed...
Name: lvm2-remove-use-dm_regex.patch
Type: text/x-patch
Size: 23254 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/lvm-devel/attachments/20070418/dd0e3a38/attachment.bin>
#5 lore raw

PATCH 1/1 libdevmapper: (4/6) Add filtering feature to dm_report

In reply to Jun'ichi Nomura

Hi,

This patch adds a filtering feature to dm_report.

- Add dm_report_set_filter() API.
By calling this, dm_report_object() omits rows which doesn't match the condition specified by the filter.

- Fitlers can be composed with the following components:
* Simple comparison of field value
'==', '!=', '>', '>=', '<', '<='
Strings should be quoted by either ' or ".
Only decimal, non-negative integers are currently allowed.
* Regular expression
'=~', '!~'
Regular expression can be quoted by '/', '|', '#', or any other characters.
* Logical combinations of the expressions
'and', 'or', '!', '(', ')'

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

Add filtering feature to dm_report.

Filter is set by dm_report_set_filters()

---
 lib/.exported_symbols |    1 
 lib/libdevmapper.h    |    4 
 lib/libdm-report.c    |  783 +++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 781 insertions(+), 7 deletions(-)
lib/.exported_symbols +1 -0
Index: device-mapper.work/lib/.exported_symbols
===================================================================
@@ -127,5 +127,6 @@ dm_report_field_int32
 dm_report_field_uint32
 dm_report_field_uint64
 dm_report_field_set_value
+dm_report_set_filter
 dm_regex_create
 dm_regex_match
lib/libdevmapper.h +4 -0
Index: device-mapper.work/lib/libdevmapper.h
===================================================================
@@ -688,6 +688,10 @@ int dm_report_object(struct dm_report *r
 int dm_report_output(struct dm_report *rh);
 void dm_report_free(struct dm_report *rh);
 
+/* Set filter */
+int dm_report_set_filter(struct dm_report *rh,
+			 const char *filter, uint32_t flags);
+
 /*
  * Report functions are provided for simple data types.
  * They take care of allocating copies of the data.
lib/libdm-report.c +776 -7

864 lines not on this page · raw message

#6 lore raw

PATCH 1/1 LVM2: (2/2) Use dm_report filter

Hi,

This patch adds '--filter' option to reporting commands: lvs, vgs and pvs.

The patch depends on the following patches:
[PATCH] libdevmapper: (4/6) Add filtering feature to dm_report
https://www.redhat.com/archives/dm-devel/2007-April/msg00029.html
[PATCH] libdevmapper: (7/6) Add dm_report_get_report_types()
https://www.redhat.com/archives/dm-devel/2007-April/msg00035.html

Examples:

Find PVs used for VG vg0

# pvs --filter 'vg_name == "vg0"'

Find PVs not used by any LVs

# pvs --filter 'used == 0'

Find PVs satisfying both of the aboves

# pvs --filter 'vg_name == "vg0" && used == 0'

Find PVs not satisfying the above

# pvs --filter '! (vg_name == "vg0" && used == 0)'

Find VGs with more than 2 PVs and with more than 400 extents

# vgs --filter 'pv_count > 2 && free_count > 400'

Find active snapshot LVs

# lvs --filter 'attr =~ /^s...a/'

Find LVs using /dev/sdc

# lvs --filter 'devices =~ |/dev/sdc|'

..

Possible future enhancements:
- Cope with units.
I.e. lvs --filter 'size > 4G' to find LVs larger than 4GB Currently, the filter can handle only the raw value of the field.

Thanks,

Signature · 8 lines
Jun'ichi Nomura, NEC Corporation of America
-------------- next part --------------
A non-text attachment was scrubbed...
Name: lvm2-add-filter.patch
Type: text/x-patch
Size: 7144 bytes
Desc: not available
URL: <http://listman.redhat.com/archives/lvm-devel/attachments/20070418/97908cf7/attachment.bin>
#7 lore raw

PATCH 1/1 libdevmapper: (5/6) Add '--filter' option to dmsetup

In reply to Jun'ichi Nomura

Hi,

This patch adds '--filter' option to dmsetup, so that it can use the filtering feature of dm_report.

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

Add --filter (-F) option to dmsetup for filtering report output.

---
 dmsetup/dmsetup.c |   15 ++++++++++++++-
 man/dmsetup.8     |    2 +-
 2 files changed, 15 insertions(+), 2 deletions(-)
dmsetup/dmsetup.c +14 -1
Index: device-mapper.work/dmsetup/dmsetup.c
===================================================================
@@ -104,6 +104,7 @@ enum {
 	COLS_ARG,
 	EXEC_ARG,
 	FORCE_ARG,
+	FILTER_ARG,
 	GID_ARG,
 	MAJOR_ARG,
 	MINOR_ARG,
@@ -1650,6 +1651,13 @@ static int _report_init(struct command *
 					options, separator, flags, keys, NULL)))
 		goto out;
 
+	if (_string_args[FILTER_ARG] &&
+	    !dm_report_set_filter(_report, _string_args[FILTER_ARG], 0)) {
+		dm_report_free(_report);
+		_report = NULL;
+		goto out;
+	}
+
 	r = 1;
 
 out:
@@ -2059,6 +2067,7 @@ static int _process_switches(int *argc, 
 		{"columns", 0, &ind, COLS_ARG},
 		{"exec", 1, &ind, EXEC_ARG},
 		{"force", 0, &ind, FORCE_ARG},
+		{"filter", 1, &ind, FILTER_ARG},
 		{"gid", 1, &ind, GID_ARG},
 		{"major", 1, &ind, MAJOR_ARG},
 		{"minor", 1, &ind, MINOR_ARG},
@@ -2133,7 +2142,7 @@ static int _process_switches(int *argc, 
 
 	optarg = 0;
 	optind = OPTIND_INIT;
-	while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfGj:m:Mno:O:ru:Uv",
+	while ((ind = -1, c = GETOPTLONG_FN(*argc, *argv, "cCfF:Gj:m:Mno:O:ru:Uv",
 					    long_options, NULL)) != -1) {
 		if (c == ':' || c == '?')
 			return 0;
@@ -2141,6 +2150,10 @@ static int _process_switches(int *argc, 
 			_switches[COLS_ARG]++;
 		if (c == 'f' || ind == FORCE_ARG)
 			_switches[FORCE_ARG]++;
+		if (c == 'F' || ind == FILTER_ARG) {
+			_switches[FILTER_ARG]++;
+			_string_args[FILTER_ARG] = optarg;
+		}
 		if (c == 'r' || ind == READ_ONLY)
 			_switches[READ_ONLY]++;
 		if (c == 'j' || ind == MAJOR_ARG) {
man/dmsetup.8 +1 -1
Index: device-mapper.work/man/dmsetup.8
===================================================================
@@ -44,7 +44,7 @@ dmsetup \- low level logical volume mana
 .br
 .B dmsetup info -c|-C|--columns
 .I [--noheadings] [--separator separator] [-o fields] [-O|--sort sort_fields]
-.I [device_name]
+.I [--filter expression] [device_name]
 .br
 .B dmsetup deps
 .I [device_name]
#8 lore raw

PATCH 1/1 libdevmapper: (6/6) Add deps and treenode fields for dmsetup info -c

In reply to Jun'ichi Nomura

Hi,

This patch adds optional fields to 'dmsetup info -c'.
You can specify the following fields with '-o', '-O' and filtering option.
- deps
- deps_count
- parents
- parents_count

For example, you can find the top-level dm devices by:

  # dmsetup info -c -o name --filter 'parents_count == 0'

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

Add fields of deps and treenode to dmsetup

---
 dmsetup/dmsetup.c |  283 ++++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 276 insertions(+), 7 deletions(-)
dmsetup/dmsetup.c +276 -7
Index: device-mapper.work/dmsetup/dmsetup.c
===================================================================
@@ -241,11 +241,14 @@ static int _parse_file(struct dm_task *d
 struct dmsetup_report_obj {
 	struct dm_task *task;
 	struct dm_info *info;
+	struct dm_task *deps;
+	struct dm_tree_node *tree;
 };
 
 static int _display_info_cols(struct dm_task *dmt, struct dm_info *info)
 {
 	struct dmsetup_report_obj obj;
+	int r = 0;
 
 	if (!info->exists) {
 		fprintf(stderr, "Device does not exist.\n");
@@ -254,11 +257,18 @@ static int _display_info_cols(struct dm_
 
 	obj.task = dmt;
 	obj.info = info;
+	obj.deps = NULL; /* task is created later on demand */
+	obj.tree = NULL; /* deptree is created later on demand */
 
 	if (!dm_report_object(_report, &obj))
-		return 0;
+		goto out;
 
-	return 1;
+	r = 1;
+
+      out:
+	if (obj.deps)
+		dm_task_destroy(obj.deps);
+	return r;
 }
 
 static void _display_info_long(struct dm_task *dmt, struct dm_info *info)
@@ -1457,17 +1467,26 @@ static int _add_dep(int argc __attribute
 /*
  * Create and walk dependency tree
  */
-static int _tree(int argc, char **argv, void *data __attribute((unused)))
+static int _build_whole_deptree(void)
 {
+	if (_dtree)
+		return 1;
+
 	if (!(_dtree = dm_tree_create()))
 		return 0;
 
-	if (!_process_all(argc, argv, 0, _add_dep))
+	if (!_process_all(0, NULL, 0, _add_dep))
 		return 0;
 
-	_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
+	return 1;
+}
+
+static int _tree(int argc, char **argv, void *data __attribute((unused)))
+{
+	if (!_build_whole_deptree())
+		return 0;
 
-	dm_tree_free(_dtree);
+	_tree_walk_children(dm_tree_find_node(_dtree, 0, 0), 0);
 
 	return 1;
 }
@@ -1539,8 +1558,193 @@ static int _dm_info_status_disp(struct d
 	return dm_report_field_string(rh, field, &s);
 }
 
+#define MAJ_MIN_LEN 32
+
+static int _dm_info_device_disp(struct dm_report *rh, struct dm_pool *mem,
+				struct dm_report_field *field, const void *data,
+				void *private)
+{
+	char buf[MAJ_MIN_LEN], *repstr;
+	struct dm_info *info = (struct dm_info *) data;
+
+	if (!dm_pool_begin_object(mem, 8)) {
+		log_error("dm_pool_begin_object failed");
+		return 0;
+	}
+
+	if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+			info->major, info->minor) < 0) {
+		log_error("dm_pool_alloc failed");
+		goto out_abandon;
+	}
+
+	if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+		log_error("dm_pool_grow_object failed");
+		goto out_abandon;
+	}
+
+	repstr = dm_pool_end_object(mem);
+	dm_report_field_set_value(field, repstr, repstr);
+	return 1;
+
+      out_abandon:
+	dm_pool_abandon_object(mem);
+	return 0;
+}
+
+static int _dm_tree_parent_maps_disp(struct dm_report *rh,
+				     struct dm_pool *mem,
+				     struct dm_report_field *field,
+				     const void *data, void *private)
+{
+	struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
+	void *t = NULL;
+	const char *name;
+	int first_node = 1;
+	char *repstr;
+
+	if (!dm_pool_begin_object(mem, 16)) {
+		log_error("dm_pool_begin_object failed");
+		return 0;
+	}
+
+	while ((parent = dm_tree_next_child(&t, node, 1))) {
+		name = dm_tree_node_get_name(parent);
+		if (!name || !*name)
+			continue;
+		if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
+			log_error("dm_pool_grow_object failed");
+			goto out_abandon;
+		}
+		if (!dm_pool_grow_object(mem, name, strlen(name))) {
+			log_error("dm_pool_grow_object failed");
+			goto out_abandon;
+		}
+		if (first_node)
+			first_node = 0;
+	}
+
+	if (!dm_pool_grow_object(mem, "\0", 1)) {
+		log_error("dm_pool_grow_object failed");
+		goto out_abandon;
+	}
+
+	repstr = dm_pool_end_object(mem);
+	dm_report_field_set_value(field, repstr, repstr);
+	return 1;
+
+      out_abandon:
+	dm_pool_abandon_object(mem);
+	return 0;
+}
+
+static int _dm_tree_parents_disp(struct dm_report *rh, struct dm_pool *mem,
+				 struct dm_report_field *field,
+				 const void *data, void *private)
+{
+	struct dm_tree_node *node = (struct dm_tree_node *) data, *parent;
+	void *t = NULL;
+	const struct dm_info *info;
+	int first_node = 1;
+	char buf[MAJ_MIN_LEN], *repstr;
+
+	if (!dm_pool_begin_object(mem, 16)) {
+		log_error("dm_pool_begin_object failed");
+		return 0;
+	}
+
+	while ((parent = dm_tree_next_child(&t, node, 1))) {
+		info = dm_tree_node_get_info(parent);
+		if (!info->major && !info->minor)
+			continue;
+		if (!first_node && !dm_pool_grow_object(mem, ",", 1)) {
+			log_error("dm_pool_grow_object failed");
+			goto out_abandon;
+		}
+		if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+				info->major, info->minor) < 0) {
+			log_error("dm_snprintf failed");
+			goto out_abandon;
+		}
+		if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+			log_error("dm_pool_grow_object failed");
+			goto out_abandon;
+		}
+		if (first_node)
+			first_node = 0;
+	}
+
+	if (!dm_pool_grow_object(mem, "\0", 1)) {
+		log_error("dm_pool_grow_object failed");
+		goto out_abandon;
+	}
+
+	repstr = dm_pool_end_object(mem);
+	dm_report_field_set_value(field, repstr, repstr);
+	return 1;
+
+      out_abandon:
+	dm_pool_abandon_object(mem);
+	return 0;
+}
+
+static int _dm_tree_parents_count_disp(struct dm_report *rh,
+				       struct dm_pool *mem,
+				       struct dm_report_field *field,
+				       const void *data, void *private)
+{
+	struct dm_tree_node *node = (struct dm_tree_node *) data;
+	int num_parent = dm_tree_node_num_children(node, 1);
+
+	return dm_report_field_int(rh, field, &num_parent);
+}
+
+static int _dm_deps_disp(struct dm_report *rh, struct dm_pool *mem,
+			 struct dm_report_field *field, const void *data,
+			 void *private)
+{
+	struct dm_deps *deps = (struct dm_deps *) data;
+	int i;
+	char buf[MAJ_MIN_LEN], *repstr;
+
+	if (!dm_pool_begin_object(mem, 16)) {
+		log_error("dm_pool_begin_object failed");
+		return 0;
+	}
+
+	for (i = 0; i < deps->count; i++) {
+		if (dm_snprintf(buf, sizeof(buf), "%d:%d",
+		       (int) MAJOR(deps->device[i]),
+		       (int) MINOR(deps->device[i])) < 0) {
+			log_error("dm_snprintf failed");
+			goto out_abandon;
+		}
+		if (!dm_pool_grow_object(mem, buf, strlen(buf))) {
+			log_error("dm_pool_grow_object failed");
+			goto out_abandon;
+		}
+		if (i + 1 < deps->count && !dm_pool_grow_object(mem, ",", 1)) {
+			log_error("dm_pool_grow_object failed");
+			goto out_abandon;
+		}
+	}
+
+	if (!dm_pool_grow_object(mem, "\0", 1)) {
+		log_error("dm_pool_grow_object failed");
+		goto out_abandon;
+	}
+
+	repstr = dm_pool_end_object(mem);
+	dm_report_field_set_value(field, repstr, repstr);
+	return 1;
+
+      out_abandon:
+	dm_pool_abandon_object(mem);
+	return 0;
+}
+
 /* Report types */
-enum { DR_TASK = 1, DR_INFO = 2 };
+enum { DR_TASK = 1, DR_INFO = 2, DR_DEPS = 4, DR_TREE = 8 };
 
 static void *_task_get_obj(void *obj)
 {
@@ -1552,9 +1756,65 @@ static void *_info_get_obj(void *obj)
 	return ((struct dmsetup_report_obj *)obj)->info;
 }
 
+static void *_tree_get_obj(void *obj)
+{
+	struct dmsetup_report_obj *o = (struct dmsetup_report_obj *) obj;
+	struct dm_info *info;
+
+	if (o->tree)
+		return o->tree;
+
+	if (!_build_whole_deptree())
+		return NULL;
+
+	if (!(info = _info_get_obj(o)))
+		return NULL;
+
+	o->tree = dm_tree_find_node(_dtree, info->major, info->minor);
+	return o->tree;
+}
+
+static void *_deps_get_obj(void *obj)
+{
+	struct dmsetup_report_obj *o = (struct dmsetup_report_obj *) obj;
+	struct dm_task *dmt;
+	const char *name;
+
+	if (o->deps)
+		return dm_task_get_deps(o->deps);
+
+	/* name */
+	if (!(dmt = _task_get_obj(o)))
+		return NULL;
+	if (!(name = dm_task_get_name(dmt)))
+		return NULL;
+
+	/* deps */
+	if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
+		return NULL;
+
+	if (!dm_task_set_name(dmt, name))
+		goto out;
+
+	if (_switches[NOOPENCOUNT_ARG] && !dm_task_no_open_count(dmt))
+		goto out;
+
+	if (!dm_task_run(dmt))
+		goto out;
+
+	o->deps = dmt;
+	return dm_task_get_deps(dmt);
+
+      out:
+	dm_task_destroy(dmt);
+	return NULL;
+}
+
 static const struct dm_report_object_type _report_types[] = {
 	{ DR_TASK, "Mapped Device Name", "", _task_get_obj },
 	{ DR_INFO, "Mapped Device Information", "", _info_get_obj },
+	{ DR_DEPS, "Mapped Device Dependency", "", _deps_get_obj },
+	{ DR_TREE, "Mapped Device Dependency", "", _tree_get_obj },
 	{ 0, "", "", NULL },
 };
 
@@ -1570,11 +1830,17 @@ static const struct dm_report_field_type
 FIELD_F(TASK, STR, "Name", 16, dm_name, "name", "Name of mapped device.")
 FIELD_F(TASK, STR, "UUID", 32, dm_uuid, "uuid", "Unique (optional) identifier for mapped device.")
 FIELD_F(INFO, STR, "Stat", 4, dm_info_status, "attr", "(L)ive, (I)nactive, (s)uspended, (r)ead-only, read-(w)rite.")
+FIELD_F(INFO, STR, "Device", 6, dm_info_device, "device", "Device major and minor numbers")
 FIELD_O(INFO, dm_info, NUM, "Maj", major, 3, int32, "major", "Block device major number.")
 FIELD_O(INFO, dm_info, NUM, "Min", minor, 3, int32, "minor", "Block device minor number.")
 FIELD_O(INFO, dm_info, NUM, "Open", open_count, 4, int32, "open", "Number of references to open device, if requested.")
 FIELD_O(INFO, dm_info, NUM, "Targ", target_count, 4, int32, "segments", "Number of segments in live table, if present.")
 FIELD_O(INFO, dm_info, NUM, "Event", event_nr, 6, uint32, "events", "Number of most recent event.")
+FIELD_O(DEPS, dm_deps, NUM, "Deps", count, 4, int32, "deps_count", "Number of underlying devices")
+FIELD_F(DEPS, STR, "Depend on", 10, dm_deps, "deps", "List of underlying devic es")
+FIELD_F(TREE, STR, "Parent Devices", 16, dm_tree_parents, "parents", "List of overlaying devices")
+FIELD_F(TREE, STR, "Parent Maps", 12, dm_tree_parent_maps, "parent_maps", "List of overlaying maps")
+FIELD_F(TREE, NUM, "Parents", 7, dm_tree_parents_count, "parents_count", "Number of overlaying devices")
 {0, 0, 0, 0, "", "", NULL, NULL},
 /* *INDENT-ON* */
 };
@@ -2300,5 +2566,8 @@ out:
 		dm_report_free(_report);
 	}
 
+	if (_dtree)
+		dm_tree_free(_dtree);
+
 	return r;
 }
#9 lore raw

PATCH 1/1 libdevmapper: (7/6) Add dm_report_get_report_types()

In reply to Jun'ichi Nomura

Hi,

This patch was missing from the last post...

Since rh->report_types can be updated after dm_report_init(), we need an interface to obtain it later.

Thanks,

Signature · 1 line
Jun'ichi Nomura, NEC Corporation of America

Add dm_report_get_report_types() to obtain updated report_types field after dm_report_set_filter() call.

---
 dmsetup/dmsetup.c     |    1 +
 lib/.exported_symbols |    1 +
 lib/libdevmapper.h    |    1 +
 lib/libdm-report.c    |    5 +++++
 4 files changed, 8 insertions(+)
lib/.exported_symbols +1 -0
Index: device-mapper.work/lib/.exported_symbols
===================================================================
@@ -128,5 +128,6 @@ dm_report_field_uint32
 dm_report_field_uint64
 dm_report_field_set_value
 dm_report_set_filter
+dm_report_get_report_types
 dm_regex_create
 dm_regex_match
lib/libdm-report.c +5 -0
Index: device-mapper.work/lib/libdm-report.c
===================================================================
@@ -88,6 +88,11 @@ struct row {
 	struct dm_report_field *(*sort_fields)[]; /* Fields in sort order */
 };
 
+uint32_t dm_report_get_report_types(struct dm_report *rh)
+{
+	return rh->report_types;
+}
+
 static const struct dm_report_object_type *_find_type(struct dm_report *rh,
 						      uint32_t report_type)
 {
lib/libdevmapper.h +1 -0
Index: device-mapper.work/lib/libdevmapper.h
===================================================================
@@ -687,6 +687,7 @@ struct dm_report *dm_report_init(uint32_
 int dm_report_object(struct dm_report *rh, void *object);
 int dm_report_output(struct dm_report *rh);
 void dm_report_free(struct dm_report *rh);
+uint32_t dm_report_get_report_types(struct dm_report *rh);
 
 /* Set filter */
 int dm_report_set_filter(struct dm_report *rh,
dmsetup/dmsetup.c +1 -0
Index: device-mapper.work/dmsetup/dmsetup.c
===================================================================
@@ -1924,6 +1924,7 @@ static int _report_init(struct command *
 		goto out;
 	}
 
+	report_type = dm_report_get_report_types(_report);
 	r = 1;
 
 out: