diff options
author | Ondrej Kozina <okozina@redhat.com> | 2015-02-11 15:21:35 +0100 |
---|---|---|
committer | Ondrej Kozina <okozina@redhat.com> | 2015-04-01 11:01:21 +0200 |
commit | ea956e79e65494e98473801301c3289f8c3ad956 (patch) | |
tree | 14ee50ba4857314a9fc1669e456e66fc03bf8cbd | |
parent | 2233c916b087afab0f6f98ccb0fee79c2feea9f2 (diff) | |
download | lvm2-ea956e79e65494e98473801301c3289f8c3ad956.tar.gz |
lvmpolld: add suport for 'exit when idle'
-rw-r--r-- | daemons/lvmpolld/lvmpolld-core.c | 105 | ||||
-rw-r--r-- | daemons/lvmpolld/lvmpolld-data-utils.h | 22 |
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); } |