From 57784d85969a0bcf8599442e3be5ae7edf1fbe10 Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Sat, 5 Aug 2017 10:05:44 -0600 Subject: irmd: Don't call ipcp_flow_dealloc under lock When a process was killed, ipcp_flow_dealloc was called under a lock, causing a deadlock in the IRMd because handling the IPCP response also needs to take the same lock (the IPCP calls flow_dealloc to finalize this). This deadlock also resulted in the IPCP always reporting that it failed to send a reply message as the deadlock effectively blocks the IRMd until its socket timeout expired and thus the IPCP was always responding to an already closed socket. --- src/irmd/main.c | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) (limited to 'src/irmd/main.c') diff --git a/src/irmd/main.c b/src/irmd/main.c index 96b0b729..a8ccccb2 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -1638,6 +1638,8 @@ void * irm_sanitize(void * o) pthread_rwlock_wrlock(&irmd.flows_lock); list_for_each_safe(p, h, &irmd.irm_flows) { + int ipcpi; + int port_id; struct irm_flow * f = list_entry(p, struct irm_flow, next); @@ -1645,9 +1647,13 @@ void * irm_sanitize(void * o) && ts_diff_ms(&f->t0, &now) > IRMD_FLOW_TIMEOUT) { log_dbg("Pending port_id %d timed out.", f->port_id); - f->n_1_api = -1; + f->n_api = -1; irm_flow_set_state(f, FLOW_DEALLOC_PENDING); - ipcp_flow_dealloc(f->n_1_api, f->port_id); + ipcpi = f->n_1_api; + port_id = f->port_id; + pthread_rwlock_unlock(&irmd.flows_lock); + ipcp_flow_dealloc(ipcpi, port_id); + pthread_rwlock_wrlock(&irmd.flows_lock); continue; } @@ -1660,7 +1666,11 @@ void * irm_sanitize(void * o) shm_flow_set_destroy(set); f->n_api = -1; irm_flow_set_state(f, FLOW_DEALLOC_PENDING); - ipcp_flow_dealloc(f->n_1_api, f->port_id); + ipcpi = f->n_1_api; + port_id = f->port_id; + pthread_rwlock_unlock(&irmd.flows_lock); + ipcp_flow_dealloc(ipcpi, port_id); + pthread_rwlock_wrlock(&irmd.flows_lock); continue; } -- cgit v1.2.3 From 3f9fb4c957e639b96df672190c9d03eec02dce3e Mon Sep 17 00:00:00 2001 From: Dimitri Staessens Date: Sat, 5 Aug 2017 12:15:52 -0600 Subject: irmd: Don't self-query an IPCP Upon flow_allocation, the IRMd queries IPCPs for the destination name. After this commit, when an IPCP allocates a flow, the IRMd won't query that IPCP. --- src/irmd/main.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'src/irmd/main.c') diff --git a/src/irmd/main.c b/src/irmd/main.c index a8ccccb2..3f83ab2c 100644 --- a/src/irmd/main.c +++ b/src/irmd/main.c @@ -222,7 +222,8 @@ static struct ipcp_entry * get_ipcp_entry_by_name(const char * name) return NULL; } -static struct ipcp_entry * get_ipcp_by_dst_name(const char * name) +static struct ipcp_entry * get_ipcp_by_dst_name(const char * name, + pid_t src) { struct list_head * p; struct list_head * h; @@ -233,7 +234,7 @@ static struct ipcp_entry * get_ipcp_by_dst_name(const char * name) list_for_each_safe(p, h, &irmd.ipcps) { struct ipcp_entry * e = list_entry(p, struct ipcp_entry, next); - if (e->dif_name == NULL) + if (e->dif_name == NULL || e->api == src) continue; hash = malloc(IPCP_HASH_LEN(e)); @@ -1103,7 +1104,7 @@ static int flow_alloc(pid_t api, int state; uint8_t * hash; - ipcp = get_ipcp_by_dst_name(dst); + ipcp = get_ipcp_by_dst_name(dst, api); if (ipcp == NULL) { log_info("Destination %s unreachable.", dst); return -1; @@ -1199,7 +1200,7 @@ static int flow_dealloc(pid_t api, if (irm_flow_get_state(f) == FLOW_DEALLOC_PENDING) { list_del(&f->next); if ((kill(f->n_api, 0) < 0 && f->n_1_api == -1) || - (kill (f->n_1_api, 0) < 0 && f->n_api == -1)) + (kill(f->n_1_api, 0) < 0 && f->n_api == -1)) irm_flow_set_state(f, FLOW_NULL); clear_irm_flow(f); irm_flow_destroy(f); -- cgit v1.2.3