master - dmeventd: exit on idle
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=2af696c32f99b2...
Commit: 2af696c32f99b2951bcc7e2a73130e46dc4f383f
Parent: 4284ba65ebe6401b2dbedc9abe850b650ed68f93
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 20:36:46 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:43:03 2015 +0200
dmeventd: exit on idle
Implementing exit when 'dmeventd' is idle.
Default idle timeout set to 1 hour - after this time period
dmeventd will cleanly exit.
On systems with 'systemd' - service is automatically started with
next contact on dmeventd communication socket/fifo.
On other systems - new dmeventd starts again when lvm2 command detects
its missing and monitoring is needed.
---
WHATS_NEW_DM | 1 +
daemons/dmeventd/dmeventd.c | 35 +++++++++++++++++++++++++++--------
2 files changed, 28 insertions(+), 8 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 8524a6d..910f6d6 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.110 -
======================================
+ Support exit on idle for dmenventd (1 hour).
Add support to allow unmonitor device from plugin itself.
New design for thread co-operation in dmeventd.
Dmeventd read device status with 'noflush'.
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index a7c1c6e..606ef30 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -87,11 +87,15 @@ static pthread_mutex_t _global_mutex;
static const size_t THREAD_STACK_SIZE = 300 * 1024;
+/* Default idle exit timeout 1 hour (in seconds) */
+static const time_t DMEVENTD_IDLE_EXIT_TIMEOUT = 60 * 60;
+
static int _debug_level = 0;
static int _use_syslog = 1;
static int _systemd_activation = 0;
static int _foreground = 0;
static int _restart = 0;
+static time_t _idle_since = 0;
static char **_initial_registrations = 0;
/* FIXME Make configurable at runtime */
@@ -279,6 +283,7 @@ static void _lib_put(struct dso_data *data)
DEBUGLOG("Unholding control device.");
dm_hold_control_dev(0);
dm_lib_release();
+ _idle_since = time(NULL);
}
}
}
@@ -346,6 +351,7 @@ static struct dso_data *_load_dso(struct message_data *data)
if (dm_list_empty(&_dso_registry)) {
DEBUGLOG("Holding control device open.");
dm_hold_control_dev(1);
+ _idle_since = 0;
}
/*
@@ -2106,7 +2112,7 @@ int main(int argc, char *argv[])
.client_path = DM_EVENT_FIFO_CLIENT,
.server_path = DM_EVENT_FIFO_SERVER
};
- int nothreads;
+ time_t now, idle_exit_timeout = DMEVENTD_IDLE_EXIT_TIMEOUT;
//struct sys_log logdata = {DAEMON_NAME, LOG_DAEMON};
opterr = 0;
@@ -2197,23 +2203,36 @@ int main(int argc, char *argv[])
kill(getppid(), SIGTERM);
log_notice("dmeventd ready for processing.");
+ _idle_since = time(NULL);
+
if (_initial_registrations)
_process_initial_registrations();
for (;;) {
- if (_exit_now) {
+ if (_idle_since) {
+ if (_exit_now) {
+ log_info("dmeventd detected break while being idle "
+ "for %ld second(s), exiting.",
+ (long) (time(NULL) - _idle_since));
+ break;
+ } else if (idle_exit_timeout) {
+ now = time(NULL);
+ if (now < _idle_since)
+ _idle_since = now; /* clock change? */
+ now -= _idle_since;
+ if (now >= idle_exit_timeout) {
+ log_info("dmeventd was idle for %ld second(s), "
+ "exiting.", (long) now);
+ break;
+ }
+ }
+ } else if (_exit_now) {
_exit_now = 0;
/*
* When '_exit_now' is set, signal has been received,
* but can not simply exit unless all
* threads are done processing.
*/
- _lock_mutex();
- nothreads = (dm_list_empty(&_thread_registry) &&
- dm_list_empty(&_thread_registry_unused));
- _unlock_mutex();
- if (nothreads)
- break;
log_warn("WARNING: There are still devices being monitored.");
log_warn("WARNING: Refusing to exit.");
}
8 years, 7 months
master - dmeventd: debug signals
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=4284ba65ebe640...
Commit: 4284ba65ebe6401b2dbedc9abe850b650ed68f93
Parent: aeec62ad1987a5ec59b782f3377d6ae1693e1eab
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 11:15:53 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:41:12 2015 +0200
dmeventd: debug signals
---
daemons/dmeventd/dmeventd.c | 20 ++++++++++++++++++++
1 files changed, 20 insertions(+), 0 deletions(-)
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index 2706ad6..a7c1c6e 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -789,6 +789,23 @@ static void _unregister_for_timeout(struct thread_status *thread)
pthread_mutex_unlock(&_timeout_mutex);
}
+#ifdef DEBUG_SIGNALS
+/* Print list of signals within a signal set */
+static void _print_sigset(const char *prefix, const sigset_t *sigset)
+{
+ int sig, cnt = 0;
+
+ for (sig = 1; sig < NSIG; sig++)
+ if (!sigismember(sigset, sig)) {
+ cnt++;
+ log_debug("%s%d (%s)", prefix, sig, strsignal(sig));
+ }
+
+ if (!cnt)
+ log_debug("%s<empty signal set>", prefix);
+}
+#endif
+
static sigset_t _unblock_sigalrm(void)
{
sigset_t set, old;
@@ -844,6 +861,9 @@ static int _event_wait(struct thread_status *thread)
pthread_sigmask(SIG_SETMASK, &set, NULL);
+#ifdef DEBUG_SIGNALS
+ _print_sigset("dmeventd blocking ", &set);
+#endif
DEBUGLOG("Completed waitevent task for %s.", thread->device.name);
return ret;
8 years, 7 months
master - dmeventd: snapshot plugin unmonitor
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=aeec62ad1987a5...
Commit: aeec62ad1987a5ec59b782f3377d6ae1693e1eab
Parent: 12aa56d29867b962257d7d2789a661a22c649347
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 15:36:21 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:41:12 2015 +0200
dmeventd: snapshot plugin unmonitor
Send signal to itself to mark plugin as 'finished' as
the watching rule is no longer usable.
---
.../dmeventd/plugins/snapshot/dmeventd_snapshot.c | 10 ++++++++++
1 files changed, 10 insertions(+), 0 deletions(-)
diff --git a/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c b/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
index d9bef5c..7962e96 100644
--- a/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
+++ b/daemons/dmeventd/plugins/snapshot/dmeventd_snapshot.c
@@ -18,6 +18,7 @@
#include <sys/wait.h>
#include <stdarg.h>
+#include <pthread.h>
/* First warning when snapshot is 80% full. */
#define WARNING_THRESH (DM_PERCENT_1 * 80)
@@ -203,6 +204,15 @@ void process_event(struct dm_task *dmt,
/* Maybe configurable ? */
_remove(dm_task_get_uuid(dmt));
#endif
+ pthread_kill(pthread_self(), SIGALRM);
+ goto out;
+ }
+
+ if (length <= (status->used_sectors - status->metadata_sectors)) {
+ /* TODO eventually recognize earlier when room is enough */
+ log_info("Dropping monitoring of fully provisioned snapshot %s.",
+ device);
+ pthread_kill(pthread_self(), SIGALRM);
goto out;
}
8 years, 7 months
master - dmeventd: handle signal from plugin
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=12aa56d29867b9...
Commit: 12aa56d29867b962257d7d2789a661a22c649347
Parent: 9156c5d0888bf95b79d931682b51fc63c96ba236
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 15:48:14 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:40:07 2015 +0200
dmeventd: handle signal from plugin
Add support to unmonitor device when monitor recognizes there is
nothing to monitor anymore.
TODO: possibly API change with return value could be also used.
---
WHATS_NEW_DM | 3 ++-
daemons/dmeventd/dmeventd.c | 11 +++++++++++
2 files changed, 13 insertions(+), 1 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 8c27139..8524a6d 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,6 +1,7 @@
Version 1.02.110 -
======================================
- New design for thread cooperation in dmeventd.
+ Add support to allow unmonitor device from plugin itself.
+ New design for thread co-operation in dmeventd.
Dmeventd read device status with 'noflush'.
Dmeventd closes control device when no device is monitored.
Thin plugin for dmeventd improved percentage usage.
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index d8c317e..2706ad6 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -973,6 +973,17 @@ static void *_monitor_thread(void *arg)
_lock_mutex();
thread->processing = 0;
+
+ /*
+ * Thread can terminate itself from plugin via SIGALRM
+ * Timer thread will not send signal while processing
+ * TODO: maybe worth API change and return value for
+ * _do_process_event() instead of this signal solution
+ */
+ if (sigpending(&pendmask) < 0)
+ log_sys_error("sigpending", "");
+ else if (sigismember(&pendmask, SIGALRM))
+ break;
} else {
_unlock_mutex();
8 years, 7 months
master - dmeventd: rework locking code
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=9156c5d0888bf9...
Commit: 9156c5d0888bf95b79d931682b51fc63c96ba236
Parent: 466a1c72b7f24be4c932b503b3f8a3fb50a2eda5
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 15:47:53 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:39:24 2015 +0200
dmeventd: rework locking code
Redesign threading code:
- plugin registration runs within its new created thread for
improved parallel usage.
- wait task is created just once and used during whole plugin lifetime.
- event thread is based over 'events' filter being set - when
filter is 0, such thread is 'unused'.
- event loop is simplified.
- timeout thread is never signaling 'processing' thread.
- pending of events filter cnange is properly reported and
running event thread is signalled when possible.
- helgrind is not reporting problems.
---
WHATS_NEW_DM | 1 +
daemons/dmeventd/dmeventd.c | 497 ++++++++++++++++++++-----------------------
2 files changed, 231 insertions(+), 267 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 5f92657..8c27139 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.110 -
======================================
+ New design for thread cooperation in dmeventd.
Dmeventd read device status with 'noflush'.
Dmeventd closes control device when no device is monitored.
Thin plugin for dmeventd improved percentage usage.
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index 8267dc4..d8c317e 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -85,23 +85,6 @@ static volatile sig_atomic_t _exit_now = 0; /* set to '1' when signal is given t
*/
static pthread_mutex_t _global_mutex;
-/*
- There are three states a thread can attain (see struct
- thread_status, field int status):
-
- - DM_THREAD_RUNNING: thread has started up and is either working or
- waiting for events... transitions to either SHUTDOWN or DONE
- - DM_THREAD_SHUTDOWN: thread is still doing something, but it is
- supposed to terminate (and transition to DONE) as soon as it
- finishes whatever it was doing at the point of flipping state to
- SHUTDOWN... the thread is still on the thread list
- - DM_THREAD_DONE: thread has terminated and has been moved over to
- unused thread list, cleanup pending
- */
-#define DM_THREAD_RUNNING 0
-#define DM_THREAD_SHUTDOWN 1
-#define DM_THREAD_DONE 2
-
static const size_t THREAD_STACK_SIZE = 300 * 1024;
static int _debug_level = 0;
@@ -204,6 +187,13 @@ struct message_data {
struct dm_event_daemon_message *msg; /* Pointer to message buffer. */
};
+/* There are three states a thread can attain. */
+enum {
+ DM_THREAD_REGISTERING, /* Registering, transitions to RUNNING */
+ DM_THREAD_RUNNING, /* Working on events, transitions to DONE */
+ DM_THREAD_DONE /* Terminated and cleanup is pending */
+};
+
/*
* Housekeeping of thread+device states.
*
@@ -222,18 +212,19 @@ struct thread_status {
char *name;
int major, minor;
} device;
- uint32_t event_nr; /* event number */
int processing; /* Set when event is being processed */
- int status; /* see DM_THREAD_{RUNNING,SHUTDOWN,DONE}
- constants above */
- enum dm_event_mask events; /* bitfield for event filter. */
- enum dm_event_mask current_events; /* bitfield for occured events. */
- struct dm_task *current_task;
+ int status; /* See DM_THREAD_{REGISTERING,RUNNING,DONE} */
+
+ int events; /* bitfield for event filter. */
+ int current_events; /* bitfield for occured events. */
+ struct dm_task *wait_task;
+ int pending; /* Set when event filter change is pending */
time_t next_time;
uint32_t timeout;
struct dm_list timeout_list;
void *dso_private; /* dso per-thread status variable */
+ /* TODO per-thread mutex */
};
static DM_LIST_INIT(_thread_registry);
static DM_LIST_INIT(_thread_registry_unused);
@@ -379,34 +370,57 @@ bad:
/* Allocate/free the thread status structure for a monitoring thread. */
static void _free_thread_status(struct thread_status *thread)
{
+
_lib_put(thread->dso_data);
- if (thread->current_task)
- dm_task_destroy(thread->current_task);
+ if (thread->wait_task)
+ dm_task_destroy(thread->wait_task);
dm_free(thread->device.uuid);
dm_free(thread->device.name);
dm_free(thread);
}
-/* Allocate/free the status structure for a monitoring thread. */
+/* Note: events_field must not be 0, ensured by caller */
static struct thread_status *_alloc_thread_status(const struct message_data *data,
struct dso_data *dso_data)
{
- struct thread_status *ret;
-
- if (!(ret = dm_zalloc(sizeof(*ret))))
- return NULL;
+ struct thread_status *thread;
- if (!(ret->device.uuid = dm_strdup(data->device_uuid))) {
- dm_free(ret);
+ if (!(thread = dm_zalloc(sizeof(*thread)))) {
+ log_error("Cannot create new thread, out of memory.");
return NULL;
}
- ret->dso_data = dso_data;
- ret->events = data->events_field;
- ret->timeout = data->timeout_secs;
- dm_list_init(&ret->timeout_list);
+ _lib_get(dso_data);
+ thread->dso_data = dso_data;
- return ret;
+ if (!(thread->wait_task = dm_task_create(DM_DEVICE_WAITEVENT)))
+ goto_out;
+
+ if (!dm_task_set_uuid(thread->wait_task, data->device_uuid))
+ goto_out;
+
+ if (!(thread->device.uuid = dm_strdup(data->device_uuid)))
+ goto_out;
+
+ /* Until real name resolved, use UUID */
+ if (!(thread->device.name = dm_strdup(data->device_uuid)))
+ goto_out;
+
+ /* runs ioctl and may register lvm2 pluging */
+ thread->processing = 1;
+ thread->status = DM_THREAD_REGISTERING;
+
+ thread->events = data->events_field;
+ thread->pending = DM_EVENT_REGISTRATION_PENDING;
+ thread->timeout = data->timeout_secs;
+ dm_list_init(&thread->timeout_list);
+
+ return thread;
+
+out:
+ _free_thread_status(thread);
+
+ return NULL;
}
/*
@@ -563,6 +577,8 @@ static int _fill_device_data(struct thread_status *ts)
ts->device.major = dmi.major;
ts->device.minor = dmi.minor;
+ dm_task_set_event_nr(ts->wait_task, dmi.event_nr);
+
ret = 1;
fail:
dm_task_destroy(dmt);
@@ -711,8 +727,17 @@ static void *_timeout_thread(void *unused __attribute__((unused)))
dm_list_iterate_items_gen(thread, &_timeout_registry, timeout_list) {
if (thread->next_time <= curr_time) {
thread->next_time = curr_time + thread->timeout;
- DEBUGLOG("Sending SIGALRM to Thr %x for timeout.", (int) thread->thread);
- pthread_kill(thread->thread, SIGALRM);
+ _lock_mutex();
+ if (thread->processing) {
+ /* Cannot signal processing monitoring thread */
+ log_debug("Skipping SIGALRM to processing Thr %x for timeout.",
+ (int) thread->thread);
+ } else {
+ DEBUGLOG("Sending SIGALRM to Thr %x for timeout.",
+ (int) thread->thread);
+ pthread_kill(thread->thread, SIGALRM);
+ }
+ _unlock_mutex();
}
if (thread->next_time < timeout.tv_sec || !timeout.tv_sec)
@@ -781,69 +806,45 @@ enum {
};
/* Wait on a device until an event occurs. */
-static int _event_wait(struct thread_status *thread, struct dm_task **task)
+static int _event_wait(struct thread_status *thread)
{
sigset_t set;
int ret = DM_WAIT_RETRY;
- struct dm_task *dmt;
struct dm_info info;
- int ioctl_errno;
-
- *task = 0;
- DEBUGLOG("Preparing waitevent task for %s", thread->device.uuid);
- if (!(dmt = dm_task_create(DM_DEVICE_WAITEVENT)))
- return DM_WAIT_RETRY;
+ /* TODO: audit libdm thread usage */
- thread->current_task = dmt;
-
- if (!dm_task_set_uuid(dmt, thread->device.uuid) ||
- !dm_task_set_event_nr(dmt, thread->event_nr))
- goto out;
-
- /*
- * Check if there are already some waiting events,
- * in this case the logging is unmodified.
- * TODO: audit libdm thread usage
- */
- DEBUGLOG("Starting waitevent task for %s", thread->device.uuid);
/*
* This is so that you can break out of waiting on an event,
* either for a timeout event, or to cancel the thread.
*/
set = _unblock_sigalrm();
- if (dm_task_run(dmt)) {
+
+ if (dm_task_run(thread->wait_task)) {
thread->current_events |= DM_EVENT_DEVICE_ERROR;
ret = DM_WAIT_INTR;
-
- if ((ret = dm_task_get_info(dmt, &info)))
- thread->event_nr = info.event_nr;
+ /* Update event_nr */
+ if (dm_task_get_info(thread->wait_task, &info))
+ dm_task_set_event_nr(thread->wait_task, info.event_nr);
} else {
- ioctl_errno = dm_task_get_errno(dmt);
- if (thread->events & DM_EVENT_TIMEOUT && ioctl_errno == EINTR) {
+ switch (dm_task_get_errno(thread->wait_task)) {
+ case ENXIO:
+ log_error("%s disappeared, detaching.",
+ thread->device.name);
+ ret = DM_WAIT_FATAL;
+ break;
+ case EINTR:
thread->current_events |= DM_EVENT_TIMEOUT;
ret = DM_WAIT_INTR;
- } else if (thread->status == DM_THREAD_SHUTDOWN && ioctl_errno == EINTR)
- ret = DM_WAIT_FATAL;
- else {
- if (ioctl_errno == ENXIO) {
- log_error("%s disappeared, detaching.",
- thread->device.name);
- ret = DM_WAIT_FATAL;
- } else
- log_sys_error("dm_task_run", "");
+ break;
+ default:
+ log_sys_error("dm_task_run", "waitevent");
}
}
- DEBUGLOG("Completed waitevent task for %s", thread->device.uuid);
pthread_sigmask(SIG_SETMASK, &set, NULL);
- out:
- if (ret == DM_WAIT_FATAL || ret == DM_WAIT_RETRY) {
- dm_task_destroy(dmt);
- thread->current_task = NULL;
- } else
- *task = dmt;
+ DEBUGLOG("Completed waitevent task for %s.", thread->device.name);
return ret;
}
@@ -869,9 +870,27 @@ static int _do_unregister_device(struct thread_status *thread)
}
/* Process an event in the DSO. */
-static void _do_process_event(struct thread_status *thread, struct dm_task *task)
+static void _do_process_event(struct thread_status *thread)
{
- thread->dso_data->process_event(task, thread->current_events, &(thread->dso_private));
+ struct dm_task *task;
+
+ /* NOTE: timeout event gets status */
+ task = (thread->current_events & DM_EVENT_TIMEOUT)
+ ? _get_device_status(thread) : thread->wait_task;
+
+ if (!task)
+ log_error("Lost event in Thr %x.", (int)thread->thread);
+ else {
+ thread->dso_data->process_event(task, thread->current_events, &(thread->dso_private));
+ if (task != thread->wait_task)
+ dm_task_destroy(task);
+ }
+}
+
+static void _thread_unused(struct thread_status *thread)
+{
+ UNLINK_THREAD(thread);
+ LINK(thread, &_thread_registry_unused);
}
/* Thread cleanup handler to unregister device. */
@@ -879,36 +898,30 @@ static void _monitor_unregister(void *arg)
{
struct thread_status *thread = arg, *thread_iter;
- DEBUGLOG("_monitor_unregister thread cleanup handler running");
- if (!_do_unregister_device(thread))
+ dm_list_iterate_items(thread_iter, &_thread_registry)
+ if (thread_iter == thread) {
+ /* Relink to _unused */
+ _thread_unused(thread);
+ break;
+ }
+
+ thread->pending = 0; /* Event pending resolved */
+ thread->processing = 1; /* Process unregistering */
+
+ _unlock_mutex();
+
+ DEBUGLOG("Unregistering monitor for %s.", thread->device.name);
+ _unregister_for_timeout(thread);
+
+ if ((thread->status != DM_THREAD_REGISTERING) &&
+ !_do_unregister_device(thread))
log_error("%s: %s unregister failed.", __func__,
thread->device.name);
- if (thread->current_task) {
- dm_task_destroy(thread->current_task);
- thread->current_task = NULL;
- }
- _lock_mutex();
- if (thread->events & DM_EVENT_TIMEOUT) {
- /* _unregister_for_timeout locks another mutex, we
- don't want to deadlock so we release our mutex for
- a bit */
- _unlock_mutex();
- _unregister_for_timeout(thread);
- _lock_mutex();
- }
- /* we may have been relinked to unused registry since we were
- called, so check that */
- dm_list_iterate_items(thread_iter, &_thread_registry_unused)
- if (thread_iter == thread) {
- thread->status = DM_THREAD_DONE;
- _unlock_mutex();
- return;
- }
DEBUGLOG("Marking Thr %x as DONE and unused.", (int)thread->thread);
- thread->status = DM_THREAD_DONE;
- UNLINK_THREAD(thread);
- LINK(thread, &_thread_registry_unused);
+
+ _lock_mutex();
+ thread->status = DM_THREAD_DONE; /* Last access to thread memory! */
_unlock_mutex();
}
@@ -916,80 +929,64 @@ static void _monitor_unregister(void *arg)
static void *_monitor_thread(void *arg)
{
struct thread_status *thread = arg;
- int wait_error;
- struct dm_task *task;
+ int ret;
+ sigset_t pendmask;
pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
pthread_cleanup_push(_monitor_unregister, thread);
- /* Wait for do_process_request() to finish its task. */
- _lock_mutex();
- thread->status = DM_THREAD_RUNNING;
- _unlock_mutex();
-
- /* Loop forever awaiting/analyzing device events. */
- while (1) {
- thread->current_events = 0;
+ if (!_fill_device_data(thread)) {
+ log_error("Failed to fill device data for %s.", thread->device.uuid);
+ _lock_mutex();
+ goto out;
+ }
- wait_error = _event_wait(thread, &task);
- if (wait_error == DM_WAIT_RETRY) {
- usleep(100); /* avoid busy loop */
- continue;
- }
+ if (!_do_register_device(thread)) {
+ log_error("Failed to register device %s.", thread->device.name);
+ _lock_mutex();
+ goto out;
+ }
- if (wait_error == DM_WAIT_FATAL)
- break;
+ _lock_mutex();
+ thread->status = DM_THREAD_RUNNING;
+ thread->processing = 0;
- /* Timeout occurred, task is not filled properly.
- * We get device status here for processing it in DSO.
- */
- if (wait_error == DM_WAIT_INTR &&
- thread->current_events & DM_EVENT_TIMEOUT) {
- dm_task_destroy(task);
- task = _get_device_status(thread);
- /* FIXME: syslog fail here ? */
- if (!(thread->current_task = task))
- continue;
- }
+ /* Loop awaiting/analyzing device events. */
+ while (thread->events) {
- /*
- * We know that wait succeeded and stored a
- * pointer to dm_task with device status into task.
- */
+ thread->pending = 0; /* Event is no longer pending... */
/*
- * Check against filter.
+ * Check against bitmask filter.
*
* If there's current events delivered from _event_wait() AND
* the device got registered for those events AND
* those events haven't been processed yet, call
* the DSO's process_event() handler.
*/
- _lock_mutex();
- if (thread->status == DM_THREAD_SHUTDOWN) {
- _unlock_mutex();
- break;
- }
-
if (thread->events & thread->current_events) {
- thread->processing = 1;
+ thread->processing = 1; /* Cannot be removed/signaled */
_unlock_mutex();
- _do_process_event(thread, task);
- dm_task_destroy(task);
- thread->current_task = NULL;
+ _do_process_event(thread);
+ thread->current_events = 0; /* Current events processed */
_lock_mutex();
thread->processing = 0;
- _unlock_mutex();
} else {
_unlock_mutex();
- dm_task_destroy(task);
- thread->current_task = NULL;
+
+ if ((ret = _event_wait(thread)) == DM_WAIT_RETRY)
+ usleep(100); /* Avoid busy loop, wait without mutex */
+
+ _lock_mutex();
+
+ if (ret == DM_WAIT_FATAL)
+ break;
}
}
+out:
- DEBUGLOG("Finished _monitor_thread.");
pthread_cleanup_pop(1);
return NULL;
@@ -1001,10 +998,36 @@ static int _create_thread(struct thread_status *thread)
return _pthread_create_smallstack(&thread->thread, _monitor_thread, thread);
}
-static int _terminate_thread(struct thread_status *thread)
+/* Update events - needs to be locked */
+static int _update_events(struct thread_status *thread, int events)
{
- DEBUGLOG("Sending SIGALRM to terminate Thr %x.", (int)thread->thread);
- return pthread_kill(thread->thread, SIGALRM);
+ int ret = 0;
+
+ if (thread->events == events)
+ return 0; /* Nothing has changed */
+
+ thread->events = events;
+ thread->pending = DM_EVENT_REGISTRATION_PENDING;
+
+ /* Only non-processing threads can be notified */
+ if (!thread->processing) {
+ DEBUGLOG("Sending SIGALRM to wakeup Thr %x.", (int)thread->thread);
+
+ /* Notify thread waiting in ioctl (to speed-up) */
+ if ((ret = pthread_kill(thread->thread, SIGALRM))) {
+ if (ret == ESRCH)
+ thread->events = 0; /* thread is gone */
+ else
+ log_error("Unable to wakeup thread: %s",
+ strerror(ret));
+ }
+ }
+
+ /* Threads with no events has to be moved to unused */
+ if (!thread->events)
+ _thread_unused(thread);
+
+ return -ret;
}
/* Return success on daemon active check. */
@@ -1020,8 +1043,8 @@ static int _active(struct message_data *message_data)
*/
static int _unregister_for_event(struct message_data *message_data)
{
- int ret = 0;
struct thread_status *thread;
+ int ret;
/*
* Clear event in bitfield and deactivate
@@ -1031,38 +1054,21 @@ static int _unregister_for_event(struct message_data *message_data)
if (!(thread = _lookup_thread_status(message_data))) {
_unlock_mutex();
- ret = -ENODEV;
- goto out;
+ return -ENODEV;
}
- if (thread->status == DM_THREAD_DONE) {
- /* the thread has terminated while we were not
- watching */
- _unlock_mutex();
- return 0;
- }
+ /* AND mask event ~# from events bitfield. */
+ ret = _update_events(thread, (thread->events & ~message_data->events_field));
- thread->events &= ~message_data->events_field;
+ _unlock_mutex();
- if (!(thread->events & DM_EVENT_TIMEOUT)) {
- _unlock_mutex();
+ /* If there are no events, thread is later garbage
+ * collected by _cleanup_unused_threads */
+ if (message_data->events_field & DM_EVENT_TIMEOUT)
_unregister_for_timeout(thread);
- _lock_mutex();
- }
- /*
- * In case there's no events to monitor on this device ->
- * unlink and terminate its monitoring thread.
- */
- if (!thread->events) {
- DEBUGLOG("Marking Thr %x unused (no events).", (int)thread->thread);
- UNLINK_THREAD(thread);
- LINK(thread, &_thread_registry_unused);
- }
- _unlock_mutex();
- DEBUGLOG("Unregistered uuid:%s.", thread->device.uuid);
+ DEBUGLOG("Unregistered event for %s.", thread->device.name);
- out:
return ret;
}
@@ -1082,73 +1088,52 @@ static int _register_for_event(struct message_data *message_data)
!(dso_data = _load_dso(message_data))) {
stack;
#ifdef ELIBACC
- ret = -ELIBACC;
+ ret = ELIBACC;
#else
- ret = -ENODEV;
+ ret = ENODEV;
#endif
return ret;
}
_lock_mutex();
- if ((thread = _lookup_thread_status(message_data)))
- /* Or event # into events bitfield. */
- thread->events |= message_data->events_field;
-
- _unlock_mutex();
+ if ((thread = _lookup_thread_status(message_data))) {
+ /* OR event # into events bitfield. */
+ ret = _update_events(thread, (thread->events | message_data->events_field));
+ } else {
+ _unlock_mutex();
- if (!thread) {
+ /* Only creating thread during event processing
+ * Remaining initialization happens within monitoring thread */
if (!(thread = _alloc_thread_status(message_data, dso_data))) {
stack;
return -ENOMEM;
}
- if (!_fill_device_data(thread)) {
- ret = -ENODEV;
- goto_out;
- }
-
- if (!_do_register_device(thread)) {
- ret = -ENOMEM;
- goto_out;
- }
-
- if ((ret = -_create_thread(thread))) {
- _do_unregister_device(thread);
- goto_out;
+ if ((ret = _create_thread(thread))) {
+ log_sys_error("pthread_create", "");
+ _free_thread_status(thread);
+ return -ret;
}
_lock_mutex();
- if (_lookup_thread_status(message_data)) {
- DEBUGLOG("Race, uuid already registered, marking Thr %x unused.",
- (int)thread->thread);
- thread->status = DM_THREAD_SHUTDOWN;
- thread->events = 0;
- LINK(thread, &_thread_registry_unused);
- _unlock_mutex();
- ret = -EEXIST; /* race ? */
- goto_out;
- }
-
+ /* Note: same uuid can't be added in parallel */
LINK_THREAD(thread);
- _unlock_mutex();
}
+ _unlock_mutex();
+
/* If creation of timeout thread fails (as it may), we fail
here completely. The client is responsible for either
retrying later or trying to register without timeout
events. However, if timeout thread cannot be started, it
usually means we are so starved on resources that we are
almost as good as dead already... */
- if ((thread->events & DM_EVENT_TIMEOUT) &&
- (ret = -_register_for_timeout(thread)))
+ if ((message_data->events_field & DM_EVENT_TIMEOUT) &&
+ (ret = _register_for_timeout(thread)))
_unregister_for_event(message_data);
- return ret;
-out:
- _free_thread_status(thread);
-
- return ret;
+ return -ret;
}
/*
@@ -1161,16 +1146,14 @@ static int _registered_device(struct message_data *message_data,
{
int r;
struct dm_event_daemon_message *msg = message_data->msg;
- unsigned events = ((thread->status == DM_THREAD_RUNNING) &&
- thread->events) ? thread->events :
- thread->events | DM_EVENT_REGISTRATION_PENDING;
dm_free(msg->data);
if ((r = dm_asprintf(&(msg->data), "%s %s %s %u",
message_data->id,
thread->dso_data->dso_name,
- thread->device.uuid, events)) < 0)
+ thread->device.uuid,
+ thread->events | thread->pending)) < 0)
return -ENOMEM;
msg->size = (uint32_t) r;
@@ -1182,7 +1165,6 @@ static int _registered_device(struct message_data *message_data,
static int _want_registered_device(char *dso_name, char *device_uuid,
struct thread_status *thread)
{
- DEBUGLOG("Looking for dso:%s uuid:%s.", dso_name, device_uuid);
/* If DSO names and device paths are equal. */
if (dso_name && device_uuid)
return !strcmp(dso_name, thread->dso_data->dso_name) &&
@@ -1625,58 +1607,39 @@ static void _process_initial_registrations(void)
static void _cleanup_unused_threads(void)
{
- int ret;
struct dm_list *l;
struct thread_status *thread;
- int join_ret = 0;
+ int ret;
_lock_mutex();
+
while ((l = dm_list_first(&_thread_registry_unused))) {
thread = dm_list_item(l, struct thread_status);
- if (thread->processing)
- break; /* cleanup on the next round */
+ if (thread->status != DM_THREAD_DONE) {
+ if (thread->processing)
+ break; /* cleanup on the next round */
- if (thread->status == DM_THREAD_RUNNING) {
- thread->status = DM_THREAD_SHUTDOWN;
- break;
- }
+ /* Signal possibly sleeping thread */
+ ret = pthread_kill(thread->thread, SIGALRM);
+ if (!ret || (ret != ESRCH))
+ break; /* check again on the next round */
- if (thread->status == DM_THREAD_SHUTDOWN) {
- if (!thread->events) {
- /* turn codes negative -- should we be returning this? */
- ret = _terminate_thread(thread);
+ /* thread is likely gone */
+ }
- if (ret == ESRCH) {
- thread->status = DM_THREAD_DONE;
- } else if (ret) {
- log_error("Unable to terminate thread: %s",
- strerror(ret));
- }
- break;
- }
+ dm_list_del(l);
+ _unlock_mutex();
- dm_list_del(l);
- log_error("thread can't be on unused list unless !thread->events");
- thread->status = DM_THREAD_RUNNING;
- LINK_THREAD(thread);
+ DEBUGLOG("Destroying Thr %x.", (int)thread->thread);
- continue;
- }
+ if (pthread_join(thread->thread, NULL))
+ log_sys_error("pthread_join", "");
- if (thread->status == DM_THREAD_DONE) {
- dm_list_del(l);
- _unlock_mutex();
- DEBUGLOG("Destroying Thr %x.", (int)thread->thread);
- join_ret = pthread_join(thread->thread, NULL);
- _free_thread_status(thread);
- _lock_mutex();
- }
+ _free_thread_status(thread);
+ _lock_mutex();
}
_unlock_mutex();
-
- if (join_ret)
- log_error("Failed pthread_join: %s.", strerror(join_ret));
}
static void _sig_alarm(int signum __attribute__((unused)))
8 years, 7 months
master - cleanup: use enums
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=466a1c72b7f24b...
Commit: 466a1c72b7f24be4c932b503b3f8a3fb50a2eda5
Parent: 81e9ab3156badecc6a64447708c4ae4886e3c244
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Wed Oct 21 20:56:20 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:36:00 2015 +0200
cleanup: use enums
---
daemons/dmeventd/dmeventd.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index cde4f93..8267dc4 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -102,7 +102,7 @@ static pthread_mutex_t _global_mutex;
#define DM_THREAD_SHUTDOWN 1
#define DM_THREAD_DONE 2
-#define THREAD_STACK_SIZE (300*1024)
+static const size_t THREAD_STACK_SIZE = 300 * 1024;
static int _debug_level = 0;
static int _use_syslog = 1;
@@ -774,9 +774,11 @@ static sigset_t _unblock_sigalrm(void)
return old;
}
-#define DM_WAIT_RETRY 0
-#define DM_WAIT_INTR 1
-#define DM_WAIT_FATAL 2
+enum {
+ DM_WAIT_RETRY,
+ DM_WAIT_INTR,
+ DM_WAIT_FATAL
+};
/* Wait on a device until an event occurs. */
static int _event_wait(struct thread_status *thread, struct dm_task **task)
8 years, 7 months
master - dmeventd: code mode _get_device_status
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=81e9ab3156bade...
Commit: 81e9ab3156badecc6a64447708c4ae4886e3c244
Parent: 15dbd4b56a65dba2f19bb1685529731faa9894c6
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 12:36:25 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:35:25 2015 +0200
dmeventd: code mode _get_device_status
Move _get_device_status() in code.
Use dm_task_no_flush() function when reading status.
(e.g. none blocking for thins pool)
---
WHATS_NEW_DM | 1 +
daemons/dmeventd/dmeventd.c | 44 +++++++++++++++++++++++-------------------
2 files changed, 25 insertions(+), 20 deletions(-)
diff --git a/WHATS_NEW_DM b/WHATS_NEW_DM
index 000bddd..5f92657 100644
--- a/WHATS_NEW_DM
+++ b/WHATS_NEW_DM
@@ -1,5 +1,6 @@
Version 1.02.110 -
======================================
+ Dmeventd read device status with 'noflush'.
Dmeventd closes control device when no device is monitored.
Thin plugin for dmeventd improved percentage usage.
Snapshot plugin for dmeventd improved percentage usage.
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index 26e611d..cde4f93 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -570,6 +570,30 @@ fail:
return ret;
}
+static struct dm_task *_get_device_status(struct thread_status *ts)
+{
+ struct dm_task *dmt = dm_task_create(DM_DEVICE_STATUS);
+
+ if (!dmt)
+ return_NULL;
+
+ if (!dm_task_set_uuid(dmt, ts->device.uuid)) {
+ dm_task_destroy(dmt);
+ return_NULL;
+ }
+
+ /* Non-blocking status read */
+ if (!dm_task_no_flush(dmt))
+ log_warn("WARNING: Can't set no_flush for dm status.");
+
+ if (!dm_task_run(dmt)) {
+ dm_task_destroy(dmt);
+ return_NULL;
+ }
+
+ return dmt;
+}
+
/*
* Find an existing thread for a device.
*
@@ -886,26 +910,6 @@ static void _monitor_unregister(void *arg)
_unlock_mutex();
}
-static struct dm_task *_get_device_status(struct thread_status *ts)
-{
- struct dm_task *dmt = dm_task_create(DM_DEVICE_STATUS);
-
- if (!dmt)
- return NULL;
-
- if (!dm_task_set_uuid(dmt, ts->device.uuid)) {
- dm_task_destroy(dmt);
- return NULL;
- }
-
- if (!dm_task_run(dmt)) {
- dm_task_destroy(dmt);
- return NULL;
- }
-
- return dmt;
-}
-
/* Device monitoring thread. */
static void *_monitor_thread(void *arg)
{
8 years, 7 months
master - dmeventd: minimize locking time for get_imeout
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=15dbd4b56a65db...
Commit: 15dbd4b56a65dba2f19bb1685529731faa9894c6
Parent: e2ea2a81476495f494915774c46c0b3c139d1c3f
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 12:38:26 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:34:30 2015 +0200
dmeventd: minimize locking time for get_imeout
Don't hold lock when creating message (allocating memory).
Thread cannot dissapear as it's only the same thread which
may clean it.
---
daemons/dmeventd/dmeventd.c | 18 +++++++++---------
1 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index 2f5fe67..26e611d 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -1292,18 +1292,18 @@ static int _get_timeout(struct message_data *message_data)
struct thread_status *thread;
struct dm_event_daemon_message *msg = message_data->msg;
- dm_free(msg->data);
-
_lock_mutex();
- if ((thread = _lookup_thread_status(message_data))) {
- msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32,
- message_data->id, thread->timeout);
- } else
- msg->data = NULL;
-
+ thread = _lookup_thread_status(message_data);
_unlock_mutex();
- return thread ? 0 : -ENODEV;
+ if (!thread)
+ return -ENODEV;
+
+ dm_free(msg->data);
+ msg->size = dm_asprintf(&(msg->data), "%s %" PRIu32,
+ message_data->id, thread->timeout);
+
+ return (msg->data && msg->size) ? 0 : -ENOMEM;
}
/* Open fifos used for client communication. */
8 years, 7 months
master - dmeventd: drop unneded test
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=e2ea2a81476495...
Commit: e2ea2a81476495f494915774c46c0b3c139d1c3f
Parent: 941c6354dbf783da17851be7e38f243334a4acd6
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 12:31:45 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:34:29 2015 +0200
dmeventd: drop unneded test
Function is never called without device.uuid.
---
daemons/dmeventd/dmeventd.c | 3 ---
1 files changed, 0 insertions(+), 3 deletions(-)
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index bbdee82..2f5fe67 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -545,9 +545,6 @@ static int _fill_device_data(struct thread_status *ts)
struct dm_info dmi;
int ret = 0;
- if (!ts->device.uuid)
- return 0;
-
if (!(dmt = dm_task_create(DM_DEVICE_INFO)))
return 0;
8 years, 7 months
master - dmeventd: wake up timer when setting new timeout
by Zdenek Kabelac
Gitweb: http://git.fedorahosted.org/git/?p=lvm2.git;a=commitdiff;h=941c6354dbf783...
Commit: 941c6354dbf783da17851be7e38f243334a4acd6
Parent: 02eb000f5145aa60578b4591053bff9a797e64cc
Author: Zdenek Kabelac <zkabelac(a)redhat.com>
AuthorDate: Thu Oct 22 12:37:18 2015 +0200
Committer: Zdenek Kabelac <zkabelac(a)redhat.com>
CommitterDate: Thu Oct 22 22:34:29 2015 +0200
dmeventd: wake up timer when setting new timeout
---
daemons/dmeventd/dmeventd.c | 15 ++++++++++++---
1 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index 885aa9d..bbdee82 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -1274,11 +1274,20 @@ static int _set_timeout(struct message_data *message_data)
struct thread_status *thread;
_lock_mutex();
- if ((thread = _lookup_thread_status(message_data)))
- thread->timeout = message_data->timeout_secs;
+ thread = _lookup_thread_status(message_data);
_unlock_mutex();
- return thread ? 0 : -ENODEV;
+ if (!thread)
+ return -ENODEV;
+
+ /* Lets reprogram timer */
+ pthread_mutex_lock(&_timeout_mutex);
+ thread->timeout = message_data->timeout_secs;
+ thread->next_time = 0;
+ pthread_cond_signal(&_timeout_cond);
+ pthread_mutex_unlock(&_timeout_mutex);
+
+ return 0;
}
static int _get_timeout(struct message_data *message_data)
8 years, 7 months