1
0
mirror of git://sourceware.org/git/lvm2.git synced 2025-03-10 16:58:47 +03:00

dmeventd: Fix segfault in _timeout_thread

In case thread was found, or thread registration failed after
_register_for_timeout, thread_status was kept in timeout_list after
deallocation.
This commit is contained in:
Marian Csontos 2015-09-21 16:08:10 +02:00
parent 804c25a81a
commit f15db6bfa5

View File

@ -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;
}