andykimpe / rpms / 389-ds-base

Forked from rpms/389-ds-base 5 months ago
Clone
dc8c34
From 4d825079a9bb622211d3709ea2496f533b8e51d1 Mon Sep 17 00:00:00 2001
dc8c34
From: Noriko Hosoi <nhosoi@totoro.usersys.redhat.com>
dc8c34
Date: Fri, 5 Oct 2012 17:56:22 -0700
dc8c34
Subject: [PATCH 2/5] Bug 863576 - Dirsrv deadlock locking up IPA
dc8c34
dc8c34
https://bugzilla.redhat.com/show_bug.cgi?id=863576
dc8c34
dc8c34
Bug Description: Abandon of a Simple Paged Results request causes
dc8c34
the self deadlock.  When abandoning a simple paged result request,
dc8c34
the mutex for the connection object c_mutex is locked in do_abandon.
dc8c34
But to free a pagedresult massage id, pagedresults_free_one_msgid
dc8c34
called from do_abandon tries to acquire lock on c_mutex again.
dc8c34
The NSPR lock function PR_Lock is not self re-entrant.  Thus the
dc8c34
server hangs there due to the self-deadlock.
dc8c34
dc8c34
Fix Description: This patch is removing to call PR_Lock(c_mutex)
dc8c34
in pagedresults_free_one_msgid and renamed it to pagedresults_free_
dc8c34
one_msgid_nolock.  To maintain the consistency, "_nolock" is added
dc8c34
to other pagedresults apis which do not call PR_Lock in it.
dc8c34
Also, stricter locking on c_mutex is being added to pagedresults_
dc8c34
parse_control_value to protect the pagedresults related field in
dc8c34
the connection object.
dc8c34
(cherry picked from commit c19bb9dd1e95ee98a53a06f3d7eefb4dce5bc0ef)
dc8c34
---
dc8c34
 ldap/servers/slapd/abandon.c      |    2 +-
dc8c34
 ldap/servers/slapd/connection.c   |    4 +-
dc8c34
 ldap/servers/slapd/daemon.c       |    2 +-
dc8c34
 ldap/servers/slapd/pagedresults.c |  130 +++++++++++++++++++------------------
dc8c34
 ldap/servers/slapd/proto-slap.h   |    8 +-
dc8c34
 5 files changed, 74 insertions(+), 72 deletions(-)
dc8c34
dc8c34
diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c
dc8c34
index 4f00da9..094ae95 100644
dc8c34
--- a/ldap/servers/slapd/abandon.c
dc8c34
+++ b/ldap/servers/slapd/abandon.c
dc8c34
@@ -153,7 +153,7 @@ do_abandon( Slapi_PBlock *pb )
dc8c34
 	}
dc8c34
 
