Skip to content

Commit

Permalink
Add exemplar use case for rcu locks
Browse files Browse the repository at this point in the history
To demonstrate the use of RCU locks, convert CONF_MOD api to using rcu
rather than RW locks

Reviewed-by: Hugo Landau <[email protected]>
Reviewed-by: Matt Caswell <[email protected]>
(Merged from openssl#22729)
  • Loading branch information
nhorman committed Feb 1, 2024
1 parent d0e1a0a commit 504e72f
Showing 1 changed file with 88 additions and 46 deletions.
134 changes: 88 additions & 46 deletions crypto/conf/conf_mod.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#define OPENSSL_SUPPRESS_DEPRECATED

#include "internal/cryptlib.h"
#include "internal/rcu.h"
#include <stdio.h>
#include <ctype.h>
#include <openssl/crypto.h>
Expand Down Expand Up @@ -63,7 +64,7 @@ struct conf_imodule_st {
};

static CRYPTO_ONCE init_module_list_lock = CRYPTO_ONCE_STATIC_INIT;
static CRYPTO_RWLOCK *module_list_lock = NULL;
static CRYPTO_RCU_LOCK *module_list_lock = NULL;
static STACK_OF(CONF_MODULE) *supported_modules = NULL; /* protected by lock */
static STACK_OF(CONF_IMODULE) *initialized_modules = NULL; /* protected by lock */

Expand All @@ -86,7 +87,7 @@ static int conf_modules_finish_int(void);

static void module_lists_free(void)
{
CRYPTO_THREAD_lock_free(module_list_lock);
ossl_rcu_lock_free(module_list_lock);
module_list_lock = NULL;

sk_CONF_MODULE_free(supported_modules);
Expand All @@ -98,7 +99,7 @@ static void module_lists_free(void)

DEFINE_RUN_ONCE_STATIC(do_init_module_list_lock)
{
module_list_lock = CRYPTO_THREAD_lock_new();
module_list_lock = ossl_rcu_lock_new(1);
if (module_list_lock == NULL) {
ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
return 0;
Expand Down Expand Up @@ -327,17 +328,24 @@ static CONF_MODULE *module_add(DSO *dso, const char *name,
conf_init_func *ifunc, conf_finish_func *ffunc)
{
CONF_MODULE *tmod = NULL;
STACK_OF(CONF_MODULE) *old_modules;
STACK_OF(CONF_MODULE) *new_modules;

if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
return NULL;

if (!CRYPTO_THREAD_write_lock(module_list_lock))
return NULL;
ossl_rcu_write_lock(module_list_lock);

old_modules = ossl_rcu_deref(&supported_modules);

if (old_modules == NULL)
new_modules = sk_CONF_MODULE_new_null();
else
new_modules = sk_CONF_MODULE_dup(old_modules);

if (supported_modules == NULL)
supported_modules = sk_CONF_MODULE_new_null();
if (supported_modules == NULL)
if (new_modules == NULL)
goto err;

if ((tmod = OPENSSL_zalloc(sizeof(*tmod))) == NULL)
goto err;

Expand All @@ -348,14 +356,18 @@ static CONF_MODULE *module_add(DSO *dso, const char *name,
if (tmod->name == NULL)
goto err;

if (!sk_CONF_MODULE_push(supported_modules, tmod))
if (!sk_CONF_MODULE_push(new_modules, tmod))
goto err;

CRYPTO_THREAD_unlock(module_list_lock);
ossl_rcu_assign_ptr(&supported_modules, &new_modules);
ossl_rcu_write_unlock(module_list_lock);
ossl_synchronize_rcu(module_list_lock);

sk_CONF_MODULE_free(old_modules);
return tmod;

err:
CRYPTO_THREAD_unlock(module_list_lock);
ossl_rcu_write_unlock(module_list_lock);
if (tmod != NULL) {
OPENSSL_free(tmod->name);
OPENSSL_free(tmod);
Expand All @@ -374,6 +386,8 @@ static CONF_MODULE *module_find(const char *name)
CONF_MODULE *tmod;
int i, nchar;
char *p;
STACK_OF(CONF_MODULE) *mods;

p = strrchr(name, '.');

if (p)
Expand All @@ -384,18 +398,18 @@ static CONF_MODULE *module_find(const char *name)
if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
return NULL;

if (!CRYPTO_THREAD_read_lock(module_list_lock))
return NULL;
ossl_rcu_read_lock(module_list_lock);
mods = ossl_rcu_deref(&supported_modules);

for (i = 0; i < sk_CONF_MODULE_num(supported_modules); i++) {
tmod = sk_CONF_MODULE_value(supported_modules, i);
for (i = 0; i < sk_CONF_MODULE_num(mods); i++) {
tmod = sk_CONF_MODULE_value(mods, i);
if (strncmp(tmod->name, name, nchar) == 0) {
CRYPTO_THREAD_unlock(module_list_lock);
ossl_rcu_read_unlock(module_list_lock);
return tmod;
}
}

CRYPTO_THREAD_unlock(module_list_lock);
ossl_rcu_read_unlock(module_list_lock);
return NULL;
}

Expand All @@ -406,6 +420,8 @@ static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
int ret = 1;
int init_called = 0;
CONF_IMODULE *imod = NULL;
STACK_OF(CONF_IMODULE) *old_modules;
STACK_OF(CONF_IMODULE) *new_modules;

/* Otherwise add initialized module to list */
imod = OPENSSL_malloc(sizeof(*imod));
Expand All @@ -432,27 +448,33 @@ static int module_init(CONF_MODULE *pmod, const char *name, const char *value,
if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
goto err;

if (!CRYPTO_THREAD_write_lock(module_list_lock))
goto err;
ossl_rcu_write_lock(module_list_lock);

if (initialized_modules == NULL) {
initialized_modules = sk_CONF_IMODULE_new_null();
if (initialized_modules == NULL) {
CRYPTO_THREAD_unlock(module_list_lock);
ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
goto err;
}
old_modules = ossl_rcu_deref(&initialized_modules);

if (old_modules == NULL)
new_modules = sk_CONF_IMODULE_new_null();
else
new_modules = sk_CONF_IMODULE_dup(old_modules);

if (new_modules == NULL) {
ossl_rcu_write_unlock(module_list_lock);
ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
goto err;
}

if (!sk_CONF_IMODULE_push(initialized_modules, imod)) {
CRYPTO_THREAD_unlock(module_list_lock);
if (!sk_CONF_IMODULE_push(new_modules, imod)) {
ossl_rcu_write_unlock(module_list_lock);
ERR_raise(ERR_LIB_CONF, ERR_R_CRYPTO_LIB);
goto err;
}

pmod->links++;

CRYPTO_THREAD_unlock(module_list_lock);
ossl_rcu_assign_ptr(&initialized_modules, &new_modules);
ossl_rcu_write_unlock(module_list_lock);
ossl_synchronize_rcu(module_list_lock);
sk_CONF_IMODULE_free(old_modules);
return ret;

err:
Expand Down Expand Up @@ -482,30 +504,46 @@ void CONF_modules_unload(int all)
{
int i;
CONF_MODULE *md;
STACK_OF(CONF_MODULE) *old_modules;
STACK_OF(CONF_MODULE) *new_modules;
STACK_OF(CONF_MODULE) *to_delete;

if (!conf_modules_finish_int()) /* also inits module list lock */
return;

if (!CRYPTO_THREAD_write_lock(module_list_lock))
ossl_rcu_write_lock(module_list_lock);

old_modules = ossl_rcu_deref(&supported_modules);
new_modules = sk_CONF_MODULE_dup(old_modules);
to_delete = sk_CONF_MODULE_new_null();

if (new_modules == NULL) {
ossl_rcu_write_unlock(module_list_lock);
return;
}

/* unload modules in reverse order */
for (i = sk_CONF_MODULE_num(supported_modules) - 1; i >= 0; i--) {
md = sk_CONF_MODULE_value(supported_modules, i);
for (i = sk_CONF_MODULE_num(new_modules) - 1; i >= 0; i--) {
md = sk_CONF_MODULE_value(new_modules, i);
/* If static or in use and 'all' not set ignore it */
if (((md->links > 0) || !md->dso) && !all)
continue;
/* Since we're working in reverse this is OK */
(void)sk_CONF_MODULE_delete(supported_modules, i);
module_free(md);
(void)sk_CONF_MODULE_delete(new_modules, i);
sk_CONF_MODULE_push(to_delete, md);
}

if (sk_CONF_MODULE_num(supported_modules) == 0) {
sk_CONF_MODULE_free(supported_modules);
supported_modules = NULL;
if (sk_CONF_MODULE_num(new_modules) == 0) {
sk_CONF_MODULE_free(new_modules);
new_modules = NULL;
}

CRYPTO_THREAD_unlock(module_list_lock);
ossl_rcu_assign_ptr(&supported_modules, &new_modules);
ossl_rcu_write_unlock(module_list_lock);
ossl_synchronize_rcu(module_list_lock);
sk_CONF_MODULE_free(old_modules);
sk_CONF_MODULE_pop_free(to_delete, module_free);

}

/* unload a single module */
Expand All @@ -521,23 +559,27 @@ static void module_free(CONF_MODULE *md)
static int conf_modules_finish_int(void)
{
CONF_IMODULE *imod;
STACK_OF(CONF_IMODULE) *old_modules;
STACK_OF(CONF_IMODULE) *new_modules = NULL;

if (!RUN_ONCE(&init_module_list_lock, do_init_module_list_lock))
return 0;

/* If module_list_lock is NULL here it means we were already unloaded */
if (module_list_lock == NULL
|| !CRYPTO_THREAD_write_lock(module_list_lock))
if (module_list_lock == NULL)
return 0;

while (sk_CONF_IMODULE_num(initialized_modules) > 0) {
imod = sk_CONF_IMODULE_pop(initialized_modules);
ossl_rcu_write_lock(module_list_lock);
old_modules = ossl_rcu_deref(&initialized_modules);
ossl_rcu_assign_ptr(&initialized_modules, &new_modules);
ossl_rcu_write_unlock(module_list_lock);
ossl_synchronize_rcu(module_list_lock);

while (sk_CONF_IMODULE_num(old_modules) > 0) {
imod = sk_CONF_IMODULE_pop(old_modules);
module_finish(imod);
}
sk_CONF_IMODULE_free(initialized_modules);
initialized_modules = NULL;

CRYPTO_THREAD_unlock(module_list_lock);
sk_CONF_IMODULE_free(old_modules);

return 1;
}
Expand Down

0 comments on commit 504e72f

Please sign in to comment.