Blame SOURCES/0043-Ticket-49495-Fix-memory-management-is-vattr.patch

b045b9
From 2c56e7dc08a41fc1dfa6a79213e93686f553847c Mon Sep 17 00:00:00 2001
b045b9
From: William Brown <firstyear@redhat.com>
b045b9
Date: Mon, 11 Dec 2017 15:48:24 +0100
b045b9
Subject: [PATCH] Ticket 49495 - Fix memory management is vattr.
b045b9
b045b9
Bug Description:  During the fix for
b045b9
https://pagure.io/389-ds-base/issue/49436 a issue was exposed
b045b9
in how registration of attributes to cos work. With the change
b045b9
to handle -> attr link, this exposed that cos treats each attribute
b045b9
and template pair as a new type for the handle. As  aresult, this
b045b9
caused the sp_list to create a long linked list of M*N entries
b045b9
for each attr - template value. Obviously, this is extremely
b045b9
slow to traverse during a search!
b045b9
b045b9
Fix Description:  Undo part of the SLL next change and convert
b045b9
to reference counting. The issue remains that there is a defect
b045b9
in how cos handles attribute registration, but this can not be
b045b9
resolved without a significant rearchitecture of the code
b045b9
related to virtual attributes.
b045b9
b045b9
https://pagure.io/389-ds-base/issue/49495
b045b9
b045b9
Author: wibrown
b045b9
b045b9
Review by: tbordaz, lkrispen (Thanks!)
b045b9
---
b045b9
 ldap/servers/plugins/cos/cos_cache.c | 28 +++++++++++-----------------
b045b9
 ldap/servers/slapd/vattr.c           | 23 +++++++++++++++++++++--
b045b9
 2 files changed, 32 insertions(+), 19 deletions(-)
b045b9
b045b9
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
b045b9
index 662dace35..3b3c05783 100644
b045b9
--- a/ldap/servers/plugins/cos/cos_cache.c
b045b9
+++ b/ldap/servers/plugins/cos/cos_cache.c
b045b9
@@ -275,7 +275,7 @@ static Slapi_Mutex *start_lock;
b045b9
 static Slapi_Mutex *stop_lock;
b045b9
 static Slapi_CondVar *something_changed = NULL;
b045b9
 static Slapi_CondVar *start_cond = NULL;
b045b9
-
b045b9
+static vattr_sp_handle *vattr_handle = NULL;
b045b9
 
b045b9
 /*
b045b9
     cos_cache_init
b045b9
@@ -314,6 +314,15 @@ cos_cache_init(void)
b045b9
         goto out;
b045b9
     }
b045b9
 
b045b9
+    if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
b045b9
+                                cos_cache_vattr_get,
b045b9
+                                cos_cache_vattr_compare,
b045b9
+                                cos_cache_vattr_types) != 0) {
b045b9
+        slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_init - Cannot register as service provider\n");
b045b9
+        ret = -1;
b045b9
+        goto out;
b045b9
+    }
b045b9
+
b045b9
     /* grab the views interface */
b045b9
     if (slapi_apib_get_interface(Views_v1_0_GUID, &views_api)) {
b045b9
         /* lets be tolerant if views is disabled */
b045b9
@@ -847,22 +856,7 @@ cos_dn_defs_cb(Slapi_Entry *e, void *callback_data)
b045b9
                                           dnVals[valIndex]->bv_val);
b045b9
                 }
b045b9
 
b045b9
-                /*
b045b9
-                 * Each SP_handle is associated to one and only one vattr.
b045b9
-                 * We could consider making this a single function rather
b045b9
-                 * than the double-call.
b045b9
-                 */
b045b9
-
b045b9
-                vattr_sp_handle *vattr_handle = NULL;
b045b9
-
b045b9
-                if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
b045b9
-                                            cos_cache_vattr_get,
b045b9
-                                            cos_cache_vattr_compare,
b045b9
-                                            cos_cache_vattr_types) != 0) {
b045b9
-                    slapi_log_err(SLAPI_LOG_ERR, COS_PLUGIN_SUBSYSTEM, "cos_cache_init - Cannot register as service provider for %s\n", dnVals[valIndex]->bv_val);
b045b9
-                } else {
b045b9
-                    slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle, dnVals[valIndex]->bv_val, NULL, NULL);
b045b9
-                }
b045b9
+                slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle, dnVals[valIndex]->bv_val, NULL, NULL);
b045b9
 