dc8c34
 	if ( op_is_pagedresults(o) ) {
dc8c34
-		if ( 0 == pagedresults_free_one_msgid(pb->pb_conn, id) ) {
dc8c34
+		if ( 0 == pagedresults_free_one_msgid_nolock(pb->pb_conn, id) ) {
dc8c34
 			slapi_log_access( LDAP_DEBUG_STATS, "conn=%" NSPRIu64 
dc8c34
 			                  " op=%d ABANDON targetop=Simple Paged Results\n",
dc8c34
 			                  pb->pb_conn->c_connid, pb->pb_op->o_opid );
dc8c34
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
dc8c34
index 9e43104..a3b1df5 100644
dc8c34
--- a/ldap/servers/slapd/connection.c
dc8c34
+++ b/ldap/servers/slapd/connection.c
dc8c34
@@ -2094,7 +2094,7 @@ void connection_enter_leave_turbo(Connection *conn, int current_turbo_flag, int
dc8c34
 	PR_Lock(conn->c_mutex);
dc8c34
 	/* We can already be in turbo mode, or not */
dc8c34
 	current_mode = current_turbo_flag;
dc8c34
-	if (pagedresults_in_use(conn)) {
dc8c34
+	if (pagedresults_in_use_nolock(conn)) {
dc8c34
 		/* PAGED_RESULTS does not need turbo mode */
dc8c34
 		new_mode = 0;
dc8c34
 	} else if (conn->c_private->operation_rate == 0) {
dc8c34
@@ -2780,7 +2780,7 @@ disconnect_server_nomutex( Connection *conn, PRUint64 opconnid, int opid, PRErro
dc8c34
 	connection_abandon_operations( conn );
dc8c34
 	/* needed here to ensure simple paged results timeout properly and 
dc8c34
 	 * don't impact subsequent ops */
dc8c34
-	pagedresults_reset_timedout(conn);
dc8c34
+	pagedresults_reset_timedout_nolock(conn);
dc8c34
 
dc8c34
 	if (! config_check_referral_mode()) {
dc8c34
 	    /*
dc8c34
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
dc8c34
index 597e131..b611f5c 100644
dc8c34
--- a/ldap/servers/slapd/daemon.c
dc8c34
+++ b/ldap/servers/slapd/daemon.c
dc8c34
@@ -1693,7 +1693,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
dc8c34
 				{
dc8c34
 					int add_fd = 1;
dc8c34
 					/* check timeout for PAGED RESULTS */
dc8c34
-                    if (pagedresults_is_timedout(c))
dc8c34
+                    if (pagedresults_is_timedout_nolock(c))
dc8c34
 					{
dc8c34
 						/* Exceeded the timelimit; disconnect the client */
dc8c34
 						disconnect_server_nomutex(c, c->c_connid, -1,
dc8c34
diff --git a/ldap/servers/slapd/pagedresults.c b/ldap/servers/slapd/pagedresults.c
dc8c34
index ea7de14..d445c06 100644
dc8c34
--- a/ldap/servers/slapd/pagedresults.c
dc8c34
+++ b/ldap/servers/slapd/pagedresults.c
dc8c34
@@ -64,6 +64,7 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
     struct berval cookie = {0};
dc8c34
     Connection *conn = pb->pb_conn;
dc8c34
     Operation *op = pb->pb_op;
dc8c34
+    BerElement *ber = NULL;
dc8c34
 
dc8c34
     LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_parse_control_value\n");
dc8c34
     if ( NULL == conn || NULL == op || NULL == pagesize || NULL == index ) {
dc8c34
@@ -76,70 +77,71 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
 
dc8c34
     if ( psbvp->bv_len == 0 || psbvp->bv_val == NULL )
dc8c34
     {
dc8c34
-        rc = LDAP_PROTOCOL_ERROR;
dc8c34
+        LDAPDebug0Args(LDAP_DEBUG_ANY,
dc8c34
+                    "<-- pagedresults_parse_control_value: no control value\n");
dc8c34
+        return LDAP_PROTOCOL_ERROR;
dc8c34
     }
dc8c34
-    else
dc8c34
+    ber = ber_init( psbvp );
dc8c34
+    if ( ber == NULL )
dc8c34
     {
dc8c34
-        BerElement *ber = ber_init( psbvp );
dc8c34
-        if ( ber == NULL )
dc8c34
-        {
dc8c34
-            rc = LDAP_OPERATIONS_ERROR;
dc8c34
-        }
dc8c34
-        else
dc8c34
-        {
dc8c34
-            if ( ber_scanf( ber, "{io}", pagesize, &cookie ) == LBER_ERROR )
dc8c34
-            {
dc8c34
-                rc = LDAP_PROTOCOL_ERROR;
dc8c34
+        LDAPDebug0Args(LDAP_DEBUG_ANY,
dc8c34
+                    "<-- pagedresults_parse_control_value: no control value\n");
dc8c34
+        return LDAP_PROTOCOL_ERROR;
dc8c34
+    }
dc8c34
+    if ( ber_scanf( ber, "{io}", pagesize, &cookie ) == LBER_ERROR )
dc8c34
+    {
dc8c34
+        LDAPDebug0Args(LDAP_DEBUG_ANY,
dc8c34
+             "<-- pagedresults_parse_control_value: corrupted control value\n");
dc8c34
+        return LDAP_PROTOCOL_ERROR;
dc8c34
+    }
dc8c34
+
dc8c34
+    PR_Lock(conn->c_mutex);
dc8c34
+    /* the ber encoding is no longer needed */
dc8c34
+    ber_free(ber, 1);
dc8c34
+    if ( cookie.bv_len <= 0 ) {
dc8c34
+        int i;
dc8c34
+        int maxlen;
dc8c34
+        /* first time? */
dc8c34
+        maxlen = conn->c_pagedresults.prl_maxlen;
dc8c34
+        if (conn->c_pagedresults.prl_count == maxlen) {
dc8c34
+            if (0 == maxlen) { /* first time */
dc8c34
+                conn->c_pagedresults.prl_maxlen = 1;
dc8c34
+                conn->c_pagedresults.prl_list =
dc8c34
+                    (PagedResults *)slapi_ch_calloc(1,
dc8c34
+                                                sizeof(PagedResults));
dc8c34
+            } else {
dc8c34
+                /* new max length */
dc8c34
+                conn->c_pagedresults.prl_maxlen *= 2;
dc8c34
+                conn->c_pagedresults.prl_list =
dc8c34
+                    (PagedResults *)slapi_ch_realloc(
dc8c34
+                                (char *)conn->c_pagedresults.prl_list,
dc8c34
+                                sizeof(PagedResults) *
dc8c34
+                                conn->c_pagedresults.prl_maxlen);
dc8c34
+                /* initialze newly allocated area */
dc8c34
+                memset(conn->c_pagedresults.prl_list + maxlen, '\0',
dc8c34
+                           sizeof(PagedResults) * maxlen);
dc8c34
             }
dc8c34
-            /* the ber encoding is no longer needed */
dc8c34
-            ber_free(ber, 1);
dc8c34
-            if ( cookie.bv_len <= 0 ) {
dc8c34
-                int i;
dc8c34
-                int maxlen;
dc8c34
-                /* first time? */
dc8c34
-                PR_Lock(conn->c_mutex);
dc8c34
-                maxlen = conn->c_pagedresults.prl_maxlen;
dc8c34
-                if (conn->c_pagedresults.prl_count == maxlen) {
dc8c34
-                    if (0 == maxlen) { /* first time */
dc8c34
-                        conn->c_pagedresults.prl_maxlen = 1;
dc8c34
-                        conn->c_pagedresults.prl_list =
dc8c34
-                            (PagedResults *)slapi_ch_calloc(1,
dc8c34
-                                                        sizeof(PagedResults));
dc8c34
-                    } else {
dc8c34
-                        /* new max length */
dc8c34
-                        conn->c_pagedresults.prl_maxlen *= 2;
dc8c34
-                        conn->c_pagedresults.prl_list =
dc8c34
-                            (PagedResults *)slapi_ch_realloc(
dc8c34
-                                        (char *)conn->c_pagedresults.prl_list,
dc8c34
-                                        sizeof(PagedResults) *
dc8c34
-                                        conn->c_pagedresults.prl_maxlen);
dc8c34
-                        /* initialze newly allocated area */
dc8c34
-                        memset(conn->c_pagedresults.prl_list + maxlen, '\0',
dc8c34
-                                   sizeof(PagedResults) * maxlen);
dc8c34
-                    }
dc8c34
-                    *index = maxlen; /* the first position in the new area */
dc8c34
-                } else {
dc8c34
-                    for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) {
dc8c34
-                        if (!conn->c_pagedresults.prl_list[i].pr_current_be) {
dc8c34
-                            *index = i;
dc8c34
-                            break;
dc8c34
-                        }
dc8c34
-                    }
dc8c34
+            *index = maxlen; /* the first position in the new area */
dc8c34
+        } else {
dc8c34
+            for (i = 0; i < conn->c_pagedresults.prl_maxlen; i++) {
dc8c34
+                if (!conn->c_pagedresults.prl_list[i].pr_current_be) {
dc8c34
+                    *index = i;
dc8c34
+                    break;
dc8c34
                 }
dc8c34
-                conn->c_pagedresults.prl_count++;
dc8c34
-                PR_Unlock(conn->c_mutex);
dc8c34
-            } else {
dc8c34
-                /* Repeated paged results request.
dc8c34
-                 * PagedResults is already allocated. */
dc8c34
-                char *ptr = slapi_ch_malloc(cookie.bv_len + 1);
dc8c34
-                memcpy(ptr, cookie.bv_val, cookie.bv_len);
dc8c34
-                *(ptr+cookie.bv_len) = '\0';
dc8c34
-                *index = strtol(ptr, NULL, 10);
dc8c34
-                slapi_ch_free_string(&ptr);
dc8c34
             }
dc8c34
-            slapi_ch_free((void **)&cookie.bv_val);
dc8c34
         }
dc8c34
+        conn->c_pagedresults.prl_count++;
dc8c34
+    } else {
dc8c34
+        /* Repeated paged results request.
dc8c34
+         * PagedResults is already allocated. */
dc8c34
+        char *ptr = slapi_ch_malloc(cookie.bv_len + 1);
dc8c34
+        memcpy(ptr, cookie.bv_val, cookie.bv_len);
dc8c34
+        *(ptr+cookie.bv_len) = '\0';
dc8c34
+        *index = strtol(ptr, NULL, 10);
dc8c34
+        slapi_ch_free_string(&ptr);
dc8c34
     }
dc8c34
+    slapi_ch_free((void **)&cookie.bv_val);
dc8c34
+
dc8c34
     if ((*index > -1) && (*index < conn->c_pagedresults.prl_maxlen)) {
dc8c34
         /* Need to keep the latest msgid to prepare for the abandon. */
dc8c34
         conn->c_pagedresults.prl_list[*index].pr_msgid = op->o_msgid;
dc8c34
@@ -149,6 +151,7 @@ pagedresults_parse_control_value( Slapi_PBlock *pb,
dc8c34
                       "pagedresults_parse_control_value: invalid cookie: %d\n",
dc8c34
                       *index);
dc8c34
     }
dc8c34
+    PR_Unlock(conn->c_mutex);
dc8c34
 
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "<-- pagedresults_parse_control_value: idx %d\n", *index);
dc8c34
@@ -261,7 +264,7 @@ pagedresults_free_one( Connection *conn, int index )
dc8c34
 }
dc8c34
 
dc8c34
 int 
dc8c34
-pagedresults_free_one_msgid( Connection *conn, ber_int_t msgid )
dc8c34
+pagedresults_free_one_msgid_nolock( Connection *conn, ber_int_t msgid )
dc8c34
 {
dc8c34
     int rc = -1;
dc8c34
     int i;
dc8c34
@@ -269,9 +272,9 @@ pagedresults_free_one_msgid( Connection *conn, ber_int_t msgid )
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE,
dc8c34
                   "--> pagedresults_free_one: msgid=%d\n", msgid);
dc8c34
     if (conn && (msgid > -1)) {
dc8c34
-        PR_Lock(conn->c_mutex);
dc8c34
         if (conn->c_pagedresults.prl_count <= 0) {
dc8c34
-            LDAPDebug2Args(LDAP_DEBUG_TRACE, "pagedresults_free_one_msgid: "
dc8c34
+            LDAPDebug2Args(LDAP_DEBUG_TRACE,
dc8c34
+                           "pagedresults_free_one_msgid_nolock: "
dc8c34
                            "conn=%d paged requests list count is %d\n",
dc8c34
                            conn->c_connid, conn->c_pagedresults.prl_count);
dc8c34
         } else {
dc8c34
@@ -285,7 +288,6 @@ pagedresults_free_one_msgid( Connection *conn, ber_int_t msgid )
dc8c34
                 }
dc8c34
             }
dc8c34
         }
dc8c34
-        PR_Unlock(conn->c_mutex);
dc8c34
     }
dc8c34
 
dc8c34
     LDAPDebug1Arg(LDAP_DEBUG_TRACE, "<-- pagedresults_free_one: %d\n", rc);
dc8c34
@@ -720,7 +722,7 @@ pagedresults_reset_processing(Connection *conn, int index)
dc8c34
 
dc8c34
 /* Are all the paged results requests timed out? */
dc8c34
 int
dc8c34
-pagedresults_is_timedout(Connection *conn)
dc8c34
+pagedresults_is_timedout_nolock(Connection *conn)
dc8c34
 {
dc8c34
     int i;
dc8c34
     PagedResults *prp = NULL;
dc8c34
@@ -753,7 +755,7 @@ pagedresults_is_timedout(Connection *conn)
dc8c34
 
dc8c34
 /* reset all timeout */
dc8c34
 int
dc8c34
-pagedresults_reset_timedout(Connection *conn)
dc8c34
+pagedresults_reset_timedout_nolock(Connection *conn)
dc8c34
 {
dc8c34
     int i;
dc8c34
     PagedResults *prp = NULL;
dc8c34
@@ -773,7 +775,7 @@ pagedresults_reset_timedout(Connection *conn)
dc8c34
 
dc8c34
 /* paged results requests are in progress. */
dc8c34
 int
dc8c34
-pagedresults_in_use(Connection *conn)
dc8c34
+pagedresults_in_use_nolock(Connection *conn)
dc8c34
 {
dc8c34
     LDAPDebug0Args(LDAP_DEBUG_TRACE, "--> pagedresults_in_use\n");
dc8c34
     if (NULL == conn) {
dc8c34
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
dc8c34
index 1b62c13..7e438b7 100644
dc8c34
--- a/ldap/servers/slapd/proto-slap.h
dc8c34
+++ b/ldap/servers/slapd/proto-slap.h
dc8c34
@@ -1421,11 +1421,11 @@ int pagedresults_set_timelimit(Connection *conn, time_t timelimit, int index);
dc8c34
 int pagedresults_cleanup(Connection *conn, int needlock);
dc8c34
 int pagedresults_check_or_set_processing(Connection *conn, int index);
dc8c34
 int pagedresults_reset_processing(Connection *conn, int index);
dc8c34
-int pagedresults_is_timedout(Connection *conn);
dc8c34
-int pagedresults_reset_timedout(Connection *conn);
dc8c34
-int pagedresults_in_use(Connection *conn);
dc8c34
+int pagedresults_is_timedout_nolock(Connection *conn);
dc8c34
+int pagedresults_reset_timedout_nolock(Connection *conn);
dc8c34
+int pagedresults_in_use_nolock(Connection *conn);
dc8c34
 int pagedresults_free_one(Connection *conn, int index);
dc8c34
-int pagedresults_free_one_msgid( Connection *conn, ber_int_t msgid );
dc8c34
+int pagedresults_free_one_msgid_nolock( Connection *conn, ber_int_t msgid );
dc8c34
 int op_is_pagedresults(Operation *op);
dc8c34
 int pagedresults_cleanup_all(Connection *conn, int needlock);
dc8c34
 void op_set_pagedresults(Operation *op);
dc8c34
-- 
dc8c34
1.7.7.6
dc8c34