From 542d0c4bff23cb46eb156e25f995c563334e8ba2 Mon Sep 17 00:00:00 2001
From: Ondrej Kozina <okozina@redhat.com>
Date: Wed, 9 Mar 2016 18:02:30 +0100
Subject: [PATCH] lvmpolld: reinstate internal progress info tracking

---
 daemons/lvmpolld/lvmpolld-core.c       | 62 +++++++++++++++++++++++++-
 daemons/lvmpolld/lvmpolld-data-utils.c | 13 +++++-
 daemons/lvmpolld/lvmpolld-data-utils.h | 11 +++--
 3 files changed, 80 insertions(+), 6 deletions(-)

diff --git a/daemons/lvmpolld/lvmpolld-core.c b/daemons/lvmpolld/lvmpolld-core.c
index fd7327241..c6f02a4de 100644
--- a/daemons/lvmpolld/lvmpolld-core.c
+++ b/daemons/lvmpolld/lvmpolld-core.c
@@ -203,6 +203,60 @@ static int read_single_line(struct lvmpolld_thread_data *data, int err)
 	return (r > 0);
 }
 
+static const char *keyword(const enum poll_type type)
+{
+	switch (type) {
+	case PVMOVE:
+		return "Moved";
+	case CONVERT:
+		return "Converted";
+	case MERGE: /* fall through */
+	case MERGE_THIN:
+		return "Merged";
+	default:
+		return NULL;
+	}
+}
+
+static void parse_percents(struct lvmpolld_lv *pdlv, const char *line)
+{
+	char *endptr, *keyw, *nr;
+	dm_percent_t perc;
+	double d;
+
+	if (!(keyw = strstr(line, keyword(pdlv->type))) || keyw == line
+	    || !strchr(keyw, DM_PERCENT_CHAR)) {
+		DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
+		     "parsing percentage from lvm2 command failed");
+		return;
+	}
+
+	nr = strpbrk(keyw, "+-0123456789");
+	if (!nr) {
+		DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
+		     "parsing percentage from lvm2 command failed");
+		return;
+	}
+
+	d = strtod(nr, &endptr);
+	if (nr == endptr) {
+		DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
+		     "parsing percentage from lvm2 command failed");
+		return;
+	} else if (d > 100.0) {
+		WARN(pdlv->ls, "%s: %s", PD_LOG_PREFIX,
+		     "parsing percentage from lvm2 command returned invalid value");
+		return;
+	}
+
+	perc = dm_make_percent((uint64_t)(d * DM_PERCENT_1), DM_PERCENT_100);
+
+	DEBUGLOG(pdlv->ls, "%s: %s %.1f%%", PD_LOG_PREFIX,
+		 "parsed", dm_percent_to_float(perc));
+
+	pdlv_set_percents(pdlv, perc);
+}
+
 static void update_idle_state(struct lvmpolld_state *ls)
 {
 	if (!ls->idle)
@@ -274,6 +328,9 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
 			assert(read_single_line(data, 0)); /* may block indef. anyway */
 			INFO(pdlv->ls, "%s: PID %d: %s: '%s'", LVM2_LOG_PREFIX,
 			     pdlv->cmd_pid, "STDOUT", data->line);
+
+			if (pdlv->parse_output_fn)
+				pdlv->parse_output_fn(pdlv, data->line);
 		} else if (fds[0].revents) {
 			if (fds[0].revents & POLLHUP)
 				DEBUGLOG(pdlv->ls, "%s: %s", PD_LOG_PREFIX, "caught POLLHUP");
@@ -329,6 +386,8 @@ static int poll_for_output(struct lvmpolld_lv *pdlv, struct lvmpolld_thread_data
 		while (read_single_line(data, 0)) {
 			assert(r > 0);
 			INFO(pdlv->ls, "%s: PID %d: %s: %s", LVM2_LOG_PREFIX, pdlv->cmd_pid, "STDOUT", data->line);
+			if (pdlv->parse_output_fn)
+				pdlv->parse_output_fn(pdlv, data->line);
 		}
 	if (fds[1].fd >= 0)
 		while (read_single_line(data, 1)) {
@@ -562,7 +621,8 @@ static struct lvmpolld_lv *construct_pdlv(request req, struct lvmpolld_state *ls
 	unsigned handle_missing_pvs = daemon_request_int(req, LVMPD_PARM_HANDLE_MISSING_PVS, 0);
 
 	pdlv = pdlv_create(ls, id, vgname, lvname, sysdir, type,
-			   interval, uinterval, pdst);
+			   interval, uinterval, pdst,
+			   abort_polling ? NULL : parse_percents);
 
 	if (!pdlv) {
 		ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to create internal LV data structure.");
diff --git a/daemons/lvmpolld/lvmpolld-data-utils.c b/daemons/lvmpolld/lvmpolld-data-utils.c
index 99883f816..b141f0ace 100644
--- a/daemons/lvmpolld/lvmpolld-data-utils.c
+++ b/daemons/lvmpolld/lvmpolld-data-utils.c
@@ -91,7 +91,8 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
 			   const char *vgname, const char *lvname,
 			   const char *sysdir, enum poll_type type,
 			   const char *sinterval, unsigned pdtimeout,
-			   struct lvmpolld_store *pdst)
+			   struct lvmpolld_store *pdst,
+			   lvmpolld_parse_output_fn_t parse_fn)
 {
 	char *lvmpolld_id = dm_strdup(id), /* copy */
 	     *full_lvname = _construct_full_lvname(vgname, lvname), /* copy */
@@ -108,7 +109,8 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
 		.pdtimeout = pdtimeout < MIN_POLLING_TIMEOUT ? MIN_POLLING_TIMEOUT : pdtimeout,
 		.cmd_state = { .retcode = -1, .signal = 0 },
 		.pdst = pdst,
-		.init_rq_count = 1
+		.init_rq_count = 1,
+		.parse_output_fn = parse_fn
 	}, *pdlv = (struct lvmpolld_lv *) dm_malloc(sizeof(struct lvmpolld_lv));
 
 	if (!pdlv || !tmp.lvid || !tmp.lvname || !tmp.lvm_system_dir_env || !tmp.sinterval)
@@ -183,6 +185,13 @@ void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error)
 	pdlv_unlock(pdlv);
 }
 
