Blame SOURCES/0082-Ticket-48412-worker-threads-do-not-detect-abnormally.patch

400eba
From da9f4a9942f7a41ce8d07c7a73f67a0799424266 Mon Sep 17 00:00:00 2001
400eba
From: Mark Reynolds <mreynolds@redhat.com>
400eba
Date: Fri, 15 Jan 2016 11:35:16 -0500
400eba
Subject: [PATCH] Ticket 48412 - worker threads do not detect abnormally closed
400eba
 connections
400eba
400eba
Bug Description:  If a connection is abnormally closed there can still be
400eba
                  data in the connection buffer(bytes vs offset).  This prevents
400eba
                  the connection from being removed from the connection table.
400eba
                  The worker thread then goes into a loop trying to read this data
400eba
                  on an already closed connection.  If there are enough abnormally
400eba
                  closed conenction eventually all the worker threads are stuck,
400eba
                  and new connections are not accepted.
400eba
400eba
Fix Description:  When looking if there is more data in the buffer check if the
400eba
                  connection was closed, and return 0 (no more data).
400eba
400eba
                  Also did a little code cleanup.
400eba
400eba
https://fedorahosted.org/389/ticket/48412
400eba
400eba
Reviewed by: rmeggins(Thanks!)
400eba
400eba
(cherry picked from commit 30c4852a3d9ca527b78c0f89df5909bc9a268392)
400eba
(cherry picked from commit cd45d032421b0ecf76d8cbb9b1c3aeef7680d9a2)
400eba
---
400eba
 ldap/servers/slapd/connection.c | 46 ++++++++++++++++++++++++++++-------------
400eba
 1 file changed, 32 insertions(+), 14 deletions(-)
400eba
400eba
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
400eba
index a3d123e..3e435a7 100644
400eba
--- a/ldap/servers/slapd/connection.c
400eba
+++ b/ldap/servers/slapd/connection.c
400eba
@@ -1102,9 +1102,16 @@ connection_read_ldap_data(Connection *conn, PRInt32 *err)
400eba
 }
400eba
 
400eba
 static size_t
400eba
-conn_buffered_data_avail_nolock(Connection *conn)
400eba
+conn_buffered_data_avail_nolock(Connection *conn, int *conn_closed)
400eba
 {
400eba
-	return conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset;
400eba
+	if ( (conn->c_sd == SLAPD_INVALID_SOCKET) || (conn->c_flags & CONN_FLAG_CLOSING) ) {
400eba
+		/* connection is closed - ignore the buffer */
400eba
+		*conn_closed = 1;
400eba
+		return 0;
400eba
+	} else {
400eba
+		*conn_closed = 0;
400eba
+		return conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset;
400eba
+	}
400eba
 }
400eba
 
400eba
 /* Upon returning from this function, we have either: 
400eba
@@ -1127,6 +1134,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
400eba
 	PRErrorCode err = 0;
400eba
 	PRInt32 syserr = 0;
400eba
 	size_t buffer_data_avail;
400eba
+	int conn_closed = 0;
400eba
 
400eba
 	PR_EnterMonitor(conn->c_mutex);
400eba
 	/*
400eba
@@ -1142,7 +1150,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
400eba
 	
400eba
 	*tag = LBER_DEFAULT;
400eba
 	/* First check to see if we have buffered data from "before" */
