]> git.sur5r.net Git - openldap/commitdiff
Add GIANT rwlock! This should resolve nasty concurrency issues.
authorKurt Zeilenga <kurt@openldap.org>
Tue, 29 Jan 2002 17:27:20 +0000 (17:27 +0000)
committerKurt Zeilenga <kurt@openldap.org>
Tue, 29 Jan 2002 17:27:20 +0000 (17:27 +0000)
13 files changed:
servers/slapd/back-ldbm/add.c
servers/slapd/back-ldbm/back-ldbm.h
servers/slapd/back-ldbm/bind.c
servers/slapd/back-ldbm/compare.c
servers/slapd/back-ldbm/delete.c
servers/slapd/back-ldbm/entry.c
servers/slapd/back-ldbm/init.c
servers/slapd/back-ldbm/modify.c
servers/slapd/back-ldbm/modrdn.c
servers/slapd/back-ldbm/nextid.c
servers/slapd/back-ldbm/passwd.c
servers/slapd/back-ldbm/referral.c
servers/slapd/back-ldbm/search.c

index 997e969f1de3ba5718af6134ea264e45f62dd6f5..9baac8106575f52ee31ab38f91161e8bc8120eed 100644 (file)
@@ -27,7 +27,6 @@ ldbm_back_add(
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        struct berval   pdn;
        Entry           *p = NULL;
-       int                     rootlock = 0;
        int                     rc;
        ID               id = NOID;
        const char      *text = NULL;
@@ -42,12 +41,12 @@ ldbm_back_add(
        Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_add: %s\n", e->e_dn, 0, 0);
 #endif
 
-       /* nobody else can add until we lock our parent */
-       ldap_pvt_thread_mutex_lock(&li->li_add_mutex);
+       /* grab giant lock for writing */
+       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
 
        if ( ( rc = dn2id( be, &e->e_nname, &id ) ) || id != NOID ) {
                /* if (rc) something bad happened to ldbm cache */
-               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
                send_ldap_result( conn, op, 
                        rc ? LDAP_OPERATIONS_ERROR : LDAP_ALREADY_EXISTS,
                        NULL, NULL, NULL, NULL );
@@ -57,7 +56,7 @@ ldbm_back_add(
        rc = entry_schema_check( be, e, NULL, &text, textbuf, textlen );
 
        if ( rc != LDAP_SUCCESS ) {
-               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -68,7 +67,6 @@ ldbm_back_add(
                        text, 0, 0 );
 #endif
 
-
                send_ldap_result( conn, op, rc,
                        NULL, text, NULL, NULL );
                return( -1 );
@@ -94,8 +92,6 @@ ldbm_back_add(
                        char *matched_dn = NULL;
                        BerVarray refs;
 
-                       ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
-
                        if ( matched != NULL ) {
                                matched_dn = ch_strdup( matched->e_dn );
                                refs = is_entry_referral( matched )
@@ -108,6 +104,8 @@ ldbm_back_add(
                                        NULL, &e->e_name, LDAP_SCOPE_DEFAULT );
                        }
 
+                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
                                "ldbm_back_add: Parent of (%s) does not exist.\n",
@@ -127,14 +125,12 @@ ldbm_back_add(
                        return -1;
                }
 
-               /* don't need the add lock anymore */
-               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
-
                if ( ! access_allowed( be, conn, op, p,
                        children, NULL, ACL_WRITE ) )
                {
                        /* free parent and writer lock */
                        cache_return_entry_w( &li->li_cache, p ); 
+                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -148,7 +144,6 @@ ldbm_back_add(
                        send_ldap_result( conn, op, LDAP_INSUFFICIENT_ACCESS,
                            NULL, "no write access to parent", NULL, NULL );
 
-
                        return -1;
                }
 
@@ -157,6 +152,7 @@ ldbm_back_add(
 
                        /* free parent and writer lock */
                        cache_return_entry_w( &li->li_cache, p );
+                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -182,6 +178,7 @@ ldbm_back_add(
 
                        /* free parent and writer lock */
                        cache_return_entry_w( &li->li_cache, p );
+                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -214,7 +211,7 @@ ldbm_back_add(
                                p = NULL;
                                
                                if ( ! rc ) {
-                                       ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+                                       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                                        LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -236,7 +233,7 @@ ldbm_back_add(
                                }
 
                        } else {
-                               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
+                               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -256,14 +253,6 @@ ldbm_back_add(
                                return -1;
                        }
                }
-
-               /*
-                * no parent, acquire the root write lock
-                * and release the add lock.
-                */
-               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
-               rootlock = 1;
-               ldap_pvt_thread_mutex_unlock(&li->li_add_mutex);
        }
 
        if ( next_id( be, &e->e_id ) ) {
@@ -272,20 +261,16 @@ ldbm_back_add(
                        cache_return_entry_w( &li->li_cache, p ); 
                }
 
-               if ( rootlock ) {
-                       /* release root lock */
-                       ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
-               }
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
-                          "ldbm_back_add: next_id failed.\n" ));
+                       "ldbm_back_add: next_id failed.\n" ));
 #else
                Debug( LDAP_DEBUG_ANY, "ldbm_add: next_id failed\n",
                        0, 0, 0 );
 #endif
 
-
                send_ldap_result( conn, op, LDAP_OTHER,
                        NULL, "next_id add failed", NULL, NULL );
 
@@ -303,10 +288,7 @@ ldbm_back_add(
                        cache_return_entry_w( &li->li_cache, p ); 
                }
 
-               if ( rootlock ) {
-                       /* release root lock */
-                       ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
-               }
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_ERR,
@@ -392,16 +374,13 @@ return_results:;
                cache_return_entry_w( &li->li_cache, p ); 
        }
 
-       if ( rootlock ) {
-               /* release root lock */
-               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
-       }
-
        if ( rc ) {
                /* in case of error, writer lock is freed 
                 * and entry's private data is destroyed */
                cache_return_entry_w( &li->li_cache, e );
        }
 
+       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+
        return( rc );
 }
index a1072adc745446e60726a06da0a797a4e7b2fe14..c74d84c40864aa7c791a61e5fb3130182680ca56 100644 (file)
@@ -125,10 +125,8 @@ typedef struct ldbm_dbcache {
 #define MAXDBCACHE     128
 
 struct ldbminfo {
+       ldap_pvt_thread_rdwr_t          li_giant_rwlock;
        ID                      li_nextid;
-       ldap_pvt_thread_mutex_t         li_nextid_mutex;
-       ldap_pvt_thread_mutex_t         li_root_mutex;
-       ldap_pvt_thread_mutex_t         li_add_mutex;
        int                     li_mode;
        slap_mask_t     li_defaultmask;
        char                    *li_directory;
index a6ab1c5e2940830e1b5c70ba9254e65488016026..ddadbad7b16a3b1db2eb334d7e834fb86e3f5a3b 100644 (file)
@@ -50,9 +50,11 @@ ldbm_back_bind(
        Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_bind: dn: %s\n", dn->bv_val, 0, 0);
 #endif
 
-
        dn = ndn;
 
+       /* grab giant lock for reading */
+       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
+
        /* get entry with reader lock */
        if ( (e = dn2entry_r( be, dn, &matched )) == NULL ) {
                char *matched_dn = NULL;
@@ -72,6 +74,8 @@ ldbm_back_bind(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
+               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
+
                /* allow noauth binds */
                rc = 1;
                if ( method == LDAP_AUTH_SIMPLE ) {
@@ -263,6 +267,7 @@ ldbm_back_bind(
 return_results:;
        /* free entry and reader lock */
        cache_return_entry_r( &li->li_cache, e );
+       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
 
        /* front end with send result on success (rc==0) */
        return( rc );
index b3494b4964fba9a26cb590330beb9d862e362005..b5ca4f66186297bfba422f7d4e5cb24aa1ee18ea 100644 (file)
@@ -33,6 +33,9 @@ ldbm_back_compare(
        int             rc;
        int             manageDSAit = get_manageDSAit( op );
 
+       /* grab giant lock for reading */
+       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
+
        /* get entry with reader lock */
        if ( (e = dn2entry_r( be, ndn, &matched )) == NULL ) {
                char *matched_dn = NULL;
@@ -49,6 +52,8 @@ ldbm_back_compare(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
+               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
+
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -115,5 +120,6 @@ ldbm_back_compare(
 
 return_results:;
        cache_return_entry_r( &li->li_cache, e );
+       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
        return( rc );
 }
index a3b5ebe902da0c235f43e810acdab39f74f43296..874fe4f156775266ec034f63f02d6340dca56794 100644 (file)
@@ -29,7 +29,6 @@ ldbm_back_delete(
        Entry   *matched;
        struct berval   pdn;
        Entry   *e, *p = NULL;
-       int rootlock = 0;
        int     rc = -1;
        int             manageDSAit = get_manageDSAit( op );
        AttributeDescription *children = slap_schema.si_ad_children;
@@ -41,6 +40,9 @@ ldbm_back_delete(
        Debug(LDAP_DEBUG_ARGS, "==> ldbm_back_delete: %s\n", dn->bv_val, 0, 0);
 #endif
 
+       /* grab giant lock for writing */
+       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
+
        /* get entry with writer lock */
        if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
                char *matched_dn = NULL;
@@ -66,6 +68,8 @@ ldbm_back_delete(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -196,9 +200,6 @@ ldbm_back_delete(
                                goto return_results;
                        }
                }
-
-               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
-               rootlock = 1;
        }
 
        /* delete from dn2id mapping */
@@ -248,13 +249,10 @@ return_results:;
                cache_return_entry_w( &li->li_cache, p );
        }
 
-       if ( rootlock ) {
-               /* release root lock */
-               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
-       }
-
        /* free entry and writer lock */
        cache_return_entry_w( &li->li_cache, e );
 
+       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+
        return rc;
 }
index 28267e39fb658ccaa8d804c4e308461326954b22..f018d2b1299914b19202c46b3b838f02f503be48 100644 (file)
@@ -31,8 +31,8 @@ ldbm_back_entry_release_rw(
        if ( slapMode == SLAP_SERVER_MODE ) {
                /* free entry and reader or writer lock */
                cache_return_entry_rw( &li->li_cache, e, rw ); 
+
        } else {
-               
                entry_free( e );
        }
 
index 1fe1335666f1de3fcd9f0662710ded8a981b3aca..1c1af991f85eb234d1c2daf7ba0c8290c88322d1 100644 (file)
@@ -172,10 +172,8 @@ ldbm_back_db_init(
        li->li_dbshutdown = 0;
 
        /* initialize various mutex locks & condition variables */
-       ldap_pvt_thread_mutex_init( &li->li_root_mutex );
-       ldap_pvt_thread_mutex_init( &li->li_add_mutex );
+       ldap_pvt_thread_rdwr_init( &li->li_giant_rwlock );
        ldap_pvt_thread_mutex_init( &li->li_cache.c_mutex );
-       ldap_pvt_thread_mutex_init( &li->li_nextid_mutex );
        ldap_pvt_thread_mutex_init( &li->li_dbcache_mutex );
        ldap_pvt_thread_cond_init( &li->li_dbcache_cv );
 
@@ -225,10 +223,8 @@ ldbm_back_db_destroy(
        free( li->li_directory );
        attr_index_destroy( li->li_attrs );
 
-       ldap_pvt_thread_mutex_destroy( &li->li_root_mutex );
-       ldap_pvt_thread_mutex_destroy( &li->li_add_mutex );
+       ldap_pvt_thread_rdwr_destroy( &li->li_giant_rwlock );
        ldap_pvt_thread_mutex_destroy( &li->li_cache.c_mutex );
-       ldap_pvt_thread_mutex_destroy( &li->li_nextid_mutex );
        ldap_pvt_thread_mutex_destroy( &li->li_dbcache_mutex );
        ldap_pvt_thread_cond_destroy( &li->li_dbcache_cv );
 
index c7978238a2ee8575acb0b551345d6a6281121548..6948d2ffd8d088e8e9a56fab030b90d9e2f0a88d 100644 (file)
@@ -297,6 +297,8 @@ ldbm_back_modify(
        Debug(LDAP_DEBUG_ARGS, "ldbm_back_modify:\n", 0, 0, 0);
 #endif
 
+       /* grab giant lock for writing */
+       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
 
        /* acquire and lock entry */
        if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
@@ -314,6 +316,7 @@ ldbm_back_modify(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -370,9 +373,11 @@ ldbm_back_modify(
                NULL, NULL, NULL, NULL );
 
        cache_return_entry_w( &li->li_cache, e );
+       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        return( 0 );
 
 error_return:;
        cache_return_entry_w( &li->li_cache, e );
+       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        return( -1 );
 }
index 195fa4d434f575c5e86171d73b6224481e492146..f2e2dfb6d6c603ecfc049b72d76a675ebc7bb2ed 100644 (file)
@@ -88,6 +88,9 @@ ldbm_back_modrdn(
                        ? newSuperior->bv_val : "NULL", 0 );
 #endif
 
+       /* grab giant lock for writing */
+       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
+
        /* get entry with writer lock */
        if ( (e = dn2entry_w( be, ndn, &matched )) == NULL ) {
                char* matched_dn = NULL;
@@ -104,6 +107,8 @@ ldbm_back_modrdn(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
+
                send_ldap_result( conn, op, LDAP_REFERRAL,
                        matched_dn, NULL, refs, NULL );
 
@@ -262,9 +267,6 @@ ldbm_back_modrdn(
                        }
                }
 
-               ldap_pvt_thread_mutex_lock(&li->li_root_mutex);
-               rootlock = 1;
-               
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
                           "ldbm_back_modrdn: (%s) no parent, locked root.\n", e->e_dn ));
@@ -804,11 +806,6 @@ return_results:
                cache_return_entry_w( &li->li_cache, p );
        }
 
-       if ( rootlock ) {
-               /* release root writer lock */
-               ldap_pvt_thread_mutex_unlock(&li->li_root_mutex);
-       }
-
        /* free entry and writer lock */
        cache_return_entry_w( &li->li_cache, e );
        if ( rc == MUST_DESTROY ) {
@@ -817,5 +814,6 @@ return_results:
                 * the entry must be freed */
                entry_free( e );
        }
+       ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        return( rc );
 }
index 2bdcde3871fbde8ed402ec143a27e87f18f82bf6..80f6f0f61f89c022dde08a1817909b95dd57b94c 100644 (file)
@@ -102,11 +102,8 @@ next_id_get( Backend *be, ID *idp )
 
        *idp = NOID;
 
-       ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
-
        if ( li->li_nextid == NOID ) {
                if ( ( rc = next_id_read( be, idp ) ) ) {
-                       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
                        return( rc );
                }
                li->li_nextid = *idp;
@@ -114,7 +111,6 @@ next_id_get( Backend *be, ID *idp )
 
        *idp = li->li_nextid;
 
-       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
        return( rc );
 }
 
@@ -124,11 +120,8 @@ next_id( Backend *be, ID *idp )
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
        int rc = 0;
 
-       ldap_pvt_thread_mutex_lock( &li->li_nextid_mutex );
-
        if ( li->li_nextid == NOID ) {
                if ( ( rc = next_id_read( be, idp ) ) ) {
-                       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
                        return( rc );
                }
                li->li_nextid = *idp;
@@ -139,6 +132,5 @@ next_id( Backend *be, ID *idp )
                rc = -1;
        }
 
-       ldap_pvt_thread_mutex_unlock( &li->li_nextid_mutex );
        return( rc );
 }
index 1f04c48555825478fc4a93f205a8989bc5e9242f..8ad0948f09fe06cf33e52c8dbf5b25eaa306db2a 100644 (file)
@@ -31,7 +31,7 @@ ldbm_back_exop_passwd(
 )
 {
        struct ldbminfo *li = (struct ldbminfo *) be->be_private;
-       int rc;
+       int rc, locked=0;
        Entry *e = NULL;
        struct berval hash = { 0, NULL };
 
@@ -108,8 +108,12 @@ ldbm_back_exop_passwd(
                goto done;
        }
 
+       /* grab giant lock for writing */
+       ldap_pvt_thread_rdwr_wlock(&li->li_giant_rwlock);
+
        e = dn2entry_w( be, &ndn, NULL );
        if( e == NULL ) {
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
                *text = "could not locate authorization entry";
                rc = LDAP_NO_SUCH_OBJECT;
                goto done;
@@ -173,6 +177,7 @@ ldbm_back_exop_passwd(
 done:
        if( e != NULL ) {
                cache_return_entry_w( &li->li_cache, e );
+               ldap_pvt_thread_rdwr_wunlock(&li->li_giant_rwlock);
        }
 
        if( hash.bv_val != NULL ) {
index 05d51e0919b2500f1afea47fb1601a944306d1d1..48bb7886cc53017d2b837fb7d9d9a152cff52b2c 100644 (file)
@@ -38,6 +38,9 @@ ldbm_back_referrals(
                return rc;
        } 
 
+       /* grab giant lock for reading */
+       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
+
        /* get entry with reader lock */
        e = dn2entry_r( be, ndn, &matched );
        if ( e == NULL ) {
@@ -70,6 +73,8 @@ ldbm_back_referrals(
                                NULL, dn, LDAP_SCOPE_DEFAULT );
                }
 
+               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
+
                if( refs != NULL ) {
                        /* send referrals */
                        send_ldap_result( conn, op, rc = LDAP_REFERRAL,
@@ -117,5 +122,7 @@ ldbm_back_referrals(
        }
 
        cache_return_entry_r( &li->li_cache, e );
+       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
+
        return rc;
 }
index c80359f8c6ecb6dcc141727faf659e340e6d1d7b..c61b921ac6e01982298ec4986d666f1b6171c1eb 100644 (file)
@@ -64,6 +64,8 @@ ldbm_back_search(
        Debug(LDAP_DEBUG_TRACE, "=> ldbm_back_search\n", 0, 0, 0);
 #endif
 
+       /* grab giant lock for reading */
+       ldap_pvt_thread_rdwr_rlock(&li->li_giant_rwlock);
 
        if ( nbase->bv_len == 0 ) {
                /* DIT root special case */
@@ -116,6 +118,8 @@ ldbm_back_search(
                                NULL, base, scope );
                }
 
+               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
+
                send_ldap_result( conn, op, err, matched_dn.bv_val, 
                        text, refs, NULL );
 
@@ -135,6 +139,7 @@ ldbm_back_search(
                refs = NULL;
 
                cache_return_entry_r( &li->li_cache, e );
+               ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
 
 #ifdef NEW_LOGGING
                LDAP_LOG(( "backend", LDAP_LEVEL_INFO,
@@ -506,6 +511,8 @@ loop_continue:
        rc = 0;
 
 done:
+       ldap_pvt_thread_rdwr_runlock(&li->li_giant_rwlock);
+
        if( candidates != NULL )
                idl_free( candidates );