#50480 Ticket 50445 - ldbm_config_*_set functions need to validate valuse in apply=0 mode
Closed 3 years ago by spichugi. Opened 4 years ago by lkrispen.
lkrispen/389-ds-base t50445  into  master

@@ -434,45 +434,48 @@ 

       * sure that it is sane.

       */

  

-     if (apply) {

  /* Stop the user configuring a stupidly small cache */

  /* min: 8KB (page size) * def thrd cnts (threadnumber==20). */

  #define DBDEFMINSIZ 500000

-         /* We allow a value of 0, because the autotuning in start.c will

-          * register that, and trigger the recalculation of the dbcachesize as

-          * needed on the next start up.

-          */

-         if (val < DBDEFMINSIZ && val > 0) {

-             slapi_log_err(SLAPI_LOG_NOTICE, "ldbm_config_dbcachesize_set", "cache too small, increasing to %dK bytes\n",

-                           DBDEFMINSIZ / 1000);

-             val = DBDEFMINSIZ;

-         } else if (val > li->li_dbcachesize) {

-             delta = val - li->li_dbcachesize;

- 

-             util_cachesize_result sane;

-             slapi_pal_meminfo *mi = spal_meminfo_get();

-             sane = util_is_cachesize_sane(mi, &delta);

-             spal_meminfo_destroy(mi);

- 

-             if (sane != UTIL_CACHESIZE_VALID) {

-                 slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: nsslapd-dbcachesize value is too large.");

-                 slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_dbcachesize_set",

-                               "nsslapd-dbcachesize value is too large.\n");

-                 return LDAP_UNWILLING_TO_PERFORM;

-             }

+     /* We allow a value of 0, because the autotuning in start.c will

+      * register that, and trigger the recalculation of the dbcachesize as

+      * needed on the next start up.

+      */

+     if (val < DBDEFMINSIZ && val > 0) {

+         slapi_log_err(SLAPI_LOG_NOTICE, "ldbm_config_dbcachesize_set", "cache too small, increasing to %dK bytes\n",

+                       DBDEFMINSIZ / 1000);

+         val = DBDEFMINSIZ;

+     } else if (val > li->li_dbcachesize) {

+         delta = val - li->li_dbcachesize;

+ 

+         util_cachesize_result sane;

+         slapi_pal_meminfo *mi = spal_meminfo_get();

+         sane = util_is_cachesize_sane(mi, &delta);

+         spal_meminfo_destroy(mi);

+ 

+         if (sane != UTIL_CACHESIZE_VALID) {

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: nsslapd-dbcachesize value is too large.");

+             slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_dbcachesize_set",

+                           "nsslapd-dbcachesize value is too large.\n");

+             return LDAP_UNWILLING_TO_PERFORM;

+         }

+     }

+ 

+     if (CONFIG_PHASE_RUNNING == phase) {

+         if (val > 0 && li->li_cache_autosize) {

+             /* We are auto-tuning the cache, so this change would be overwritten - return an error */

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                                   "Error: \"nsslapd-dbcachesize\" can not be updated while \"nsslapd-cache-autosize\" is set "

+                                   "in \"cn=config,cn=ldbm database,cn=plugins,cn=config\".");

+             slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_dbcachesize_set",

+                           "\"nsslapd-dbcachesize\" can not be set while \"nsslapd-cache-autosize\" is set "

+                           "in \"cn=config,cn=ldbm database,cn=plugins,cn=config\".\n");

+             return LDAP_UNWILLING_TO_PERFORM;

          }

+     }

  

