summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarian Csontos <mcsontos@redhat.com>2015-09-21 16:08:10 +0200
committerMarian Csontos <mcsontos@redhat.com>2015-09-21 16:19:34 +0200
commitf15db6bfa545dc0438d25af0b5b0f0f2945ddbec (patch)
tree914603db553a6aa46ecd3a621934924385515f30
parent804c25a81a297753aa60f47f36c21149e9479c22 (diff)
downloadlvm2-dev-mcsontos-dmeventd-segfault.tar.gz
dmeventd: Fix segfault in _timeout_threaddev-mcsontos-dmeventd-segfault
In case thread was found, or thread registration failed after _register_for_timeout, thread_status was kept in timeout_list after deallocation.
-rw-r--r--daemons/dmeventd/dmeventd.c72
1 files changed, 44 insertions, 28 deletions
diff --git a/daemons/dmeventd/dmeventd.c b/daemons/dmeventd/dmeventd.c
index 1ff5bf9ec..3e020f2e3 100644
--- a/daemons/dmeventd/dmeventd.c
+++ b/daemons/dmeventd/dmeventd.c
@@ -1043,33 +1043,33 @@ static int _register_for_event(struct message_data *message_data)
goto out;
}
- /* Preallocate thread status struct to avoid deadlock. */
- if (!(thread_new = _alloc_thread_status(message_data, dso_data))) {
- stack;
- ret = -ENOMEM;
- goto out;
- }
-
- if (!_fill_device_data(thread_new)) {
- stack;
- ret = -ENODEV;
- goto out;
- }
-
- /* 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_new->events & DM_EVENT_TIMEOUT) &&
- (ret = -_register_for_timeout(thread_new)))
- goto out;
-
_lock_mutex();
if (!(thread = _lookup_thread_status(message_data))) {
_unlock_mutex();
+ /* Preallocate thread status struct to avoid deadlock. */
+ if (!(thread_new = _alloc_thread_status(message_data, dso_data))) {
+ stack;
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (!_fill_device_data(thread_new)) {
+ stack;
+ ret = -ENODEV;
+ goto out;
+ }
+
+ /* 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_new->events & DM_EVENT_TIMEOUT) &&
+ (ret = -_register_for_timeout(thread_new)))
+ goto out;
+
if (!(ret = _do_register_device(thread_new)))
goto out;
@@ -1081,24 +1081,40 @@ static int _register_for_event(struct message_data *message_data)
if ((ret = -_create_thread(thread))) {
_unlock_mutex();
_do_unregister_device(thread);
+ _unregister_for_timeout(thread);
_free_thread_status(thread);
goto out;
}
LINK_THREAD(thread);
+ _unlock_mutex();
+ } else {
+ /* Or event # into events bitfield. */
+ thread->events |= message_data->events_field;
+ if ((thread->events & DM_EVENT_TIMEOUT)) {
+ _unlock_mutex();
+ if (!(ret = -_register_for_timeout(thread_new))) {
+ /* In case previous calls failed we do not
+ * force unregister event. Reset events for
+ * consistency. */
+ _lock_mutex();
+ thread->events &= ~DM_EVENT_TIMEOUT;
+ _unlock_mutex();
+ }
+ } else {
+ _unlock_mutex();
+ }
}
- /* Or event # into events bitfield. */
- thread->events |= message_data->events_field;
- _unlock_mutex();
-
out:
/*
* Deallocate thread status after releasing
* the lock in case we haven't used it.
*/
- if (thread_new)
+ if (thread_new) {
+ _unregister_for_timeout(thread);
_free_thread_status(thread_new);
+ }
return ret;
}