From 65b4202cdf1df8fdba26fe38ec50e239b7d5e8a4 Mon Sep 17 00:00:00 2001 From: Mark Haverkamp Date: Tue, 22 Nov 2005 21:20:35 +0000 Subject: [PATCH] Fix for Bug 875. Cleans up a channel that actually opened but the library request timed out. git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@844 fd59a12c-fef9-0310-b244-a6a79926bd2f --- exec/evt.c | 84 ++++++++++++++++++++++++++++------------------- include/ipc_evt.h | 7 +++- 2 files changed, 57 insertions(+), 34 deletions(-) diff --git a/exec/evt.c b/exec/evt.c index 11cac514..27ccdd6c 100644 --- a/exec/evt.c +++ b/exec/evt.c @@ -305,6 +305,7 @@ static int processed_open_counts = 0; * ocp_conn_info: conn_info for returning to the library. * ocp_open_flags: channel open flags * ocp_timer_handle: timer handle for sync open + * ocp_serial_no: Identifier for the request * ocp_entry: list entry for pending open list. */ struct open_chan_pending { @@ -315,8 +316,17 @@ struct open_chan_pending { SaEvtChannelOpenFlagsT ocp_open_flag; poll_timer_handle ocp_timer_handle; uint64_t ocp_c_handle; + uint64_t ocp_serial_no; struct list_head ocp_entry; }; +static uint64_t open_serial_no = 0; + +/* + * code to indicate that the open request has timed out. The + * invocation data element is used for this code since it is + * only used by the open async call which cannot have a timeout. + */ +#define OPEN_TIMED_OUT 0x5a6b5a6b5a6b5a6bLLU /* * list of pending channel opens @@ -1099,7 +1109,8 @@ static SaErrorT evt_open_channel(SaNameT *cn, SaUint8T flgs) cpkt.chc_head.id = MESSAGE_REQ_EXEC_EVT_CHANCMD; cpkt.chc_head.size = sizeof(cpkt); cpkt.chc_op = EVT_OPEN_CHAN_OP; - cpkt.u.chc_chan = *cn; + cpkt.u.chc_chan.ocr_name = *cn; + cpkt.u.chc_chan.ocr_serial_no = ++open_serial_no; chn_iovec.iov_base = &cpkt; chn_iovec.iov_len = cpkt.chc_head.size; log_printf(CHAN_OPEN_DEBUG, "evt_open_channel: Send open mcast\n"); @@ -2089,6 +2100,7 @@ static int lib_evt_open_channel(struct conn_info *conn_info, void *message) ocp->ocp_conn_info = conn_info; ocp->ocp_c_handle = req->ico_c_handle; ocp->ocp_timer_handle = 0; + ocp->ocp_serial_no = open_serial_no; list_init(&ocp->ocp_entry); list_add_tail(&ocp->ocp_entry, &open_pending); /* @@ -2127,8 +2139,6 @@ static int lib_evt_open_channel_async(struct conn_info *conn_info, struct req_evt_channel_open *req; struct res_evt_channel_open res; struct open_chan_pending *ocp; - int msec_in_future; - int ret; req = message; @@ -2166,24 +2176,9 @@ static int lib_evt_open_channel_async(struct conn_info *conn_info, ocp->ocp_open_flag = req->ico_open_flag; ocp->ocp_conn_info = conn_info; ocp->ocp_timer_handle = 0; + ocp->ocp_serial_no = open_serial_no; list_init(&ocp->ocp_entry); list_add_tail(&ocp->ocp_entry, &open_pending); - if (req->ico_timeout != 0) { - /* - * Time in nanoseconds - convert to miliseconds - */ - msec_in_future = (uint32_t)(req->ico_timeout / 1000000ULL); - ret = poll_timer_add(aisexec_poll_handle, - msec_in_future, - ocp, - chan_open_timeout, - &ocp->ocp_timer_handle); - if (ret != 0) { - log_printf(LOG_LEVEL_WARNING, - "Error setting timeout for open channel %s\n", - req->ico_channel_name.value); - } - } open_return: res.ico_head.size = sizeof(res); @@ -3271,7 +3266,9 @@ static int evt_remote_recovery_evt(void *msg, struct in_addr source_addr, /* - * Timeout handler for event channel open. + * Timeout handler for event channel open. We flag the structure + * as timed out. Then if the open request is ever returned, we can + * issue a close channel and keep the reference counting correct. */ static void chan_open_timeout(void *data) { @@ -3281,9 +3278,8 @@ static void chan_open_timeout(void *data) res.ico_head.size = sizeof(res); res.ico_head.id = MESSAGE_RES_EVT_OPEN_CHANNEL; res.ico_head.error = SA_AIS_ERR_TIMEOUT; + ocp->ocp_invocation = OPEN_TIMED_OUT; libais_send_response (ocp->ocp_conn_info, &res, sizeof(res)); - list_del(&ocp->ocp_entry); - free(ocp); } /* @@ -3300,17 +3296,35 @@ static void evt_chan_open_finish(struct open_chan_pending *ocp, int ret = 0; void *ptr; - log_printf(CHAN_OPEN_DEBUG, "Open channel finish %s\n", + log_printf(CHAN_OPEN_DEBUG, "Open channel finish %s\n", getSaNameT(&ocp->ocp_chan_name)); if (ocp->ocp_timer_handle) { ret = poll_timer_delete(aisexec_poll_handle, ocp->ocp_timer_handle); if (ret != 0 ) { - log_printf(LOG_LEVEL_WARNING, + log_printf(LOG_LEVEL_WARNING, "Error clearing timeout for open channel of %s\n", getSaNameT(&ocp->ocp_chan_name)); } } + /* + * If this is a finished open for a timed out request, then + * send out a close on this channel to clean things up. + */ + if (ocp->ocp_invocation == OPEN_TIMED_OUT) { + log_printf(CHAN_OPEN_DEBUG, "Closing timed out open of %s\n", + getSaNameT(&ocp->ocp_chan_name)); + error = evt_close_channel(&ocp->ocp_chan_name, EVT_CHAN_ACTIVE); + if (error != SA_AIS_OK) { + log_printf(CHAN_OPEN_DEBUG, + "Close of timed out open failed for %s\n", + getSaNameT(&ocp->ocp_chan_name)); + } + list_del(&ocp->ocp_entry); + free(ocp); + return; + } + /* * Create a handle to give back to the caller to associate * with this channel open instance. @@ -3438,7 +3452,9 @@ convert_chan_packet(struct req_evt_chan_command *cpkt) switch (cpkt->chc_op) { case EVT_OPEN_CHAN_OP: - cpkt->u.chc_chan.length = swab16(cpkt->u.chc_chan.length); + cpkt->u.chc_chan.ocr_name.length = + swab16(cpkt->u.chc_chan.ocr_name.length); + cpkt->u.chc_chan.ocr_serial_no = swab64(cpkt->u.chc_chan.ocr_serial_no); break; case EVT_UNLINK_CHAN_OP: @@ -3532,15 +3548,16 @@ static int evt_remote_chan_op(void *msg, struct in_addr source_addr, struct list_head *l, *nxt; log_printf(CHAN_OPEN_DEBUG, "Opening channel %s for node 0x%x\n", - cpkt->u.chc_chan.value, mn->mn_node_info.nodeId); - eci = find_channel(&cpkt->u.chc_chan, EVT_CHAN_ACTIVE); + cpkt->u.chc_chan.ocr_name.value, + mn->mn_node_info.nodeId); + eci = find_channel(&cpkt->u.chc_chan.ocr_name, EVT_CHAN_ACTIVE); if (!eci) { - eci = create_channel(&cpkt->u.chc_chan); + eci = create_channel(&cpkt->u.chc_chan.ocr_name); } if (!eci) { log_printf(LOG_LEVEL_WARNING, "Could not create channel %s\n", - getSaNameT(&cpkt->u.chc_chan)); + getSaNameT(&cpkt->u.chc_chan.ocr_name)); break; } @@ -3553,10 +3570,11 @@ static int evt_remote_chan_op(void *msg, struct in_addr source_addr, for (l = open_pending.next; l != &open_pending; l = nxt) { nxt = l->next; ocp = list_entry(l, struct open_chan_pending, ocp_entry); - log_printf(CHAN_OPEN_DEBUG, - "Compare channel %s %s\n", ocp->ocp_chan_name.value, - eci->esc_channel_name.value); - if (name_match(&ocp->ocp_chan_name, &eci->esc_channel_name)) { + log_printf(CHAN_OPEN_DEBUG, + "Compare channel req no %llu %llu\n", + ocp->ocp_serial_no, + cpkt->u.chc_chan.ocr_serial_no); + if (ocp->ocp_serial_no == cpkt->u.chc_chan.ocr_serial_no) { evt_chan_open_finish(ocp, eci); break; } diff --git a/include/ipc_evt.h b/include/ipc_evt.h index 6e121b9b..320a76a3 100644 --- a/include/ipc_evt.h +++ b/include/ipc_evt.h @@ -383,6 +383,11 @@ struct evt_close_unlink_chan { uint64_t chcu_unlink_id; }; +struct open_chan_req { + SaNameT ocr_name; + uint64_t ocr_serial_no; +}; + /* * Sent via MESSAGE_REQ_EXEC_EVT_CHANCMD * @@ -394,7 +399,7 @@ struct req_evt_chan_command { struct req_header chc_head; int chc_op; union { - SaNameT chc_chan; + struct open_chan_req chc_chan; SaEvtEventIdT chc_event_id; struct evt_set_id chc_set_id; struct evt_set_opens chc_set_opens;