+     if(apply) {

          if (CONFIG_PHASE_RUNNING == phase) {

-             if (val > 0 && li->li_cache_autosize) {

-                 /* We are auto-tuning the cache, so this change would be overwritten - return an error */

-                 slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

-                                       "Error: \"nsslapd-dbcachesize\" can not be updated while \"nsslapd-cache-autosize\" is set "

-                                       "in \"cn=config,cn=ldbm database,cn=plugins,cn=config\".");

-                 slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_dbcachesize_set",

-                               "\"nsslapd-dbcachesize\" can not be set while \"nsslapd-cache-autosize\" is set "

-                               "in \"cn=config,cn=ldbm database,cn=plugins,cn=config\".\n");

-                 return LDAP_UNWILLING_TO_PERFORM;

-             }

              li->li_new_dbcachesize = val;

              if (val == 0) {

                  slapi_log_err(SLAPI_LOG_NOTICE, "ldbm_config_dbcachesize_set", "cache size reset to 0, will be autosized on next startup.\n");
@@ -503,13 +506,13 @@ 

      int retval = LDAP_SUCCESS;

      int val = (int)((uintptr_t)value);

  

-     if (apply) {

-         if (val < 0) {

-             slapi_log_err(SLAPI_LOG_NOTICE, "ldbm_config_maxpassbeforemerge_set",

-                           "maxpassbeforemerge will not take negative value - setting to 100\n");

-             val = 100;

-         }

+     if (val < 0) {

+         slapi_log_err(SLAPI_LOG_NOTICE, "ldbm_config_maxpassbeforemerge_set",

+                       "maxpassbeforemerge will not take negative value - setting to 100\n");

+         val = 100;

+     }

  

+     if (apply) {

          li->li_maxpassbeforemerge = val;

      }

  
@@ -894,15 +897,15 @@ 

      int retval = LDAP_SUCCESS;

      int val = (int)((uintptr_t)value);

  

+     if (val < 0) {

+         slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                               "Error: Invalid value for %s (%d). Value must be equal or greater than zero.",

+                               CONFIG_DB_OLD_IDL_MAXIDS, val);

+         return LDAP_UNWILLING_TO_PERFORM;

+     }

+ 

      if (apply) {

-         if (val >= 0) {

-             li->li_old_idl_maxids = val;

-         } else {

-             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

-                                   "Error: Invalid value for %s (%d). Value must be equal or greater than zero.",

-                                   CONFIG_DB_OLD_IDL_MAXIDS, val);

-             return LDAP_UNWILLING_TO_PERFORM;

-         }

+         li->li_old_idl_maxids = val;

      }

  

      return retval;
@@ -1270,21 +1273,21 @@ 

       * sure that it is sane.

       */

  

-     if (apply) {

-         if (val > li->li_dblayer_private->dblayer_cache_config) {

-             delta = val - li->li_dblayer_private->dblayer_cache_config;

-             util_cachesize_result sane;

- 

-             slapi_pal_meminfo *mi = spal_meminfo_get();

-             sane = util_is_cachesize_sane(mi, &delta);

-             spal_meminfo_destroy(mi);

- 

-             if (sane != UTIL_CACHESIZE_VALID) {

-                 slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: db cachesize value is too large");

-                 slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_db_cache_set", "db cachesize value is too large.\n");

-                 return LDAP_UNWILLING_TO_PERFORM;

-             }

+     if (val > li->li_dblayer_private->dblayer_cache_config) {

+         delta = val - li->li_dblayer_private->dblayer_cache_config;

+         util_cachesize_result sane;

+ 

+         slapi_pal_meminfo *mi = spal_meminfo_get();

+         sane = util_is_cachesize_sane(mi, &delta);

+         spal_meminfo_destroy(mi);

+ 

+         if (sane != UTIL_CACHESIZE_VALID) {

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: db cachesize value is too large");

+             slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_db_cache_set", "db cachesize value is too large.\n");

+             return LDAP_UNWILLING_TO_PERFORM;

          }

+     }

+     if (apply) {

          li->li_dblayer_private->dblayer_cache_config = val;

      }

  
@@ -1385,17 +1388,17 @@ 

  {

      struct ldbminfo *li = (struct ldbminfo *)arg;

  

+     int val = (int)((uintptr_t)value);

+     if (val < 0 || val > 100) {

+         slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                               "Error: Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

+                               CONFIG_CACHE_AUTOSIZE, val);

+         slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_cache_autosize_set",

+                       "Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

+                       CONFIG_CACHE_AUTOSIZE, val);

+         return LDAP_UNWILLING_TO_PERFORM;

+     }

      if (apply) {

-         int val = (int)((uintptr_t)value);

-         if (val < 0 || val > 100) {

-             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

-                                   "Error: Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

-                                   CONFIG_CACHE_AUTOSIZE, val);

-             slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_cache_autosize_set",

-                           "Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

-                           CONFIG_CACHE_AUTOSIZE, val);

-             return LDAP_UNWILLING_TO_PERFORM;

-         }

          li->li_cache_autosize = val;

      }

      return LDAP_SUCCESS;
