ike-sa-manager: Store a reference to the thread that checked out an IKE_SA

This could be helpful when debugging deadlocks that manifest around
wait_for_entry(), as it helps identifying other involved threads (the
thread object is seen in the thread_main() call in each thread's backtrace).
This commit is contained in:
Tobias Brunner 2016-02-10 16:41:52 +01:00
parent 963b080810
commit c674233804

View File

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2005-2011 Martin Willi * Copyright (C) 2005-2011 Martin Willi
* Copyright (C) 2011 revosec AG * Copyright (C) 2011 revosec AG
* Copyright (C) 2008-2015 Tobias Brunner * Copyright (C) 2008-2016 Tobias Brunner
* Copyright (C) 2005 Jan Hutter * Copyright (C) 2005 Jan Hutter
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
@ -23,6 +23,7 @@
#include <daemon.h> #include <daemon.h>
#include <sa/ike_sa_id.h> #include <sa/ike_sa_id.h>
#include <bus/bus.h> #include <bus/bus.h>
#include <threading/thread.h>
#include <threading/condvar.h> #include <threading/condvar.h>
#include <threading/mutex.h> #include <threading/mutex.h>
#include <threading/rwlock.h> #include <threading/rwlock.h>
@ -57,9 +58,9 @@ struct entry_t {
condvar_t *condvar; condvar_t *condvar;
/** /**
* Is this ike_sa currently checked out? * Thread by which this IKE_SA is currently checked out, if any
*/ */
bool checked_out; thread_t *checked_out;
/** /**
* Does this SA drives out new threads? * Does this SA drives out new threads?
@ -1148,7 +1149,7 @@ METHOD(ike_sa_manager_t, checkout, ike_sa_t*,
{ {
if (wait_for_entry(this, entry, segment)) if (wait_for_entry(this, entry, segment))
{ {
entry->checked_out = TRUE; entry->checked_out = thread_current();
ike_sa = entry->ike_sa; ike_sa = entry->ike_sa;
DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out", DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
@ -1292,7 +1293,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
entry->init_hash = hash; entry->init_hash = hash;
segment = put_entry(this, entry); segment = put_entry(this, entry);
entry->checked_out = TRUE; entry->checked_out = thread_current();
unlock_single_segment(this, segment); unlock_single_segment(this, segment);
DBG2(DBG_MGR, "created IKE_SA %s[%u]", DBG2(DBG_MGR, "created IKE_SA %s[%u]",
@ -1347,7 +1348,7 @@ METHOD(ike_sa_manager_t, checkout_by_message, ike_sa_t*,
ike_sa_id_t *ike_id; ike_sa_id_t *ike_id;
ike_id = entry->ike_sa->get_id(entry->ike_sa); ike_id = entry->ike_sa->get_id(entry->ike_sa);
entry->checked_out = TRUE; entry->checked_out = thread_current();
if (message->get_first_payload_type(message) != PLV1_FRAGMENT && if (message->get_first_payload_type(message) != PLV1_FRAGMENT &&
message->get_first_payload_type(message) != PLV2_FRAGMENT) message->get_first_payload_type(message) != PLV2_FRAGMENT)
{ /* TODO-FRAG: this fails if there are unencrypted payloads */ { /* TODO-FRAG: this fails if there are unencrypted payloads */
@ -1410,7 +1411,7 @@ METHOD(ike_sa_manager_t, checkout_by_config, ike_sa_t*,
current_ike = current_peer->get_ike_cfg(current_peer); current_ike = current_peer->get_ike_cfg(current_peer);
if (current_ike->equals(current_ike, peer_cfg->get_ike_cfg(peer_cfg))) if (current_ike->equals(current_ike, peer_cfg->get_ike_cfg(peer_cfg)))
{ {
entry->checked_out = TRUE; entry->checked_out = thread_current();
ike_sa = entry->ike_sa; ike_sa = entry->ike_sa;
DBG2(DBG_MGR, "found existing IKE_SA %u with a '%s' config", DBG2(DBG_MGR, "found existing IKE_SA %u with a '%s' config",
ike_sa->get_unique_id(ike_sa), ike_sa->get_unique_id(ike_sa),
@ -1449,7 +1450,7 @@ METHOD(ike_sa_manager_t, checkout_by_id, ike_sa_t*,
if (entry->ike_sa->get_unique_id(entry->ike_sa) == id) if (entry->ike_sa->get_unique_id(entry->ike_sa) == id)
{ {
ike_sa = entry->ike_sa; ike_sa = entry->ike_sa;
entry->checked_out = TRUE; entry->checked_out = thread_current();
break; break;
} }
/* other threads might be waiting for this entry */ /* other threads might be waiting for this entry */
@ -1505,7 +1506,7 @@ METHOD(ike_sa_manager_t, checkout_by_name, ike_sa_t*,
/* got one, return */ /* got one, return */
if (ike_sa) if (ike_sa)
{ {
entry->checked_out = TRUE; entry->checked_out = thread_current();
DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out", DBG2(DBG_MGR, "IKE_SA %s[%u] successfully checked out",
ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa)); ike_sa->get_name(ike_sa), ike_sa->get_unique_id(ike_sa));
break; break;
@ -1597,7 +1598,7 @@ METHOD(ike_sa_manager_t, checkin, void,
/* ike_sa_id must be updated */ /* ike_sa_id must be updated */
entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa)); entry->ike_sa_id->replace_values(entry->ike_sa_id, ike_sa->get_id(ike_sa));
/* signal waiting threads */ /* signal waiting threads */
entry->checked_out = FALSE; entry->checked_out = NULL;
entry->processing = -1; entry->processing = -1;
/* check if this SA is half-open */ /* check if this SA is half-open */
if (entry->half_open && ike_sa->get_state(ike_sa) != IKE_CONNECTING) if (entry->half_open && ike_sa->get_state(ike_sa) != IKE_CONNECTING)
@ -1656,7 +1657,7 @@ METHOD(ike_sa_manager_t, checkin, void,
* thread can acquire it. Since it is not yet in the list of * thread can acquire it. Since it is not yet in the list of
* connected peers that will not cause a deadlock as no other * connected peers that will not cause a deadlock as no other
* caller of check_unqiueness() will try to check out this SA */ * caller of check_unqiueness() will try to check out this SA */
entry->checked_out = TRUE; entry->checked_out = thread_current();
unlock_single_segment(this, segment); unlock_single_segment(this, segment);
this->public.check_uniqueness(&this->public, ike_sa, TRUE); this->public.check_uniqueness(&this->public, ike_sa, TRUE);
@ -1667,7 +1668,7 @@ METHOD(ike_sa_manager_t, checkin, void,
* thread is waiting, but it should still exist, so there is no * thread is waiting, but it should still exist, so there is no
* need for a lookup via get_entry_by... */ * need for a lookup via get_entry_by... */
lock_single_segment(this, segment); lock_single_segment(this, segment);
entry->checked_out = FALSE; entry->checked_out = NULL;
/* We already signaled waiting threads above, we have to do that /* We already signaled waiting threads above, we have to do that
* again after checking the SA out and back in again. */ * again after checking the SA out and back in again. */
entry->condvar->signal(entry->condvar); entry->condvar->signal(entry->condvar);
@ -1711,7 +1712,7 @@ METHOD(ike_sa_manager_t, checkin_and_destroy, void,
{ /* it looks like flush() has been called and the SA is being deleted { /* it looks like flush() has been called and the SA is being deleted
* anyway, just check it in */ * anyway, just check it in */
DBG2(DBG_MGR, "ignored check-in and destroy of IKE_SA during shutdown"); DBG2(DBG_MGR, "ignored check-in and destroy of IKE_SA during shutdown");
entry->checked_out = FALSE; entry->checked_out = NULL;
entry->condvar->broadcast(entry->condvar); entry->condvar->broadcast(entry->condvar);
unlock_single_segment(this, segment); unlock_single_segment(this, segment);
return; return;