b045b9
             } /* if(attrType is cosAttribute) */
b045b9
 
b045b9
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
b045b9
index 432946c79..13e527188 100644
b045b9
--- a/ldap/servers/slapd/vattr.c
b045b9
+++ b/ldap/servers/slapd/vattr.c
b045b9
@@ -1544,6 +1544,7 @@ struct _vattr_sp_handle
b045b9
     vattr_sp *sp;
b045b9
     struct _vattr_sp_handle *next; /* So we can link them together in the map */
b045b9
     void *hint;                    /* Hint to the SP */
b045b9
+    uint64_t rc;
b045b9
 };
b045b9
 
b045b9
 /* Calls made by Service Providers */
b045b9
@@ -1770,7 +1771,7 @@ is a separate thing in the insterests of stability.
b045b9
 
b045b9
  */
b045b9
 
b045b9
-#define VARRT_MAP_HASHTABLE_SIZE 10
b045b9
+#define VARRT_MAP_HASHTABLE_SIZE 32
b045b9
 
b045b9
 /* Attribute map oject */
b045b9
 /* Needs to contain: a linked list of pointers to provider handles handles,
b045b9
@@ -1867,7 +1868,10 @@ vattr_map_entry_free(vattr_map_entry *vae)
b045b9
     vattr_sp_handle *list_entry = vae->sp_list;
b045b9
     while (list_entry != NULL) {
b045b9
         vattr_sp_handle *next_entry = list_entry->next;
b045b9
-        slapi_ch_free((void **)&list_entry);
b045b9
+        if (slapi_atomic_decr_64(&(list_entry->rc), __ATOMIC_RELAXED) == 0) {
b045b9
+            /* Only free on RC 0 */
b045b9
+            slapi_ch_free((void **)&list_entry);
b045b9
+        }
b045b9
         list_entry = next_entry;
b045b9
     }
b045b9
     slapi_ch_free_string(&(vae->type_name));
b045b9
@@ -2280,6 +2284,17 @@ to handle the calls on it, but return nothing */
b045b9
  *
b045b9
  * Better idea, is that regattr should just take the fn pointers
b045b9
  * and callers never *see* the sp_handle structure at all.
b045b9
+ *
b045b9
+ * This leaves us with some quirks today. First: if you have plugin A
b045b9
+ * and B, A registers attr 1 and B 1 and 2, it's possible that if you
b045b9
+ * register A1 first, then B1, you have B->A in next. Then when you
b045b9
+ * register B2, because we take 0==result from map_lookup, we add sp
b045b9
+ * "as is" to the map. This means that B2 now has the same next to A1
b045b9
+ * handle. This won't add a bug, because A1 won't be able to service the
b045b9
+ * attr, but it could cause some head scratching ...
b045b9
+ *
b045b9
+ * Again, to fix this, the whole vattr external interface needs a
b045b9
+ * redesign ... :(
b045b9
  */
b045b9
 
b045b9
 int
b045b9
@@ -2304,11 +2319,15 @@ vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint)
b045b9
         if (found) {
b045b9
             return 0;
b045b9
         }
b045b9
+        /* Increase the ref count of the sphandle */
b045b9
+        slapi_atomic_incr_64(&(sp->rc), __ATOMIC_RELAXED);
b045b9
         /* We insert the SP handle into the linked list at the head */
b045b9
         sp->next = map_entry->sp_list;
b045b9
         map_entry->sp_list = sp;
b045b9
     } else {
b045b9
         /* If not, add it */
b045b9
+        /* Claim a reference on the sp ... */
b045b9
+        slapi_atomic_incr_64(&(sp->rc), __ATOMIC_RELAXED);
b045b9
         map_entry = vattr_map_entry_new(type_to_add, sp, hint);
b045b9
         if (NULL == map_entry) {
b045b9
             return ENOMEM;
b045b9
-- 
b045b9
2.13.6
b045b9