summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Kozina <okozina@redhat.com>2015-02-11 15:21:35 +0100
committerOndrej Kozina <okozina@redhat.com>2015-04-01 11:01:21 +0200
commitea956e79e65494e98473801301c3289f8c3ad956 (patch)
tree14ee50ba4857314a9fc1669e456e66fc03bf8cbd
parent2233c916b087afab0f6f98ccb0fee79c2feea9f2 (diff)
downloadlvm2-ea956e79e65494e98473801301c3289f8c3ad956.tar.gz
lvmpolld: add suport for 'exit when idle'
-rw-r--r--daemons/lvmpolld/lvmpolld-core.c105
-rw-r--r--daemons/lvmpolld/lvmpolld-data-utils.h22
2 files changed, 97 insertions, 30 deletions
diff --git a/daemons/lvmpolld/lvmpolld-core.c b/daemons/lvmpolld/lvmpolld-core.c
index d47ee06fb..e21593017 100644
--- a/daemons/lvmpolld/lvmpolld-core.c
+++ b/daemons/lvmpolld/lvmpolld-core.c
@@ -56,13 +56,13 @@
#define REASON_INTERNAL_ERROR "lvmpolld internal error"
typedef struct lvmpolld_state {
+ daemon_idle *idle;
log_state *log;
const char *log_config;
+ const char *lvm_binary;
lvmpolld_store_t lvid_to_pdlv_abort;
lvmpolld_store_t lvid_to_pdlv_poll;
-
- const char *lvm_binary;
} lvmpolld_state_t;
static const char *const const polling_ops[] = { [PVMOVE] = LVMPD_REQ_PVMOVE,
@@ -187,6 +187,21 @@ static void parse_line_for_percents(lvmpolld_lv_t *pdlv, const char *line)
pdlv_set_percents(pdlv, perc);
}
+static void update_active_state(lvmpolld_state_t *ls)
+{
+ if (!ls->idle)
+ return;
+
+ pdst_lock(&ls->lvid_to_pdlv_poll);
+ pdst_lock(&ls->lvid_to_pdlv_abort);
+
+ ls->idle->is_idle = !ls->lvid_to_pdlv_poll.active_polling_count &&
+ !ls->lvid_to_pdlv_abort.active_polling_count;
+
+ pdst_unlock(&ls->lvid_to_pdlv_abort);
+ pdst_unlock(&ls->lvid_to_pdlv_poll);
+}
+
/* make this configurable */
#define MAX_TIMEOUT 0
@@ -490,7 +505,7 @@ err:
if (pdlv_get_background(pdlv)) {
/* holding store lock provides there's no single reader */
- pdst_remove(pdst, pdlv->lvid);
+ pdst_locked_remove(pdst, pdlv->lvid);
pdlv_destroy(pdlv);
} else if (error) {
/* last reader is responsible for pdlv cleanup */
@@ -499,12 +514,16 @@ err:
} else
pdlv_set_polling_finished(pdlv, 1);
+ pdst_locked_dec(pdst);
+
pdst_unlock(pdst);
/*
* after the store get unlocked pdlv
* may be already removed by some reader
*/
+ update_active_state(pdlv->ls);
+
if (outpipe[0] != -1)
close(outpipe[0]);
if (outpipe[1] != -1)
@@ -544,7 +563,7 @@ static response progress_info(client_handle h, lvmpolld_state_t *ls, request req
pdst_lock(pdst);
/* store locked */
- pdlv = pdst_lookup(pdst, lvid);
+ pdlv = pdst_locked_lookup(pdst, lvid);
if (pdlv) {
if (pdlv_get_and_unset_background(pdlv))
WARN(ls, "%s: %s", PD_LOG_PREFIX,
@@ -558,7 +577,7 @@ static response progress_info(client_handle h, lvmpolld_state_t *ls, request req
INFO(ls, "%s: %s %s", PD_LOG_PREFIX,
"Polling finished. Removing related data structure for LV",
lvid);
- pdst_remove(pdst, lvid);
+ pdst_locked_remove(pdst, lvid);
pdlv_destroy(pdlv);
}
}
@@ -667,16 +686,16 @@ static response poll_init(client_handle h, lvmpolld_state_t *ls, request req, en
pdst_lock(pdst);
- pdlv = pdst_lookup(pdst, lvid);
+ pdlv = pdst_locked_lookup(pdst, lvid);
if (pdlv && pdlv_get_polling_finished(pdlv)) {
- WARN(ls, "%s: %s %s", PD_LOG_PREFIX, "Removing uncollected info for LV",
+ WARN(ls, "%s: %s %s", PD_LOG_PREFIX, "Force removal of uncollected info for LV",
lvid);
/*
* lvmpolld has to remove uncollected results in this case.
* otherwise it would have to refuse request for new polling
* lv with same id.
*/
- pdst_remove(pdst, lvid);
+ pdst_locked_remove(pdst, lvid);
pdlv_destroy(pdlv);
pdlv = NULL;
}
@@ -696,18 +715,22 @@ static response poll_init(client_handle h, lvmpolld_state_t *ls, request req, en
pdst_unlock(pdst);
return reply_fail(REASON_INTERNAL_ERROR);
}
- if (!pdst_insert(pdst, lvid, pdlv)) {
+ if (!pdst_locked_insert(pdst, lvid, pdlv)) {
pdlv_destroy(pdlv);
pdst_unlock(pdst);
return reply_fail(REASON_INTERNAL_ERROR);
}
if (!spawn_detached_thread(pdlv)) {
ERROR(ls, "%s: %s", PD_LOG_PREFIX, "failed to spawn detached thread");
- pdst_remove(pdst, lvid);
+ pdst_locked_remove(pdst, lvid);
pdlv_destroy(pdlv);
pdst_unlock(pdst);
return reply_fail(REASON_INTERNAL_ERROR);
}
+
+ pdst_locked_inc(pdst);
+ if (ls->idle)
+ ls->idle->is_idle = 0;
}
pdst_unlock(pdst);
@@ -715,6 +738,7 @@ static response poll_init(client_handle h, lvmpolld_state_t *ls, request req, en
return daemon_reply_simple(LVMPD_RESP_OK, NULL);
}
+
static response handler(struct daemon_state s, client_handle h, request r)
{
lvmpolld_state_t *ls = s.private;
@@ -722,61 +746,88 @@ static response handler(struct daemon_state s, client_handle h, request r)
if (!strcmp(rq, LVMPD_REQ_PVMOVE))
return poll_init(h, ls, r, PVMOVE);
- if (!strcmp(rq, LVMPD_REQ_CONVERT))
+ else if (!strcmp(rq, LVMPD_REQ_CONVERT))
return poll_init(h, ls, r, CONVERT);
- if (!strcmp(rq, LVMPD_REQ_MERGE))
+ else if (!strcmp(rq, LVMPD_REQ_MERGE))
return poll_init(h, ls, r, MERGE);
- if (!strcmp(rq, LVMPD_REQ_MERGE_THIN))
+ else if (!strcmp(rq, LVMPD_REQ_MERGE_THIN))
return poll_init(h, ls, r, MERGE_THIN);
- if (!strcmp(rq, LVMPD_REQ_PROGRESS))
+ else if (!strcmp(rq, LVMPD_REQ_PROGRESS))
return progress_info(h, ls, r);
+ else
+ return reply_fail(REASON_REQ_NOT_IMPLEMENTED);
+}
+
+static int process_timeout_arg(const char *str, unsigned *max_timeouts)
+{
+ char *endptr;
+ unsigned long l;
+
+ l = strtoul(str, &endptr, 10);
+ if (errno || *endptr || l >= UINT_MAX)
+ return 0;
+
+ *max_timeouts = (unsigned) l;
- return reply_fail(REASON_REQ_NOT_IMPLEMENTED);
+ return 1;
}
int main(int argc, char *argv[])
{
signed char opt;
+ struct timeval timeout;
+ daemon_idle di = { .ptimeout = &timeout };
lvmpolld_state_t ls = { .log_config = "" };
daemon_state s = {
.daemon_fini = fini,
.daemon_init = init,
.handler = handler,
- .name = LVMPOLLD_PROTOCOL,
+ .name = "lvmpolld",
.pidfile = getenv("LVM_LVMPOLLD_PIDFILE") ?: LVMPOLLD_PIDFILE,
.private = &ls,
- .protocol = "lvmpolld",
+ .protocol = LVMPOLLD_PROTOCOL,
.protocol_version = LVMPOLLD_PROTOCOL_VERSION,
.socket_path = getenv("LVM_LVMPOLLD_SOCKET") ?: LVMPOLLD_SOCKET,
};
// use getopt_long
- while ((opt = getopt(argc, argv, "?fhVl:p:s:B:")) != EOF) {
+ while ((opt = getopt(argc, argv, "?fhVl:p:s:B:t:")) != EOF) {
switch (opt) {
- case 'h':
- usage(argv[0], stdout);
- exit(0);
case '?':
usage(argv[0], stderr);
exit(0);
+ case 'B': /* --binary */
+ ls.lvm_binary = optarg;
+ break;
+ case 'V':
+ printf("lvmpolld version: " LVM_VERSION "\n");
+ exit(1);
case 'f':
s.foreground = 1;
break;
+ case 'h':
+ usage(argv[0], stdout);
+ exit(0);
case 'l':
ls.log_config = optarg;
break;
case 'p':
s.pidfile = optarg;
break;
- case 's': // --socket
+ case 's': /* --socket */
s.socket_path = optarg;
break;
- case 'B': /* --binary */
- ls.lvm_binary = optarg;
+ case 't': /* --timeout in seconds */
+ if (!process_timeout_arg(optarg, &di.max_timeouts)) {
+ fprintf(stderr, "Invalid value of timeout parameter");
+ exit(1);
+ }
+ /* 0 equals to wait indefinitely */
+ if (di.max_timeouts) {
+ ls.idle = &di;
+ s.idle = &di;
+ }
break;
- case 'V':
- printf("lvmpolld version: " LVM_VERSION "\n");
- exit(1);
}
}
diff --git a/daemons/lvmpolld/lvmpolld-data-utils.h b/daemons/lvmpolld/lvmpolld-data-utils.h
index 64b732bd8..11f2310f7 100644
--- a/daemons/lvmpolld/lvmpolld-data-utils.h
+++ b/daemons/lvmpolld/lvmpolld-data-utils.h
@@ -37,6 +37,7 @@ typedef struct {
pthread_mutex_t lock;
void *store;
const char *name;
+ unsigned active_polling_count;
} lvmpolld_store_t;
typedef struct {
@@ -167,17 +168,32 @@ static inline void pdst_unlock(lvmpolld_store_t *pdst)
pthread_mutex_unlock(&pdst->lock);
}
-static inline int pdst_insert(lvmpolld_store_t *pdst, const char *key, lvmpolld_lv_t *pdlv)
+static inline void pdst_locked_inc(lvmpolld_store_t *pdst)
+{
+ pdst->active_polling_count++;
+}
+
+static inline void pdst_locked_dec(lvmpolld_store_t *pdst)
+{
+ pdst->active_polling_count--;
+}
+
+static inline unsigned pdst_locked_get_active_polling_count(const lvmpolld_store_t *pdst)
+{
+ return pdst->active_polling_count;
+}
+
+static inline int pdst_locked_insert(lvmpolld_store_t *pdst, const char *key, lvmpolld_lv_t *pdlv)
{
return dm_hash_insert(pdst->store, key, pdlv);
}
-static inline lvmpolld_lv_t *pdst_lookup(lvmpolld_store_t *pdst, const char *key)
+static inline lvmpolld_lv_t *pdst_locked_lookup(lvmpolld_store_t *pdst, const char *key)
{
return dm_hash_lookup(pdst->store, key);
}
-static inline void pdst_remove(lvmpolld_store_t *pdst, const char *key)
+static inline void pdst_locked_remove(lvmpolld_store_t *pdst, const char *key)
{
dm_hash_remove(pdst->store, key);
}