[lvm-devel] master - report: fix segfault while reporting PV/LV segment fields together with LV fields needeing device status (LVSINFO)

Peter Rajnoha prajnoha at fedoraproject.org
Mon Jul 7 13:58:16 UTC 2014


Gitweb:        http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=83b55c2dfba12db95fa5247039470278741372ab
Commit:        83b55c2dfba12db95fa5247039470278741372ab
Parent:        6dc7b783c80c6834aa724df49b5d47b9b5601506
Author:        Peter Rajnoha <prajnoha at redhat.com>
AuthorDate:    Mon Jul 7 15:54:13 2014 +0200
Committer:     Peter Rajnoha <prajnoha at redhat.com>
CommitterDate: Mon Jul 7 15:54:13 2014 +0200

report: fix segfault while reporting PV/LV segment fields together with LV fields needeing device status (LVSINFO)

There was missing lv_info call for situations where there were
mixed PV/LV segment fields together with LVSINFO fields which
require extra lv_info call for LV device status. This ended up
with NULL lvinfo passed to the field reporting functions, hence
the segfault.
---
 tools/reporter.c |   79 +++++++++++++++++++++++++++++++++++++++++++++++------
 1 files changed, 70 insertions(+), 9 deletions(-)

diff --git a/tools/reporter.c b/tools/reporter.c
index 524d6c4..5e9fb24 100644
--- a/tools/reporter.c
+++ b/tools/reporter.c
@@ -70,12 +70,28 @@ static int _segs_single(struct cmd_context *cmd __attribute__((unused)),
 
 	return ECMD_PROCESSED;
 }
-static int _pvsegs_sub_single(struct cmd_context *cmd,
-			      struct volume_group *vg,
-			      struct pv_segment *pvseg, void *handle)
+
+static int _segs_with_lv_info_single(struct cmd_context *cmd __attribute__((unused)),
+				     struct lv_segment *seg, void *handle)
+{
+	struct lvinfo lvinfo;
+
+	if (!lv_info(cmd, seg->lv, 0, &lvinfo, 1, 1) ||
+	    !report_object(handle, seg->lv->vg, seg->lv, NULL, seg, NULL, &lvinfo, NULL))
+		return_ECMD_FAILED;
+
+	return ECMD_PROCESSED;
+}
+
+static int _do_pvsegs_sub_single(struct cmd_context *cmd,
+				 struct volume_group *vg,
+				 struct pv_segment *pvseg,
+				 int lv_info_needed,
+				 void *handle)
 {
 	int ret = ECMD_PROCESSED;
 	struct lv_segment *seg = pvseg->lvseg;
+	struct lvinfo lvinfo = {.exists = 0};
 
 	struct volume_group _free_vg = {
 		.cmd = cmd,
@@ -120,8 +136,13 @@ static int _pvsegs_sub_single(struct cmd_context *cmd,
 	dm_list_init(&_free_logical_volume.segs_using_this_lv);
 	dm_list_init(&_free_logical_volume.snapshot_segs);
 
+	if (seg && !lv_info(cmd, seg->lv, 0, &lvinfo, 1, 1)) {
+		ret = ECMD_FAILED;
+		goto_out;
+	}
+
 	if (!report_object(handle, vg, seg ? seg->lv : &_free_logical_volume, pvseg->pv,
-			   seg ? : &_free_lv_segment, pvseg, NULL, pv_label(pvseg->pv))) {
+			   seg ? : &_free_lv_segment, pvseg, &lvinfo, pv_label(pvseg->pv))) {
 		ret = ECMD_FAILED;
 		goto_out;
 	}
@@ -130,6 +151,21 @@ static int _pvsegs_sub_single(struct cmd_context *cmd,
 	return ret;
 }
 
+static int _pvsegs_sub_single(struct cmd_context *cmd,
+			      struct volume_group *vg,
+			      struct pv_segment *pvseg, void *handle)
+{
+	return _do_pvsegs_sub_single(cmd, vg, pvseg, 0, handle);
+}
+
+static int _pvsegs_with_lv_info_sub_single(struct cmd_context *cmd,
+					   struct volume_group *vg,
+					   struct pv_segment *pvseg,
+					   void *handle)
+{
+	return _do_pvsegs_sub_single(cmd, vg, pvseg, 1, handle);
+}
+
 static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
 			  void *handle)
 {
@@ -139,6 +175,16 @@ static int _lvsegs_single(struct cmd_context *cmd, struct logical_volume *lv,
 	return process_each_segment_in_lv(cmd, lv, handle, _segs_single);
 }
 
+static int _lvsegs_with_lv_info_single(struct cmd_context *cmd,
+				       struct logical_volume *lv,
+				       void *handle)
+{
+	if (!arg_count(cmd, all_ARG) && !lv_is_visible(lv))
+		return ECMD_PROCESSED;
+
+	return process_each_segment_in_lv(cmd, lv, handle, _segs_with_lv_info_single);
+}
+
 static int _pvsegs_single(struct cmd_context *cmd, struct volume_group *vg,
 			  struct physical_volume *pv, void *handle)
 {
@@ -146,6 +192,15 @@ static int _pvsegs_single(struct cmd_context *cmd, struct volume_group *vg,
 					  _pvsegs_sub_single);
 }
 
+static int _pvsegs_with_lv_info_single(struct cmd_context *cmd,
+				       struct volume_group *vg,
+				       struct physical_volume *pv,
+				       void *handle)
+{
+	return process_each_segment_in_pv(cmd, vg, pv, handle,
+				_pvsegs_with_lv_info_sub_single);
+}
+
 static int _pvs_single(struct cmd_context *cmd, struct volume_group *vg,
 		       struct physical_volume *pv, void *handle)
 {
@@ -253,7 +308,7 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
 	int r = ECMD_PROCESSED;
 	int aligned, buffered, headings, field_prefixes, quoted;
 	int columns_as_rows;
-	unsigned args_are_pvs;
+	unsigned args_are_pvs, lv_info_needed;
 
 	aligned = find_config_tree_bool(cmd, report_aligned_CFG, NULL);
 	buffered = find_config_tree_bool(cmd, report_buffered_CFG, NULL);
@@ -371,12 +426,15 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
 					  columns_as_rows, selection)))
 		return_ECMD_FAILED;
 