+void pdlv_set_percents(struct lvmpolld_lv *pdlv, dm_percent_t percent)
+{
+	pdlv_lock(pdlv);
+	pdlv->percent = percent;
+	pdlv_unlock(pdlv);
+}
+
 void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished)
 {
 	pdlv_lock(pdlv);
diff --git a/daemons/lvmpolld/lvmpolld-data-utils.h b/daemons/lvmpolld/lvmpolld-data-utils.h
index 5bb5c863d..215886516 100644
--- a/daemons/lvmpolld/lvmpolld-data-utils.h
+++ b/daemons/lvmpolld/lvmpolld-data-utils.h
@@ -19,6 +19,9 @@
 
 struct buffer;
 struct lvmpolld_state;
+struct lvmpolld_lv;
+
+typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
 
 enum poll_type {
 	PVMOVE = 0,
@@ -54,6 +57,7 @@ struct lvmpolld_lv {
 	const char *const sinterval;
 	const char *const lvm_system_dir_env;
 	struct lvmpolld_store *const pdst;
+	lvmpolld_parse_output_fn_t parse_output_fn;
 	const char *const *cmdargv;
 	const char *const *cmdenvp;
 
@@ -65,13 +69,12 @@ struct lvmpolld_lv {
 
 	/* block of shared variables protected by lock */
 	struct lvmpolld_cmd_stat cmd_state;
+	dm_percent_t percent;
 	unsigned init_rq_count; /* for debuging purposes only */
 	unsigned polling_finished:1; /* no more updates */
 	unsigned error:1; /* unrecoverable error occured in lvmpolld */
 };
 
-typedef void (*lvmpolld_parse_output_fn_t) (struct lvmpolld_lv *pdlv, const char *line);
-
 /* TODO: replace with configuration option */
 #define MIN_POLLING_TIMEOUT 60
 
@@ -101,7 +104,8 @@ struct lvmpolld_lv *pdlv_create(struct lvmpolld_state *ls, const char *id,
 			   const char *vgname, const char *lvname,
 			   const char *sysdir, enum poll_type type,
 			   const char *sinterval, unsigned pdtimeout,
-			   struct lvmpolld_store *pdst);
+			   struct lvmpolld_store *pdst,
+			   lvmpolld_parse_output_fn_t parse_fn);
 
 /* only call with appropriate struct lvmpolld_store lock held */
 void pdlv_destroy(struct lvmpolld_lv *pdlv);
@@ -138,6 +142,7 @@ unsigned pdlv_get_polling_finished(struct lvmpolld_lv *pdlv);
 struct lvmpolld_lv_state pdlv_get_status(struct lvmpolld_lv *pdlv);
 void pdlv_set_cmd_state(struct lvmpolld_lv *pdlv, const struct lvmpolld_cmd_stat *cmd_state);
 void pdlv_set_error(struct lvmpolld_lv *pdlv, unsigned error);
+void pdlv_set_percents(struct lvmpolld_lv *pdlv, dm_percent_t percent);
 void pdlv_set_polling_finished(struct lvmpolld_lv *pdlv, unsigned finished);
 
 /*