@@ -1418,17 +1421,17 @@ 

  {

      struct ldbminfo *li = (struct ldbminfo *)arg;

  

+     int val = (int)((uintptr_t)value);

+     if (val < 0 || val > 100) {

+         slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

+                               "Error: Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

+                               CONFIG_CACHE_AUTOSIZE_SPLIT, val);

+         slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_cache_autosize_split_set",

+                       "Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

+                       CONFIG_CACHE_AUTOSIZE_SPLIT, val);

+         return LDAP_UNWILLING_TO_PERFORM;

+     }

      if (apply) {

-         int val = (int)((uintptr_t)value);

-         if (val < 0 || val > 100) {

-             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,

-                                   "Error: Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

-                                   CONFIG_CACHE_AUTOSIZE_SPLIT, val);

-             slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_cache_autosize_split_set",

-                           "Invalid value for %s (%d). The value must be between \"0\" and \"100\"\n",

-                           CONFIG_CACHE_AUTOSIZE_SPLIT, val);

-             return LDAP_UNWILLING_TO_PERFORM;

-         }

          li->li_cache_autosize_split = val;

      }

      return LDAP_SUCCESS;
@@ -1461,22 +1464,22 @@ 

       * If we are setting a LARGER value, we check the delta of the two, and make

       * sure that it is sane.

       */