+	/* Do we need lv_info to be called for LV device status? */
+	lv_info_needed = (report_type & LVSINFO) ? 1 : 0;
+
 	/* Ensure options selected are compatible */
 	if (report_type & SEGS)
 		report_type |= LVS;
 	if (report_type & PVSEGS)
 		report_type |= PVS;
-	if ((report_type & LVS) && (report_type & (PVS | LABEL)) && !args_are_pvs) {
+	if ((report_type & (LVS | LVSINFO)) && (report_type & (PVS | LABEL)) && !args_are_pvs) {
 		log_error("Can't report LV and PV fields at the same time");
 		dm_report_free(report_handle);
 		return ECMD_FAILED;
@@ -384,7 +442,7 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
 
 	/* Change report type if fields specified makes this necessary */
 	if ((report_type & PVSEGS) ||
-	    ((report_type & (PVS | LABEL)) && (report_type & LVS)))
+	    ((report_type & (PVS | LABEL)) && (report_type & (LVS | LVSINFO))))
 		report_type = PVSEGS;
 	else if ((report_type & LABEL) && (report_type & VGS))
 		report_type = PVS;
@@ -427,12 +485,15 @@ static int _report(struct cmd_context *cmd, int argc, char **argv,
 		break;
 	case SEGS:
 		r = process_each_lv(cmd, argc, argv, 0, report_handle,
-				    &_lvsegs_single);
+				    lv_info_needed ? &_lvsegs_with_lv_info_single
+						   : &_lvsegs_single);
 		break;
 	case PVSEGS:
 		if (args_are_pvs)
 			r = process_each_pv(cmd, argc, argv, NULL, 0,
-					    0, report_handle, &_pvsegs_single);
+					    0, report_handle,
+					    lv_info_needed ? &_pvsegs_with_lv_info_single
+							   : &_pvsegs_single);
 		else
 			r = process_each_vg(cmd, argc, argv, 0,
 					    report_handle, &_pvsegs_in_vg);




More information about the lvm-devel mailing list