mirror of
				https://git.proxmox.com/git/mirror_corosync
				synced 2025-11-04 13:15:00 +00:00 
			
		
		
		
	When corosync is during sync operation cmap_dispatch blocks. Signed-off-by: Jan Friesse <jfriesse@redhat.com>
		
			
				
	
	
		
			438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			438 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2015-2016 Red Hat, Inc.
 | 
						|
 *
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Author: Jan Friesse (jfriesse@redhat.com)
 | 
						|
 *
 | 
						|
 * This software licensed under BSD license, the text of which follows:
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions are met:
 | 
						|
 *
 | 
						|
 * - Redistributions of source code must retain the above copyright notice,
 | 
						|
 *   this list of conditions and the following disclaimer.
 | 
						|
 * - Redistributions in binary form must reproduce the above copyright notice,
 | 
						|
 *   this list of conditions and the following disclaimer in the documentation
 | 
						|
 *   and/or other materials provided with the distribution.
 | 
						|
 * - Neither the name of the Red Hat, Inc. nor the names of its
 | 
						|
 *   contributors may be used to endorse or promote products derived from this
 | 
						|
 *   software without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 | 
						|
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 | 
						|
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 | 
						|
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 | 
						|
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 | 
						|
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 | 
						|
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
						|
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
 | 
						|
 * THE POSSIBILITY OF SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include "qdevice-cmap.h"
 | 
						|
#include "qdevice-net-poll.h"
 | 
						|
#include "qdevice-log.h"
 | 
						|
#include "qdevice-net-send.h"
 | 
						|
#include "qdevice-net-socket.h"
 | 
						|
#include "qdevice-votequorum.h"
 | 
						|
#include "qdevice-ipc.h"
 | 
						|
#include "qdevice-net-poll-array-user-data.h"
 | 
						|
 | 
						|
/*
 | 
						|
 * Needed for creating nspr handle from unix fd
 | 
						|
 */
 | 
						|
#include <private/pprio.h>
 | 
						|
 | 
						|
static void
 | 
						|
