master - tests: implement umount in script
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=1a2b88516bd213...
Commit: 1a2b88516bd213a912ba6c5133a977a5003f3a16
Parent: 47c11c7b1c364a2d2fd257aaa191816e146d3602
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Jan 21 17:37:53 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sat Jan 21 17:42:19 2017 +0100
tests: implement umount in script
Since dmeventd no longer umounts thin devices, such logic
needs to be implemented by external script.
Add some very simple one for the start.
---
test/shell/thin-autoumount-dmeventd.sh | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/test/shell/thin-autoumount-dmeventd.sh b/test/shell/thin-autoumount-dmeventd.sh
index 40dd75f..363efe2 100644
--- a/test/shell/thin-autoumount-dmeventd.sh
+++ b/test/shell/thin-autoumount-dmeventd.sh
@@ -42,6 +42,22 @@ export MKE2FS_CONFIG="$TESTDIR/lib/mke2fs.conf"
aux have_thin 1 0 0 || skip
+aux lvmconf "dmeventd/thin_command = \"$PWD/testcmd.sh\""
+
+# Simple implementation of umount when lvextend fails
+cat <<- EOF >testcmd.sh
+#!/bin/sh
+
+echo "Data $DMEVENTD_THIN_POOL_DATA"
+echo "Metadata $DMEVENTD_THIN_POOL_METADATA"
+
+lvextend --use-policies $1 || {
+ umount --lazy "$mntdir" || true
+ umount --lazy "$mntusedir" || true
+}
+EOF
+chmod +x testcmd.sh
+
aux prepare_dmeventd
# Use autoextend percent 0 - so extension fails and triggers umount...
6 years
master - tests: enusure units in TiB
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=47c11c7b1c364a...
Commit: 47c11c7b1c364a2d2fd257aaa191816e146d3602
Parent: 2e0605d6db9723d4bea472b21352d398f29e226e
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Jan 21 16:20:41 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sat Jan 21 17:42:19 2017 +0100
tests: enusure units in TiB
---
test/shell/lvcreate-large.sh | 8 ++++----
1 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/test/shell/lvcreate-large.sh b/test/shell/lvcreate-large.sh
index 81c612a..6fc4c5e 100644
--- a/test/shell/lvcreate-large.sh
+++ b/test/shell/lvcreate-large.sh
@@ -32,15 +32,15 @@ pvcreate "$DM_DEV_DIR/$vg/$lv"
vgcreate $vg1 "$DM_DEV_DIR/$vg/$lv"
lvcreate -l 100%FREE -n $lv1 $vg1
-check lv_field $vg1/$lv1 size "1024.00t"
+check lv_field $vg1/$lv1 size "1024.00t" --units t
lvresize -f -l 72%VG $vg1/$lv1
-check lv_field $vg1/$lv1 size "737.28t"
+check lv_field $vg1/$lv1 size "737.28t" --units t
lvremove -ff $vg1/$lv1
lvcreate -l 100%VG -n $lv1 $vg1
-check lv_field $vg1/$lv1 size "1024.00t"
+check lv_field $vg1/$lv1 size "1024.00t" --units t
lvresize -f -l 72%VG $vg1/$lv1
-check lv_field $vg1/$lv1 size "737.28t"
+check lv_field $vg1/$lv1 size "737.28t" --units t
lvremove -ff $vg1/$lv1
lvremove -ff $vg/$lv
6 years
master - dmeventd_thin: internal command without lvm prefix
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2e0605d6db9723...
Commit: 2e0605d6db9723d4bea472b21352d398f29e226e
Parent: 85dab3963fbf8b3cc1be84f2d7c43257075ac2a3
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Sat Jan 21 17:37:01 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sat Jan 21 17:42:19 2017 +0100
dmeventd_thin: internal command without lvm prefix
Internal command processing needs to go without 'lvm ' prefix.
---
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index a676de3..a6a534d 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -375,7 +375,8 @@ int register_device(const char *device,
dm_split_words(str, maxcmd - 1, 0, state->argv);
_init_thread_signals(state);
- }
+ } else
+ memmove(state->cmd_str, state->cmd_str + 4, strlen(state->cmd_str + 4) + 1);
state->pid = -1;
*user = state;
6 years
master - dmeventd_thin: enable support for external command
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=85dab3963fbf8b...
Commit: 85dab3963fbf8b3cc1be84f2d7c43257075ac2a3
Parent: 8c4f3633ac460f24342a83e98afa6e8186d453a3
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jan 20 22:54:20 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Sat Jan 21 00:01:05 2017 +0100
dmeventd_thin: enable support for external command
With this commit we start to support configurable action
from thin-pool monitoring via 'dmeventd/thin_command'
---
WHATS_NEW_DM | 1 +
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 3 +--
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index a8d4105..4903de3 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.138 -
=====================================
+ Support configurable command executed from dmeventd thin plugin.
Support new R|r human readable units output format.
Thin dmeventd plugin reacts faster on lvextend failure path with umount.
Add dm_stats_bind_from_fd() to bind a stats handle from a file descriptor.
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index 2367bde..a676de3 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -357,8 +357,7 @@ int register_device(const char *device,
if (!dmeventd_lvm2_command(state->mem, state->cmd_str,
sizeof(state->cmd_str),
- "lvextend --use-policies",
- device)) {
+ "_dmeventd_thin_command", device)) {
dmeventd_lvm2_exit_with_pool(state);
goto_bad;
}
6 years
master - dmeventd_thin: new logic for calling commands
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8c4f3633ac460f...
Commit: 8c4f3633ac460f24342a83e98afa6e8186d453a3
Parent: 8b95551ade0af5c1ef93f044c4508134f359e242
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jan 20 23:07:05 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jan 20 23:58:56 2017 +0100
dmeventd_thin: new logic for calling commands
For more advanced support we need to ensure better logic for calling
external much more advanced script for maintanance of thin-pool.
So this new code ensures:
When thin-pool data or metadata is bigger then 50%,
then with each 5% increment, action is called.
This is independent from autoextend_threshold.
This action always happens when thin-pool is over threshold,
(so no action when it's exactly i.e. 60%).
The only exception is 100% full thin-pool - which invokes 'last'
action.
Since thin-pool occupancy may change also downward, code needs
to also handle possibly reduction of occupancy of thin-pool.
So when usage drop from 90% to 50%, thin-pool will start to call
again action when it will pass 55% threshold.
This give external commands lot of option i.e. to call 'fstrim'
before actual resize is needed.
---
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 44 +++++++++++++-----------
1 files changed, 24 insertions(+), 20 deletions(-)
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index bd70e78..2367bde 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -243,21 +243,27 @@ void process_event(struct dm_task *dmt,
state->fails = 0;
}
+ /*
+ * Trigger action when threshold boundary is exceeded.
+ * Report 80% threshold warning when it's used above 80%.
+ * Only 100% is exception as it cannot be surpased so policy
+ * action is called for: >50%, >55% ... >95%, 100%
+ */
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
if (state->metadata_percent <= WARNING_THRESH)
state->metadata_warn_once = 0; /* Dropped bellow threshold, reset warn once */
else if (!state->metadata_warn_once++) /* Warn once when raised above threshold */
log_warn("WARNING: Thin pool %s metadata is now %.2f%% full.",
device, dm_percent_to_float(state->metadata_percent));
- if (state->metadata_percent >= state->metadata_percent_check) {
- /*
- * Usage has raised more than CHECK_STEP since the last
- * time. Run actions.
- */
- state->metadata_percent_check = (state->metadata_percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
-
- needs_policy = 1;
- }
+ if (state->metadata_percent > CHECK_MINIMUM) {
+ /* Run action when usage raised more than CHECK_STEP since the last time */
+ if (state->metadata_percent > state->metadata_percent_check)
+ needs_policy = 1;
+ state->metadata_percent_check = (state->metadata_percent / CHECK_STEP + 1) * CHECK_STEP;
+ if (state->metadata_percent_check == DM_PERCENT_100)
+ state->metadata_percent_check--; /* Can't get bigger then 100% */
+ } else
+ state->metadata_percent_check = CHECK_MINIMUM;
state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
if (state->data_percent <= WARNING_THRESH)
@@ -265,15 +271,15 @@ void process_event(struct dm_task *dmt,
else if (!state->data_warn_once++)
log_warn("WARNING: Thin pool %s data is now %.2f%% full.",
device, dm_percent_to_float(state->data_percent));
- if (state->data_percent >= state->data_percent_check) {
- /*
- * Usage has raised more than CHECK_STEP since
- * the last time. Run actions.
- */
- state->data_percent_check = (state->data_percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
-
- needs_policy = 1;
- }
+ if (state->data_percent > CHECK_MINIMUM) {
+ /* Run action when usage raised more than CHECK_STEP since the last time */
+ if (state->data_percent > state->data_percent_check)
+ needs_policy = 1;
+ state->data_percent_check = (state->data_percent / CHECK_STEP + 1) * CHECK_STEP;
+ if (state->data_percent_check == DM_PERCENT_100)
+ state->data_percent_check--; /* Can't get bigger then 100% */
+ } else
+ state->data_percent_check = CHECK_MINIMUM;
/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
* Avoids too high number of error retries, yet shows some status messages in log regularly.
@@ -372,8 +378,6 @@ int register_device(const char *device,
_init_thread_signals(state);
}
- state->metadata_percent_check = CHECK_MINIMUM;
- state->data_percent_check = CHECK_MINIMUM;
state->pid = -1;
*user = state;
6 years
master - dmeventd_thin: drop umounting on error path
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=8b95551ade0af5...
Commit: 8b95551ade0af5c1ef93f044c4508134f359e242
Parent: 43e3268adacbb3cd7b173e24c3423cf9d6807526
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jan 20 23:06:45 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jan 20 23:58:56 2017 +0100
dmeventd_thin: drop umounting on error path
Default internal logic will stop trying to do any 'rescue' action
when executed command fails.
This will be now fully in hands of external script if such
behaviour is needed.
---
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 259 +------------------------
1 files changed, 2 insertions(+), 257 deletions(-)
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index e1b1f77..bd70e78 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -67,246 +67,6 @@ DM_EVENT_LOG_FN("thin")
#define UUID_PREFIX "LVM-"
-/* Figure out device UUID has LVM- prefix and is OPEN */
-static int _has_unmountable_prefix(int major, int minor)
-{
- struct dm_task *dmt;
- struct dm_info info;
- const char *uuid;
- int r = 0;
-
- if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
- return_0;
-
- if (!dm_task_set_major_minor(dmt, major, minor, 1))
- goto_out;
-
- if (!dm_task_no_flush(dmt))
- stack;
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, &info))
- goto out;
-
- if (!info.exists || !info.open_count)
- goto out; /* Not open -> not mounted */
-
- if (!(uuid = dm_task_get_uuid(dmt)))
- goto out;
-
- /* Check it's public mountable LV
- * has prefix LVM- and UUID size is 68 chars */
- if (memcmp(uuid, UUID_PREFIX, sizeof(UUID_PREFIX) - 1) ||
- strlen(uuid) != 68)
- goto out;
-
-#if THIN_DEBUG
- log_debug("Found logical volume %s (%u:%u).", uuid, major, minor);
-#endif
- r = 1;
-out:
- dm_task_destroy(dmt);
-
- return r;
-}
-
-/* Get dependencies for device, and try to find matching device */
-static int _has_deps(const char *name, int tp_major, int tp_minor, int *dev_minor)
-{
- struct dm_task *dmt;
- const struct dm_deps *deps;
- struct dm_info info;
- int major, minor;
- int r = 0;
-
- if (!(dmt = dm_task_create(DM_DEVICE_DEPS)))
- return 0;
-
- if (!dm_task_set_name(dmt, name))
- goto out;
-
- if (!dm_task_no_open_count(dmt))
- goto out;
-
- if (!dm_task_run(dmt))
- goto out;
-
- if (!dm_task_get_info(dmt, &info))
- goto out;
-
- if (!(deps = dm_task_get_deps(dmt)))
- goto out;
-
- if (!info.exists || deps->count != 1)
- goto out;
-
- major = (int) MAJOR(deps->device[0]);
- minor = (int) MINOR(deps->device[0]);
- if ((major != tp_major) || (minor != tp_minor))
- goto out;
-
- *dev_minor = info.minor;
-
- if (!_has_unmountable_prefix(major, info.minor))
- goto out;
-
-#if THIN_DEBUG
- {
- char dev_name[PATH_MAX];
- if (dm_device_get_name(major, minor, 0, dev_name, sizeof(dev_name)))
- log_debug("Found %s (%u:%u) depends on %s.",
- name, major, *dev_minor, dev_name);
- }
-#endif
- r = 1;
-out:
- dm_task_destroy(dmt);
-
- return r;
-}
-
-/* Get all active devices */
-static int _find_all_devs(dm_bitset_t bs, int tp_major, int tp_minor)
-{
- struct dm_task *dmt;
- struct dm_names *names;
- unsigned next = 0;
- int minor, r = 1;
-
- if (!(dmt = dm_task_create(DM_DEVICE_LIST)))
- return 0;
-
- if (!dm_task_run(dmt)) {
- r = 0;
- goto out;
- }
-
- if (!(names = dm_task_get_names(dmt))) {
- r = 0;
- goto out;
- }
-
- if (!names->dev)
- goto out;
-
- do {
- names = (struct dm_names *)((char *) names + next);
- if (_has_deps(names->name, tp_major, tp_minor, &minor))
- dm_bit_set(bs, minor);
- next = names->next;
- } while (next);
-
-out:
- dm_task_destroy(dmt);
-
- return r;
-}
-
-static int _run(const char *cmd, ...)
-{
- va_list ap;
- int argc = 1; /* for argv[0], i.e. cmd */
- int i = 0;
- const char **argv;
- pid_t pid = fork();
- int status;
-
- if (pid == 0) { /* child */
- va_start(ap, cmd);
- while (va_arg(ap, const char *))
- ++argc;
- va_end(ap);
-
- /* + 1 for the terminating NULL */
- argv = alloca(sizeof(const char *) * (argc + 1));
-
- argv[0] = cmd;
- va_start(ap, cmd);
- while ((argv[++i] = va_arg(ap, const char *)));
- va_end(ap);
-
- execvp(cmd, (char **)argv);
- log_sys_error("exec", cmd);
- exit(127);
- }
-
- if (pid > 0) { /* parent */
- if (waitpid(pid, &status, 0) != pid)
- return 0; /* waitpid failed */
- if (!WIFEXITED(status) || WEXITSTATUS(status))
- return 0; /* the child failed */
- }
-
- if (pid < 0)
- return 0; /* fork failed */
-
- return 1; /* all good */
-}
-
-struct mountinfo_s {
- const char *device;
- struct dm_info info;
- dm_bitset_t minors; /* Bitset for active thin pool minors */
-};
-
-static int _umount_device(char *buffer, unsigned major, unsigned minor,
- char *target, void *cb_data)
-{
- struct mountinfo_s *data = cb_data;
- char *words[10];
-
- if ((major == data->info.major) && dm_bit(data->minors, minor)) {
- if (dm_split_words(buffer, DM_ARRAY_SIZE(words), 0, words) < DM_ARRAY_SIZE(words))
- words[9] = NULL; /* just don't show device name */
- log_info("Unmounting thin %s (%d:%d) of thin pool %s (%u:%u) from mount point \"%s\".",
- words[9] ? : "", major, minor, data->device,
- data->info.major, data->info.minor,
- target);
- if (!_run(UMOUNT_COMMAND, "-fl", target, NULL))
- log_error("Failed to lazy umount thin %s (%d:%d) from %s: %s.",
- words[9], major, minor, target, strerror(errno));
- }
-
- return 1;
-}
-
-/*
- * Find all thin pool LV users and try to umount them.
- * TODO: work with read-only thin pool support
- */
-static void _umount(struct dm_task *dmt)
-{
- /* TODO: Convert to use hash to reduce memory usage */
- static const size_t MINORS = (1U << 20); /* 20 bit */
- struct mountinfo_s data = { NULL };
-
- if (!dm_task_get_info(dmt, &data.info))
- return;
-
- data.device = dm_task_get_name(dmt);
-
- if (!(data.minors = dm_bitset_create(NULL, MINORS))) {
- log_error("Failed to allocate bitset. Not unmounting %s.", data.device);
- goto out;
- }
-
- if (!_find_all_devs(data.minors, data.info.major, data.info.minor)) {
- log_error("Failed to detect mounted volumes for %s.", data.device);
- goto out;
- }
-
- if (!dm_mountinfo_read(_umount_device, &data)) {
- log_error("Could not parse mountinfo file.");
- goto out;
- }
-
-out:
- if (data.minors)
- dm_bitset_destroy(data.minors);
-}
-
static int _run_command(struct dso_state *state)
{
char val[2][36];
@@ -407,7 +167,6 @@ void process_event(struct dm_task *dmt,
char *target_type = NULL;
char *params;
int needs_policy = 0;
- int needs_umount = 0;
struct dm_task *new_dmt = NULL;
#if THIN_DEBUG
@@ -461,7 +220,6 @@ void process_event(struct dm_task *dmt,
if (!dm_get_status_thin_pool(state->mem, params, &tps)) {
log_error("Failed to parse status.");
- needs_umount = 1;
goto out;
}
@@ -499,9 +257,6 @@ void process_event(struct dm_task *dmt,
state->metadata_percent_check = (state->metadata_percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
needs_policy = 1;
-
- if (state->metadata_percent >= UMOUNT_THRESH)
- needs_umount = 1;
}
state->data_percent = dm_make_percent(tps->used_data_blocks, tps->total_data_blocks);
@@ -518,9 +273,6 @@ void process_event(struct dm_task *dmt,
state->data_percent_check = (state->data_percent / CHECK_STEP) * CHECK_STEP + CHECK_STEP;
needs_policy = 1;
-
- if (state->data_percent >= UMOUNT_THRESH)
- needs_umount = 1;
}
/* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
@@ -539,16 +291,9 @@ void process_event(struct dm_task *dmt,
} else
state->max_fails = 1; /* Reset on success */
- if (needs_policy &&
- _use_policy(dmt, state))
- needs_umount = 0; /* No umount when command was successful */
+ if (needs_policy)
+ _use_policy(dmt, state);
out:
- if (needs_umount) {
- _umount(dmt);
- /* Until something changes, do not retry any more actions */
- state->data_percent_check = state->metadata_percent_check = (DM_PERCENT_1 * 101);
- }
-
if (tps)
dm_pool_free(state->mem, tps);
6 years
master - dmeventd_thin: rework failure handling
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=43e3268adacbb3...
Commit: 43e3268adacbb3cd7b173e24c3423cf9d6807526
Parent: 46c23dfb874ab8cebf1b335ef517095ff7bfdd81
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jan 20 22:53:55 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jan 20 23:56:39 2017 +0100
dmeventd_thin: rework failure handling
Instead of stopping monitoring after couple failing retries,
keep monitoring forever, just make larger delays between command
retries (ATM upto ~42 minutes).
So syslog is not spammed too often, yet commands have a chance to
be retried and succeed eventually...
---
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 28 +++++++++++++++++-------
1 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index bdccac6..e1b1f77 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -40,7 +40,7 @@
#define UMOUNT_COMMAND "/bin/umount"
-#define MAX_FAILS (10)
+#define MAX_FAILS (256) /* ~42 mins between cmd call retry with 10s delay */
#define THIN_DEBUG 0
@@ -55,6 +55,7 @@ struct dso_state {
uint64_t known_metadata_size;
uint64_t known_data_size;
unsigned fails;
+ unsigned max_fails;
int restore_sigset;
sigset_t old_sigset;
pid_t pid;
@@ -475,11 +476,13 @@ void process_event(struct dm_task *dmt,
if (state->known_metadata_size != tps->total_metadata_blocks) {
state->metadata_percent_check = CHECK_MINIMUM;
state->known_metadata_size = tps->total_metadata_blocks;
+ state->fails = 0;
}
if (state->known_data_size != tps->total_data_blocks) {
state->data_percent_check = CHECK_MINIMUM;
state->known_data_size = tps->total_data_blocks;
+ state->fails = 0;
}
state->metadata_percent = dm_make_percent(tps->used_metadata_blocks, tps->total_metadata_blocks);
@@ -520,6 +523,22 @@ void process_event(struct dm_task *dmt,
needs_umount = 1;
}
+ /* Reduce number of _use_policy() calls by power-of-2 factor till frequency of MAX_FAILS is reached.
+ * Avoids too high number of error retries, yet shows some status messages in log regularly.
+ * i.e. PV could have been pvmoved and VG/LV was locked for a while...
+ */
+ if (state->fails) {
+ if (state->fails++ <= state->max_fails) {
+ log_debug("Postponing frequently failing policy (%u <= %u).",
+ state->fails - 1, state->max_fails);
+ return;
+ }
+ if (state->max_fails < MAX_FAILS)
+ state->max_fails <<= 1;
+ state->fails = needs_policy = 1; /* Retry failing command */
+ } else
+ state->max_fails = 1; /* Reset on success */
+
if (needs_policy &&
_use_policy(dmt, state))
needs_umount = 0; /* No umount when command was successful */
@@ -533,13 +552,6 @@ out:
if (tps)
dm_pool_free(state->mem, tps);
- if (state->fails >= MAX_FAILS) {
- log_warn("WARNING: Dropping monitoring of %s. "
- "lvm2 command fails too often (%u times in row).",
- device, state->fails);
- pthread_kill(pthread_self(), SIGALRM);
- }
-
if (new_dmt)
dm_task_destroy(new_dmt);
}
6 years
master - dmeventd_thin: SIGCHLD handler
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=46c23dfb874ab8...
Commit: 46c23dfb874ab8cebf1b335ef517095ff7bfdd81
Parent: bc7a1d70d4936fd892223686388fd6fe5c8c3934
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Jan 18 09:55:46 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jan 20 23:55:51 2017 +0100
dmeventd_thin: SIGCHLD handler
To improve reaction time on when child is finished,
lets handle SIGCHLD in particular thread.
Let's hope kernel will route SIGCHLD to matching thread.
---
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 40 +++++++++++++++++++++++++
1 files changed, 40 insertions(+), 0 deletions(-)
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index 86a2115..bdccac6 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -55,6 +55,8 @@ struct dso_state {
uint64_t known_metadata_size;
uint64_t known_data_size;
unsigned fails;
+ int restore_sigset;
+ sigset_t old_sigset;
pid_t pid;
char **argv;
char cmd_str[1024];
@@ -542,6 +544,41 @@ out:
dm_task_destroy(new_dmt);
}
+/* Handle SIGCHLD for a thread */
+static void _sig_child(int signum __attribute__((unused)))
+{
+ /* empty SIG_IGN */;
+}
+
+/* Setup handler for SIGCHLD when executing external command
+ * to get quick 'waitpid()' reaction
+ * It will interrupt syscall just like SIGALRM and
+ * invoke process_event().
+ */
+static void _init_thread_signals(struct dso_state *state)
+{
+ struct sigaction act = { .sa_handler = _sig_child };
+ sigset_t my_sigset;
+
+ sigemptyset(&my_sigset);
+
+ if (sigaction(SIGCHLD, &act, NULL))
+ log_warn("WARNING: Failed to set SIGCHLD action.");
+ else if (sigaddset(&my_sigset, SIGCHLD))
+ log_warn("WARNING: Failed to add SIGCHLD to set.");
+ else if (pthread_sigmask(SIG_UNBLOCK, &my_sigset, &state->old_sigset))
+ log_warn("WARNING: Failed to unblock SIGCHLD.");
+ else
+ state->restore_sigset = 1;
+}
+
+static void _restore_thread_signals(struct dso_state *state)
+{
+ if (state->restore_sigset &&
+ pthread_sigmask(SIG_SETMASK, &state->old_sigset, NULL))
+ log_warn("WARNING: Failed to block SIGCHLD.");
+}
+
int register_device(const char *device,
const char *uuid __attribute__((unused)),
int major __attribute__((unused)),
@@ -575,6 +612,7 @@ int register_device(const char *device,
}
dm_split_words(str, maxcmd - 1, 0, state->argv);
+ _init_thread_signals(state);
}
state->metadata_percent_check = CHECK_MINIMUM;
@@ -619,6 +657,8 @@ int unregister_device(const char *device,
if (state->pid != -1)
log_warn("WARNING: Cannot kill child %d!", state->pid);
+ _restore_thread_signals(state);
+
dmeventd_lvm2_exit_with_pool(state);
log_info("No longer monitoring thin pool %s.", device);
6 years
master - dmeventd_thin: init command
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=bc7a1d70d4936f...
Commit: bc7a1d70d4936fd892223686388fd6fe5c8c3934
Parent: 14746a6c0025fad0d918bff7f1ee105e0eee10c3
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jan 20 21:50:23 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jan 20 23:55:50 2017 +0100
dmeventd_thin: init command
When dmeventd configured command does not start with 'lvm ' prefix,
it's going to be an 'external' command.
In this case we split command by spaces to argv strings.
---
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index 74b010a..86a2115 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -549,6 +549,8 @@ int register_device(const char *device,
void **user)
{
struct dso_state *state;
+ int maxcmd;
+ char *str;
if (!dmeventd_lvm2_init_with_pool("thin_pool_state", state))
goto_bad;
@@ -561,6 +563,20 @@ int register_device(const char *device,
goto_bad;
}
+ if (strncmp(state->cmd_str, "lvm ", 4)) {
+ maxcmd = 2; /* space for last NULL element */
+ for (str = state->cmd_str; *str; str++)
+ if (*str == ' ')
+ maxcmd++;
+ if (!(str = dm_pool_strdup(state->mem, state->cmd_str)) ||
+ !(state->argv = dm_pool_zalloc(state->mem, maxcmd * sizeof(char *)))) {
+ log_error("Failed to allocate memory for command.");
+ goto bad;
+ }
+
+ dm_split_words(str, maxcmd - 1, 0, state->argv);
+ }
+
state->metadata_percent_check = CHECK_MINIMUM;
state->data_percent_check = CHECK_MINIMUM;
state->pid = -1;
6 years
master - dmeventd_thin: add wait_pid
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=14746a6c0025fa...
Commit: 14746a6c0025fad0d918bff7f1ee105e0eee10c3
Parent: 2e935c0967e8bd3f97614c258619ad0c83fe0a48
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Fri Jan 20 21:42:55 2017 +0100
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Fri Jan 20 23:55:50 2017 +0100
dmeventd_thin: add wait_pid
Add support handling command exit.
---
daemons/dmeventd/plugins/thin/dmeventd_thin.c | 55 +++++++++++++++++++++++++
1 files changed, 55 insertions(+), 0 deletions(-)
diff --git a/daemons/dmeventd/plugins/thin/dmeventd_thin.c b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
index 3e044ff..74b010a 100644
--- a/daemons/dmeventd/plugins/thin/dmeventd_thin.c
+++ b/daemons/dmeventd/plugins/thin/dmeventd_thin.c
@@ -363,6 +363,35 @@ static int _use_policy(struct dm_task *dmt, struct dso_state *state)
return 1;
}
+/* Check if executed command has finished
+ * Only 1 command may run */
+static int _wait_for_pid(struct dso_state *state)
+{
+ int status = 0;
+
+ if (state->pid == -1)
+ return 1;
+
+ if (!waitpid(state->pid, &status, WNOHANG))
+ return 0;
+
+ /* Wait for finish */
+ if (WIFEXITED(status)) {
+ log_verbose("Child %d exited with status %d.",
+ state->pid, WEXITSTATUS(status));
+ state->fails = WEXITSTATUS(status) ? 1 : 0;
+ } else {
+ if (WIFSIGNALED(status))
+ log_verbose("Child %d was terminated with status %d.",
+ state->pid, WTERMSIG(status));
+ state->fails = 1;
+ }
+
+ state->pid = -1;
+
+ return 1;
+}
+
void process_event(struct dm_task *dmt,
enum dm_event_mask event __attribute__((unused)),
void **user)
@@ -383,6 +412,11 @@ void process_event(struct dm_task *dmt,
dm_percent_to_float(state->data_percent_check),
dm_percent_to_float(state->metadata_percent_check));
#endif
+ if (!_wait_for_pid(state)) {
+ log_warn("WARNING: Skipping event, child %d is still running (%s).",
+ state->pid, state->cmd_str);
+ return;
+ }
if (event & DM_EVENT_DEVICE_ERROR) {
/* Error -> no need to check and do instant resize */
@@ -529,6 +563,7 @@ int register_device(const char *device,
state->metadata_percent_check = CHECK_MINIMUM;
state->data_percent_check = CHECK_MINIMUM;
+ state->pid = -1;
*user = state;
log_info("Monitoring thin pool %s.", device);
@@ -547,6 +582,26 @@ int unregister_device(const char *device,
void **user)
{
struct dso_state *state = *user;
+ int i;
+
+ for (i = 0; !_wait_for_pid(state) && (i < 6); ++i) {
+ if (i == 0)
+ /* Give it 2 seconds, then try to terminate & kill it */
+ log_verbose("Child %d still not finished (%s) waiting.",
+ state->pid, state->cmd_str);
+ else if (i == 3) {
+ log_warn("WARNING: Terminating child %d.", state->pid);
+ kill(state->pid, SIGINT);
+ kill(state->pid, SIGTERM);
+ } else if (i == 5) {
+ log_warn("WARNING: Killing child %d.", state->pid);
+ kill(state->pid, SIGKILL);
+ }
+ sleep(1);
+ }
+
+ if (state->pid != -1)
+ log_warn("WARNING: Cannot kill child %d!", state->pid);
dmeventd_lvm2_exit_with_pool(state);
log_info("No longer monitoring thin pool %s.", device);
6 years