-     if (apply) {

-         if (val > li->li_import_cachesize) {

-             delta = val - li->li_import_cachesize;

- 

-             util_cachesize_result sane;

-             slapi_pal_meminfo *mi = spal_meminfo_get();

-             sane = util_is_cachesize_sane(mi, &delta);

-             spal_meminfo_destroy(mi);

- 

-             if (sane != UTIL_CACHESIZE_VALID) {

-                 slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: import cachesize value is too large.");

-                 slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_import_cachesize_set",

-                               "Import cachesize value is too large.\n");

-                 return LDAP_UNWILLING_TO_PERFORM;

-             }

+     if (val > li->li_import_cachesize) {

+         delta = val - li->li_import_cachesize;

+ 

+         util_cachesize_result sane;

+         slapi_pal_meminfo *mi = spal_meminfo_get();

+         sane = util_is_cachesize_sane(mi, &delta);

+         spal_meminfo_destroy(mi);

+ 

+         if (sane != UTIL_CACHESIZE_VALID) {

+             slapi_create_errormsg(errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Error: import cachesize value is too large.");

+             slapi_log_err(SLAPI_LOG_ERR, "ldbm_config_import_cachesize_set",

+                           "Import cachesize value is too large.\n");

+             return LDAP_UNWILLING_TO_PERFORM;

          }

+     }

+     if (apply) {

          li->li_import_cachesize = val;

      }

      return LDAP_SUCCESS;
@@ -2500,6 +2503,23 @@ 

  

      returntext[0] = '\0';

  

+     /* This function does:

+      * - check if the provided config modifications are valid.

+      *   since there is no transaction for changes to config entries

+      *   we do it in two passes. The first pass (apply_mod=0) just checks

+      *   that changes are valid, if an error occurs procesing is aborted

+      *   and function returns. In the second pass  (apply_mod=1) changes

+      *   are efectivly applied.

+      * - remove ignored attributes. Some attributes which were added to the

+      *   list of mods (eg modifytimestamp) are irrelevant for the config

+      *   changes and can be ignored, to ignore them also in the following

+      *   plugin calls they are removed from the list of mods and from the

+      *   postEntry, the setting of reapply mods ensures that the caller will

+      *   reset the original mods. (Note by LK: I think it is not clear why

+      *   this is done here, the callback should have no knowledge of what will

+      *   follow and why the mods are removed, for the ldbm part it would be

+      *   sufficient to just ignore them)

+      */

My understanding is that dse_callbacks will consume (apply/free) the MODs that related to them and keep (in SLAPI_MODIFY_MODS) the MODs that they ignore.
After dse_callbacks, the ignored MODs will be reapply to the postEntry. But as they were already applied before calling dse_callbacks, the dse_callbacks revert in the postEntry[MOD.attributname] = preEntry[MOD.attributename.
Like mentioned in dse.c I also do not know why we entry_apply_mods(postEntry, MODs). I guess it is to verify that it would be successful.
But then I do not understand why revert/reapply updates related to ignored attribute, why not just keeping the value in the postEntry.

Regarding your comment, I have a doubt regarding 'removed ignored attribute'. My understanding is that they are not removed but let in the MODs to be reapplied. Also this is the dse_callback that reset the orginal values in postEntry letting dse to reapply the ignored MODs.

I fully agree with your point. dse_callbacks should not know what will follow and if it is useless to revert postEntry and reapply later, it would help to clarify that code.

      /*

       * First pass: set apply mods to 0 so only input validation will be done;

       * 2nd pass: set apply mods to 1 to apply changes to internal storage
@@ -2525,11 +2545,11 @@ 

                              slapi_valueset_free(origvalues);

                          }

                      }

+                     reapply_mods = 1; /* there is at least one mod we removed */

                  }

                  continue;

              }

  

-             reapply_mods = 1; /* there is at least one mod we removed */

              /* when deleting a value, and this is the last or only value, set

                 the config param to its default value

                 when adding a value, if the value is set to its default value, replace

Bug: Some config set functions do not perform the checks for passed values if
called in apply=0 mode.
There is a memory leak if setting the config values in ldbm_config_modify_entry_callback()
fails and reapply_mods was aready set.

Fix: to prevent the memory leak only modify the list of mods if all parameter
settings will succeed. this also requires that checks are correctly
execute in apply mode 0.
For all confi set functions which do checks do it also for apply_mode 0.

Reviewd by: ?

The patch looks good . ACK
The overall code looks complex would you mind to add a comment in the block 'if (reapply_mods) {' to clarify that it is the job of dse layer to apply the ignored attributes 'modifytimestamps'... and free them.

rebased onto f50f40182519e2d733fa7a98ebbd7da52b90f79c

4 years ago

rebased onto 80ac6e6

4 years ago

@tbordaz I added a comment, could you please verify if this does make sense and if the function does what the comment say

My understanding is that dse_callbacks will consume (apply/free) the MODs that related to them and keep (in SLAPI_MODIFY_MODS) the MODs that they ignore.
After dse_callbacks, the ignored MODs will be reapply to the postEntry. But as they were already applied before calling dse_callbacks, the dse_callbacks revert in the postEntry[MOD.attributname] = preEntry[MOD.attributename.
Like mentioned in dse.c I also do not know why we entry_apply_mods(postEntry, MODs). I guess it is to verify that it would be successful.
But then I do not understand why revert/reapply updates related to ignored attribute, why not just keeping the value in the postEntry.

Regarding your comment, I have a doubt regarding 'removed ignored attribute'. My understanding is that they are not removed but let in the MODs to be reapplied. Also this is the dse_callback that reset the orginal values in postEntry letting dse to reapply the ignored MODs.

I fully agree with your point. dse_callbacks should not know what will follow and if it is useless to revert postEntry and reapply later, it would help to clarify that code.

you are right about the comment of ignored attributes, they are removed from the entry and the only ones kept in the list of mods to be reapplied.

And I missed that you wanted the comments in the level of the caller. I will rethink and rewrite it

@lkrispen, sorry I did not want to be nit picker. The patch is good but it took us so much time to understand this part of code that a comment would be a great help for the next one to dig into that place.

I have looked and also agree the patch looks reasonable. Any thing outstanding before we merge @lkrispen and @tbordaz ?

@lkrispen - is this patch still relevant with the backend work you are doing? If yes, you have all the acks you need to merge it :-)

389-ds-base is moving from Pagure to Github. This means that new issues and pull requests
will be accepted only in 389-ds-base's github repository.

This pull request has been cloned to Github as issue and is available here:
- https://github.com/389ds/389-ds-base/issues/3537

If you want to continue to work on the PR, please navigate to the github issue,
download the patch from the attachments and file a new pull request.

Thank you for understanding. We apologize for all inconvenience.

Pull-Request has been closed by spichugi

3 years ago
Metadata