qdevice_net_poll_read_socket(struct qdevice_net_instance *instance)
 | 
						|
{
 | 
						|
 | 
						|
	if (qdevice_net_socket_read(instance) == -1) {
 | 
						|
		instance->schedule_disconnect = 1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
qdevice_net_poll_read_votequorum(struct qdevice_net_instance *instance)
 | 
						|
{
 | 
						|
 | 
						|
	if (qdevice_votequorum_dispatch(instance->qdevice_instance_ptr) == -1) {
 | 
						|
		instance->schedule_disconnect = 1;
 | 
						|
		instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_COROSYNC_CONNECTION_CLOSED;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
qdevice_net_poll_read_cmap(struct qdevice_net_instance *instance)
 | 
						|
{
 | 
						|
 | 
						|
	if (qdevice_cmap_dispatch(instance->qdevice_instance_ptr) == -1) {
 | 
						|
		instance->schedule_disconnect = 1;
 | 
						|
		instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_COROSYNC_CONNECTION_CLOSED;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
qdevice_net_poll_write_socket(struct qdevice_net_instance *instance, const PRPollDesc *pfd)
 | 
						|
{
 | 
						|
	int res;
 | 
						|
 | 
						|
	if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) {
 | 
						|
		res = nss_sock_non_blocking_client_succeeded(pfd);
 | 
						|
		if (res == -1) {
 | 
						|
			/*
 | 
						|
			 * Connect failed -> try next
 | 
						|
			 */
 | 
						|
			res = nss_sock_non_blocking_client_try_next(&instance->non_blocking_client);
 | 
						|
			if (res == -1) {
 | 
						|
				qdevice_log_nss(LOG_ERR, "Can't connect to qnetd host.");
 | 
						|
				nss_sock_non_blocking_client_destroy(&instance->non_blocking_client);
 | 
						|
			}
 | 
						|
		} else if (res == 0) {
 | 
						|
			/*
 | 
						|
			 * Poll again
 | 
						|
			 */
 | 
						|
		} else if (res == 1) {
 | 
						|
			/*
 | 
						|
			 * Connect success
 | 
						|
			 */
 | 
						|
			instance->socket = instance->non_blocking_client.socket;
 | 
						|
			nss_sock_non_blocking_client_destroy(&instance->non_blocking_client);
 | 
						|
			instance->non_blocking_client.socket = NULL;
 | 
						|
 | 
						|
			instance->state = QDEVICE_NET_INSTANCE_STATE_SENDING_PREINIT_REPLY;
 | 
						|
 | 
						|
			qdevice_log(LOG_DEBUG, "Sending preinit msg to qnetd");
 | 
						|
			if (qdevice_net_send_preinit(instance) != 0) {
 | 
						|
				instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_CANT_ALLOCATE_MSG_BUFFER;
 | 
						|
				instance->schedule_disconnect = 1;
 | 
						|
			}
 | 
						|
		} else {
 | 
						|
			qdevice_log(LOG_CRIT, "Unhandled nss_sock_non_blocking_client_succeeded");
 | 
						|
			exit(1);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if (qdevice_net_socket_write(instance) == -1) {
 | 
						|
			instance->schedule_disconnect = 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
qdevice_net_poll_err_socket(struct qdevice_net_instance *instance, const PRPollDesc *pfd)
 | 
						|
{
 | 
						|
 | 
						|
	if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) {
 | 
						|
		/*
 | 
						|
		 * Workaround for RHEL<7. Pollout is never set for nonblocking connect (doesn't work
 | 
						|
		 * only with poll, select works as expected!???).
 | 
						|
		 * So test if client is still valid and if pollout was not already called (ensured
 | 
						|
		 * by default because of order in PR_Poll).
 | 
						|
		 * If both applies it's possible to emulate pollout set by calling poll_write.
 | 
						|
		 */
 | 
						|
		if (!instance->non_blocking_client.destroyed) {
 | 
						|
			qdevice_net_poll_write_socket(instance, pfd);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		qdevice_log(LOG_ERR, "POLL_ERR (%u) on main socket", pfd->out_flags);
 | 
						|
 | 
						|
		instance->schedule_disconnect = 1;
 | 
						|
		instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_SERVER_CLOSED_CONNECTION;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void
 | 
						|
qdevice_net_poll_read_ipc_socket(struct qdevice_net_instance *instance)
 | 
						|
{
 | 
						|
	struct unix_socket_client *client;
 | 
						|
	PRFileDesc *prfd;
 | 
						|
	struct qdevice_ipc_user_data *user_data;
 | 
						|
 | 
						|
	if (qdevice_ipc_accept(instance->qdevice_instance_ptr, &client) != 0) {
 | 
						|
		return ;
 | 
						|
	}
 | 
						|
 | 
						|
	prfd = PR_CreateSocketPollFd(client->socket);
 | 
						|
	if (prfd == NULL) {
 | 
						|
		qdevice_log_nss(LOG_CRIT, "Can't create NSPR poll fd for IPC client. "
 | 
						|
		    "Disconnecting client");
 | 
						|
		qdevice_ipc_client_disconnect(instance->qdevice_instance_ptr, client);
 | 
						|
 | 
						|
		return ;
 | 
						|
	}
 | 
						|
 | 
						|
	user_data = (struct qdevice_ipc_user_data *)client->user_data;
 | 
						|
	user_data->model_data = (void *)prfd;
 | 
						|
}
 | 
						|
 | 
						|
static PRPollDesc *
 | 
						|
qdevice_net_pr_poll_array_create(struct qdevice_net_instance *instance)
 | 
						|
{
 | 
						|
	struct pr_poll_array *poll_array;
 | 
						|
	PRPollDesc *poll_desc;
 | 
						|
	struct qdevice_net_poll_array_user_data *user_data;
 | 
						|
	struct unix_socket_client *ipc_client;
 | 
						|
	const struct unix_socket_client_list *ipc_client_list;
 | 
						|
	struct qdevice_ipc_user_data *qdevice_ipc_user_data;
 | 
						|
 | 
						|
	poll_array = &instance->poll_array;
 | 
						|
	ipc_client_list = &instance->qdevice_instance_ptr->local_ipc.clients;
 | 
						|
 | 
						|
	if (qdevice_ipc_is_closed(instance->qdevice_instance_ptr)) {
 | 
						|
		qdevice_log(LOG_DEBUG, "Local socket is closed");
 | 
						|
		instance->schedule_disconnect = 1;
 | 
						|
		instance->disconnect_reason = QDEVICE_NET_DISCONNECT_REASON_LOCAL_SOCKET_CLOSED;
 | 
						|
 | 
						|
		return (NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	pr_poll_array_clean(poll_array);
 | 
						|
 | 
						|
	if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
 | 
						|
		return (NULL);
 | 
						|
	}
 | 
						|
	poll_desc->fd = instance->votequorum_poll_fd;
 | 
						|
	poll_desc->in_flags = PR_POLL_READ;
 | 
						|
	user_data->type = QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_VOTEQUORUM;
 | 
						|
 | 
						|
	if (!instance->qdevice_instance_ptr->sync_in_progress) {
 | 
						|
		if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
 | 
						|
			return (NULL);
 | 
						|
		}
 | 
						|
		poll_desc->fd = instance->cmap_poll_fd;
 | 
						|
		poll_desc->in_flags = PR_POLL_READ;
 | 
						|
		user_data->type = QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_CMAP;
 | 
						|
	}
 | 
						|
 | 
						|
	if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
 | 
						|
		return (NULL);
 | 
						|
	}
 | 
						|
	poll_desc->fd = instance->ipc_socket_poll_fd;
 | 
						|
	poll_desc->in_flags = PR_POLL_READ;
 | 
						|
	user_data->type = QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET;
 | 
						|
 | 
						|
	if (instance->state != QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT ||
 | 
						|
	    !instance->non_blocking_client.destroyed) {
 | 
						|
		if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
 | 
						|
			return (NULL);
 | 
						|
		}
 | 
						|
 | 
						|
		user_data->type = QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_SOCKET;
 | 
						|
 | 
						|
		if (instance->state == QDEVICE_NET_INSTANCE_STATE_WAITING_CONNECT) {
 | 
						|
			poll_desc->fd = instance->non_blocking_client.socket;
 | 
						|
			poll_desc->in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
 | 
						|
		} else {
 | 
						|
			poll_desc->fd = instance->socket;
 | 
						|
			poll_desc->in_flags = PR_POLL_READ;
 | 
						|
 | 
						|
			if (!send_buffer_list_empty(&instance->send_buffer_list)) {
 | 
						|
				poll_desc->in_flags |= PR_POLL_WRITE;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	TAILQ_FOREACH(ipc_client, ipc_client_list, entries) {
 | 
						|
		if (!ipc_client->reading_line && !ipc_client->writing_buffer) {
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		if (pr_poll_array_add(poll_array, &poll_desc, (void **)&user_data) < 0) {
 | 
						|
			return (NULL);
 | 
						|
		}
 | 
						|
 | 
						|
		qdevice_ipc_user_data = (struct qdevice_ipc_user_data *)ipc_client->user_data;
 | 
						|
		poll_desc->fd = (PRFileDesc *)qdevice_ipc_user_data->model_data;
 | 
						|
		if (ipc_client->reading_line) {
 | 
						|
			poll_desc->in_flags |= PR_POLL_READ;
 | 
						|
		}
 | 
						|
 | 
						|
		if (ipc_client->writing_buffer) {
 | 
						|
			poll_desc->in_flags |= PR_POLL_WRITE;
 | 
						|
		}
 | 
						|
 | 
						|
		user_data->type = QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT;
 | 
						|
		user_data->ipc_client = ipc_client;
 | 
						|
	}
 | 
						|
 | 
						|
	pr_poll_array_gc(poll_array);
 | 
						|
 | 
						|
	return (poll_array->array);
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
qdevice_net_poll(struct qdevice_net_instance *instance)
 | 
						|
{
 | 
						|
	PRPollDesc *pfds;
 | 
						|
	PRFileDesc *prfd;
 | 
						|
	PRInt32 poll_res;
 | 
						|
	ssize_t i;
 | 
						|
	struct qdevice_net_poll_array_user_data *user_data;
 | 
						|
	struct unix_socket_client *ipc_client;
 | 
						|
	struct qdevice_ipc_user_data *qdevice_ipc_user_data;
 | 
						|
	int case_processed;
 | 
						|
 | 
						|
	pfds = qdevice_net_pr_poll_array_create(instance);
 | 
						|
	if (pfds == NULL) {
 | 
						|
		return (-1);
 | 
						|
	}
 | 
						|
 | 
						|
	instance->schedule_disconnect = 0;
 | 
						|
 | 
						|
	if ((poll_res = PR_Poll(pfds, pr_poll_array_size(&instance->poll_array),
 | 
						|
	    timer_list_time_to_expire(&instance->main_timer_list))) > 0) {
 | 
						|
		for (i = 0; i < pr_poll_array_size(&instance->poll_array); i++) {
 | 
						|
			user_data = pr_poll_array_get_user_data(&instance->poll_array, i);
 | 
						|
 | 
						|
			ipc_client = user_data->ipc_client;
 | 
						|
 | 
						|
			if (pfds[i].out_flags & PR_POLL_READ) {
 | 
						|
				case_processed = 0;
 | 
						|
 | 
						|
				switch (user_data->type) {
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_net_poll_read_socket(instance);
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_VOTEQUORUM:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_net_poll_read_votequorum(instance);
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_CMAP:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_net_poll_read_cmap(instance);
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_net_poll_read_ipc_socket(instance);
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_ipc_io_read(instance->qdevice_instance_ptr, ipc_client);
 | 
						|
					break;
 | 
						|
				/*
 | 
						|
				 * Default is not defined intentionally. Compiler shows warning when
 | 
						|
				 * new poll_array_user_data_type is added
 | 
						|
				 */
 | 
						|
				}
 | 
						|
 | 
						|
				if (!case_processed) {
 | 
						|
					qdevice_log(LOG_CRIT, "Unhandled read on poll descriptor %u", i);
 | 
						|
					exit(1);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (!instance->schedule_disconnect && pfds[i].out_flags & PR_POLL_WRITE) {
 | 
						|
				case_processed = 0;
 | 
						|
 | 
						|
				switch (user_data->type) {
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_net_poll_write_socket(instance, &pfds[i]);
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_ipc_io_write(instance->qdevice_instance_ptr, ipc_client);
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_VOTEQUORUM:
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_CMAP:
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
 | 
						|
					/*
 | 
						|
					 * Write on votequorum, cmap and ipc socket shouldn't happen.
 | 
						|
					 */
 | 
						|
					break;
 | 
						|
				/*
 | 
						|
				 * Default is not defined intentionally. Compiler shows warning when
 | 
						|
				 * new poll_array_user_data_type is added
 | 
						|
				 */
 | 
						|
				}
 | 
						|
 | 
						|
				if (!case_processed) {
 | 
						|
					qdevice_log(LOG_CRIT, "Unhandled write on poll descriptor %u", i);
 | 
						|
					exit(1);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (!instance->schedule_disconnect &&
 | 
						|
			    (pfds[i].out_flags & (PR_POLL_ERR|PR_POLL_NVAL|PR_POLL_HUP|PR_POLL_EXCEPT)) &&
 | 
						|
			    !(pfds[i].out_flags & (PR_POLL_READ|PR_POLL_WRITE))) {
 | 
						|
				case_processed = 0;
 | 
						|
 | 
						|
				switch (user_data->type) {
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_SOCKET:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_net_poll_err_socket(instance, &pfds[i]);
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_SOCKET:
 | 
						|
					case_processed = 1;
 | 
						|
					if (pfds[i].out_flags != PR_POLL_NVAL) {
 | 
						|
						qdevice_log(LOG_CRIT, "POLLERR (%u) on local socket",
 | 
						|
						    pfds[i].out_flags);
 | 
						|
						exit(1);
 | 
						|
					} else {
 | 
						|
						qdevice_log(LOG_DEBUG, "Local socket is closed");
 | 
						|
						instance->schedule_disconnect = 1;
 | 
						|
						instance->disconnect_reason =
 | 
						|
						    QDEVICE_NET_DISCONNECT_REASON_LOCAL_SOCKET_CLOSED;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_log(LOG_DEBUG, "POLL_ERR (%u) on ipc client socket. "
 | 
						|
					    "Disconnecting.",  pfds[i].out_flags);
 | 
						|
					ipc_client->schedule_disconnect = 1;
 | 
						|
					break;
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_VOTEQUORUM:
 | 
						|
				case QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_CMAP:
 | 
						|
					case_processed = 1;
 | 
						|
					qdevice_log(LOG_DEBUG, "POLL_ERR (%u) on corosync socket. "
 | 
						|
					    "Disconnecting.",  pfds[i].out_flags);
 | 
						|
 | 
						|
					instance->schedule_disconnect = 1;
 | 
						|
					instance->disconnect_reason =
 | 
						|
						QDEVICE_NET_DISCONNECT_REASON_COROSYNC_CONNECTION_CLOSED;
 | 
						|
					break;
 | 
						|
				/*
 | 
						|
				 * Default is not defined intentionally. Compiler shows warning when
 | 
						|
				 * new poll_array_user_data_type is added
 | 
						|
				 */
 | 
						|
				}
 | 
						|
 | 
						|
				if (!case_processed) {
 | 
						|
					qdevice_log(LOG_CRIT, "Unhandled error on poll descriptor %u", i);
 | 
						|
					exit(1);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (user_data->type == QDEVICE_NET_POLL_ARRAY_USER_DATA_TYPE_IPC_CLIENT &&
 | 
						|
			    ipc_client->schedule_disconnect) {
 | 
						|
				qdevice_ipc_user_data = (struct qdevice_ipc_user_data *)ipc_client->user_data;
 | 
						|
				prfd = (PRFileDesc *)qdevice_ipc_user_data->model_data;
 | 
						|
 | 
						|
				if (PR_DestroySocketPollFd(prfd) != PR_SUCCESS) {
 | 
						|
					qdevice_log_nss(LOG_WARNING, "Unable to destroy client IPC poll socket fd");
 | 
						|
				}
 | 
						|
 | 
						|
				qdevice_ipc_client_disconnect(instance->qdevice_instance_ptr, ipc_client);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!instance->schedule_disconnect) {
 | 
						|
		timer_list_expire(&instance->main_timer_list);
 | 
						|
	}
 | 
						|
 | 
						|
	if (instance->schedule_disconnect) {
 | 
						|
		/*
 | 
						|
		 * Schedule disconnect can be set by this function, by some timer_list callback
 | 
						|
		 * or cmap/votequorum callbacks
 | 
						|
		 */
 | 
						|
		return (-1);
 | 
						|
	}
 | 
						|
 | 
						|
	return (0);
 | 
						|
}
 |