400eba
-	if ((buffer_data_avail = conn_buffered_data_avail_nolock(conn))) {
400eba
+	if ((buffer_data_avail = conn_buffered_data_avail_nolock(conn, &conn_closed))) {
400eba
 		/* If so, use that data first */
400eba
 		if ( 0 != get_next_from_buffer( buffer
400eba
 				+ conn->c_private->c_buffer_offset,
400eba
@@ -1157,7 +1165,7 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
400eba
 	while (*tag == LBER_DEFAULT) {
400eba
 		int ioblocktimeout_waits = config_get_ioblocktimeout() / CONN_TURBO_TIMEOUT_INTERVAL;
400eba
 		/* We should never get here with data remaining in the buffer */
400eba
-		PR_ASSERT( !new_operation || 0 == conn_buffered_data_avail_nolock(conn) );
400eba
+		PR_ASSERT( !new_operation || !conn_buffered_data_avail_nolock(conn, &conn_closed));
400eba
 		/* We make a non-blocking read call */
400eba
 		if (CONNECTION_BUFFER_OFF != conn->c_private->use_buffer) {
400eba
 			ret = connection_read_ldap_data(conn,&err;;
400eba
@@ -1269,8 +1277,12 @@ int connection_read_operation(Connection *conn, Operation *op, ber_tag_t *tag, i
400eba
 		}
400eba
 	}
400eba
 	/* If there is remaining buffered data, set the flag to tell the caller */
400eba
-	if (conn_buffered_data_avail_nolock(conn)) {
400eba
+	if (conn_buffered_data_avail_nolock(conn, &conn_closed)) {
400eba
 		*remaining_data = 1;
400eba
+	} else if (conn_closed){
400eba
+		/* connection closed */
400eba
+		ret = CONN_DONE;
400eba
+		goto done;
400eba
 	}
400eba
 
400eba
 	if ( *tag != LDAP_TAG_MESSAGE ) {
400eba
@@ -1521,7 +1533,7 @@ connection_threadmain()
400eba
 					continue;
400eba
 				case CONN_SHUTDOWN:
400eba
 					LDAPDebug( LDAP_DEBUG_TRACE, 
400eba
-					"op_thread received shutdown signal\n", 					0,  0, 0 );
400eba
+					"op_thread received shutdown signal\n", 0, 0, 0 );
400eba
 					g_decr_active_threadcnt();
400eba
 					return;
400eba
 				case CONN_FOUND_WORK_TO_DO:
400eba
@@ -1542,8 +1554,9 @@ connection_threadmain()
400eba
 							Slapi_DN *anon_sdn = slapi_sdn_new_normdn_byref( anon_dn );
400eba
 							reslimit_update_from_dn( pb->pb_conn, anon_sdn );
400eba
 							slapi_sdn_free( &anon_sdn );
400eba
-							if (slapi_reslimit_get_integer_limit(pb->pb_conn, pb->pb_conn->c_idletimeout_handle,
400eba
-									&idletimeout)
400eba
+							if (slapi_reslimit_get_integer_limit(pb->pb_conn,
400eba
+							                                     pb->pb_conn->c_idletimeout_handle,
400eba
+							                                     &idletimeout)
400eba
 								== SLAPI_RESLIMIT_STATUS_SUCCESS)
400eba
 							{
400eba
 								pb->pb_conn->c_idletimeout = idletimeout;
400eba
@@ -1581,7 +1594,7 @@ connection_threadmain()
400eba
 		op = pb->pb_op;
400eba
 		maxthreads = config_get_maxthreadsperconn();
400eba
 		more_data = 0;
400eba
-		ret = connection_read_operation(conn,op,&tag,&more_data);
400eba
+		ret = connection_read_operation(conn, op, &tag, &more_data);
400eba
 		if ((ret == CONN_DONE) || (ret == CONN_TIMEDOUT)) {
400eba
 			slapi_log_error(SLAPI_LOG_CONNS, "connection_threadmain",
400eba
 					"conn %" NSPRIu64 " read not ready due to %d - thread_turbo_flag %d more_data %d "
400eba
@@ -1614,7 +1627,8 @@ connection_threadmain()
400eba
 		/* turn off turbo mode immediately if any pb waiting in global queue */
400eba
 		if (thread_turbo_flag && !WORK_Q_EMPTY) {
400eba
 			thread_turbo_flag = 0;
400eba
-			LDAPDebug2Args(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode - pb_q is not empty %d\n",conn->c_connid,work_q_size);
400eba
+			LDAPDebug2Args(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode - pb_q is not empty %d\n",
400eba
+			               conn->c_connid,work_q_size);
400eba
 		}
400eba
 #endif
400eba
 		
400eba
@@ -1639,7 +1653,8 @@ connection_threadmain()
400eba
 				 * should call connection_make_readable after the op is removed
400eba
 				 * connection_make_readable(conn);
400eba
 				 */
400eba
-				LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode due to %d\n",conn->c_connid,ret,0);
400eba
+				LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " leaving turbo mode due to %d\n",
400eba
+				          conn->c_connid,ret,0);
400eba
 				goto done;
400eba
 			case CONN_SHUTDOWN:
400eba
 				LDAPDebug( LDAP_DEBUG_TRACE, 
400eba
@@ -1695,7 +1710,8 @@ connection_threadmain()
400eba
 					 */
400eba
 					conn->c_idlesince = curtime;
400eba
 					connection_activity(conn, maxthreads);
400eba
-					LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " queued because more_data\n",conn->c_connid,0,0);
400eba
+					LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " queued because more_data\n",
400eba
+					          conn->c_connid,0,0);
400eba
 				} else {
400eba
 					/* keep count of how many times maxthreads has blocked an operation */
400eba
 					conn->c_maxthreadsblocked++;
400eba
@@ -1770,13 +1786,15 @@ done:
400eba
 			    memset(pb, 0, sizeof(*pb));
400eba
 		} else {
400eba
 			/* delete from connection operation queue & decr refcnt */
400eba
+			int conn_closed = 0;
400eba
 			PR_EnterMonitor(conn->c_mutex);
400eba
 			connection_remove_operation_ext( pb, conn, op );
400eba
 
400eba
 			/* If we're in turbo mode, we keep our reference to the connection alive */
400eba
 			/* can't use the more_data var because connection could have changed in another thread */
400eba
-			more_data = conn_buffered_data_avail_nolock(conn) ? 1 : 0;
400eba
-			LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " check more_data %d thread_turbo_flag %d\n",conn->c_connid,more_data,thread_turbo_flag);
400eba
+			more_data = conn_buffered_data_avail_nolock(conn, &conn_closed) ? 1 : 0;
400eba
+			LDAPDebug(LDAP_DEBUG_CONNS,"conn %" NSPRIu64 " check more_data %d thread_turbo_flag %d\n",
400eba
+			          conn->c_connid,more_data,thread_turbo_flag);
400eba
 			if (!more_data) {
400eba
 				if (!thread_turbo_flag) {
400eba
 					/*
400eba
-- 
400eba
2.4.3
400eba