/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "nscd_switch.h"
#include "nscd_log.h"
/*
* nscd_nsw_state_t list for each nss database. Protected
* by the readers/writer lock nscd_nsw_state_base_lock.
*/
nscd_nsw_state_base_t **nscd_nsw_state_base;
static rwlock_t nscd_nsw_state_base_lock = DEFAULTRWLOCK;
static void
_nscd_free_nsw_state(
nscd_nsw_state_t *s)
{
int i;
char *me = "_nscd_free_nsw_state";
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "freeing nsw state = %p\n", s);
if (s == NULL)
return;
if (s->nsw_cfg_p != NULL)
/*
* an nsw state without base does not reference
* count the nsw config data (ie not using a
* shared one), so the one created for it should
* be freed
*/
if ((*s->nsw_cfg_p)->nobase != 1)
_nscd_release((nscd_acc_data_t *)s->nsw_cfg_p);
else
(void) _nscd_set((nscd_acc_data_t *)s->nsw_cfg_p, NULL);
if (s->be_db_pp != NULL) {
for (i = 0; i < s->max_src; i++) {
if (s->be_db_pp[i] == NULL)
continue;
_nscd_release((nscd_acc_data_t *)s->be_db_pp[i]);
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "release db be ptr %p\n", s->be_db_pp[i]);
}
free(s->be_db_pp);
}
if (s->be != NULL) {
for (i = 0; i < s->max_src; i++) {
if (s->be[i] == NULL)
continue;
if (s->getent == 1)
(void) NSS_INVOKE_DBOP(s->be[i],
NSS_DBOP_ENDENT, 0);
(void) NSS_INVOKE_DBOP(s->be[i],
NSS_DBOP_DESTRUCTOR, 0);
}
free(s->be);
}
if (s->be_constr != NULL)
free(s->be_constr);
if (s->be_version_p != NULL)
free(s->be_version_p);
/* remove reference to the nsw state base */
if (s->base != NULL) {
_nscd_release((nscd_acc_data_t *)s->base);
s->base = NULL;
}
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "nsw state %p freed \n", s);
free(s);
}
static void
_nscd_free_nsw_state_base(
nscd_acc_data_t *data)
{
nscd_nsw_state_base_t *base = (nscd_nsw_state_base_t *)data;
nscd_nsw_state_t *s, *ts;
int i;
char *me = "_nscd_free_nsw_state_base";
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "freeing db state base %p\n", base);
if (base == NULL)
return;
for (i = 0; i < 2; i++) {
if (i == 1)
s = base->nsw_state.first;
else
s = base->nsw_state_thr.first;
while (s != NULL) {
ts = s->next;
_nscd_free_nsw_state(s);
s = ts;
}
}
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "nsw state base %p freed \n", base);
}
void
_nscd_free_all_nsw_state_base()
{
nscd_nsw_state_base_t *base;
int i;
char *me = "_nscd_free_all_nsw_state_base";
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "freeing all db state base\n");
(void) rw_wrlock(&nscd_nsw_state_base_lock);
for (i = 0; i < NSCD_NUM_DB; i++) {
base = nscd_nsw_state_base[i];
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_DEBUG)
(me, "freeing db state base (%d) %p \n", i, base);
if (base == NULL)
continue;
nscd_nsw_state_base[i] = (nscd_nsw_state_base_t *)
_nscd_set((nscd_acc_data_t *)base, NULL);
}
(void) rw_unlock(&nscd_nsw_state_base_lock);
}
static nscd_nsw_state_t *
_nscd_create_nsw_state(
nscd_nsw_params_t *params)
{
nscd_nsw_state_t *s;
nscd_nsw_config_t *nsw_cfg;
nscd_db_t **be_db_p, *be_db;
int i, nobe = 1;
char *me = "_nscd_create_nsw_state";
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "creating nsw state...\n");
s = calloc(1, sizeof (nscd_nsw_state_t));
if (s == NULL) {
if ((*s->nsw_cfg_p)->nobase != 1)
_nscd_release((nscd_acc_data_t *)params->nswcfg);
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "not able to allocate a nsw state\n");
return (NULL);
} else
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "nsw state %p allocated\n", s);
s->dbi = params->dbi;
s->next = NULL;
nsw_cfg = *params->nswcfg;
s->nsw_cfg_p = params->nswcfg;
s->config = nsw_cfg->nsw_config;
s->max_src = nsw_cfg->max_src;
s->p = params->p;
s->be = calloc(s->max_src, sizeof (nss_backend_t **));
if (s->be == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "not able to allocate s->be\n");
_nscd_free_nsw_state(s);
return (NULL);
} else {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "db be array %p allocated\n", s->be);
}
s->be_constr = (nss_backend_constr_t *)calloc(s->max_src,
sizeof (nss_backend_constr_t));
if (s->be_constr == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "not able to allocate s->be_constr\n");
_nscd_free_nsw_state(s);
return (NULL);
} else {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "db be constructor array %p allocated\n", s->be_constr);
}
s->be_version_p = (void **)calloc(s->max_src, sizeof (void *));
if (s->be_version_p == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "not able to allocate s->be_version_p\n");
_nscd_free_nsw_state(s);
return (NULL);
} else {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "db be version ptr array %p allocated\n", s->be_version_p);
}
s->be_db_pp = calloc(s->max_src, sizeof (nscd_db_t ***));
if (s->be_db_pp == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "not able to allocate s->be_db_pp\n");
_nscd_free_nsw_state(s);
return (NULL);
} else {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "be_db_pp array %p allocated\n", s->be_db_pp);
}
/* create the source:database backends */
for (i = 0; i < s->max_src; i++) {
nss_backend_t *be;
int srci;
char *srcn;
const char *dbn;
struct __nsw_lookup_v1 *lkp;
const nscd_db_entry_t *dbe;
nscd_be_info_t *be_info;
if (i == 0)
lkp = s->config->lookups;
else
lkp = lkp->next;
if (lkp == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "error: lkp is NULL\n");
_nscd_free_nsw_state(s);
return (NULL);
}
srci = nsw_cfg->src_idx[i];
srcn = lkp->service_name;
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "source name = %s, index = %d\n", srcn, srci);
be_db_p = (nscd_db_t **)_nscd_get(
(nscd_acc_data_t *)nscd_src_backend_db[srci]);
if (be_db_p == NULL) {
_nscd_free_nsw_state(s);
return (NULL);
}
be_db = *be_db_p;
s->be_db_pp[i] = be_db_p;
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "be db ptr array %p referenced\n", be_db_p);
be_info = NULL;
be = NULL;
dbn = params->p.name;
dbe = _nscd_get_db_entry(be_db, NSCD_DATA_BACKEND_INFO,
(const char *)dbn, NSCD_GET_FIRST_DB_ENTRY, 0);
if (dbe != NULL)
be_info = (nscd_be_info_t *)*(dbe->data_array);
if (be_info == NULL || be_info->be_constr == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "no backend info or be_constr is NULL "
"for <%s : %s>\n", NSCD_NSW_SRC_NAME(srci),
dbn);
} else {
s->be_constr[i] = be_info->be_constr;
be = (be_info->be_constr)(dbn,
NSCD_NSW_SRC_NAME(srci), 0);
if (be == NULL)
s->recheck_be = nscd_true;
}
if (be == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "not able to init be for <%s : %s>\n",
NSCD_NSW_SRC_NAME(srci), dbn);
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "releasing db be ptr %p\n", be_db_p);
_nscd_release((nscd_acc_data_t *)be_db_p);
s->be_db_pp[i] = NULL;
continue;
}
s->be[i] = be;
s->be_version_p[i] = be_info->be_version;
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "backend version is %p\n", be_info->be_version);
nobe = 0;
}
if (nobe == 1) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "NO backend found, returning NULL\n");
_nscd_free_nsw_state(s);
return (NULL);
}
return (s);
}
/*
* Try to initialize the backend instances one more time
* in case the dependencies the backend libraries depend
* on are now available
*/
static void
check_be_array(
nscd_nsw_state_t *s)
{
int i;
char *dbn;
char *srcn;
struct __nsw_lookup_v1 *lkp;
dbn = NSCD_NSW_DB_NAME(s->dbi);
s->recheck_be = nscd_false;
for (i = 0; i < s->max_src; i++) {
if (i == 0)
lkp = s->config->lookups;
else
lkp = lkp->next;
if (lkp == NULL)
return;
srcn = lkp->service_name;
/*
* it is possible that 's->be[i]' could not be
* initialized earlier due to a dependency not
* yet available (e.g., nis on domain name),
* try to initialize one more time
*/
if (s->be[i] == NULL && s->be_constr[i] != NULL) {
s->be[i] = (s->be_constr[i])(dbn, srcn, 0);
if (s->be[i] == NULL)
s->recheck_be = nscd_true;
}
}
}
static nscd_rc_t
_get_nsw_state_int(
nss_db_root_t *rootp,
nscd_nsw_params_t *params,
thread_t *tid)
{
nscd_nsw_state_t *ret = NULL;
nscd_nsw_config_t **nswcfg;
nscd_nsw_state_base_t *base;
nscd_state_ctrl_t *ctrl_p;
int thread_only = 0, wait_cond = 0;
char *me = "_get_nsw_state_int";
int dbi;
nscd_rc_t rc;
dbi = params->dbi;
/*
* no nsw state will be reused, if asked to use
* default config. So create the new structures
* used by the switch engine and the new nsw state
*/
if (params->p.flags & NSS_USE_DEFAULT_CONFIG) {
rc = _nscd_create_sw_struct(dbi, -1, (char *)params->p.name,
(char *)params->p.default_config, NULL, params);
if (rc != NSCD_SUCCESS)
return (rc);
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "no base nsw config created for %s (sources: %s)\n",
params->p.name, params->p.default_config);
ret = _nscd_create_nsw_state(params);
if (ret == NULL)
return (NSCD_CREATE_NSW_STATE_FAILED);
rootp->s = (struct nss_db_state *)ret;
return (NSCD_SUCCESS);
}
/*
* if getting a nsw state for a request from the compat
* backend, create the new switch structures if this
* is the first time around for a passwd, shadow, group,
* or user_attr database
*/
if (params->compati != -1) {
nscd_nsw_config_t **nswcfg1, **nswcfg2;
int i = params->compati;
dbi = i;
/*
* retrieve the pointer space which contains a
* pointer pointing to the nsswitch config
* structure for the compat backend
*/
nswcfg = (nscd_nsw_config_t **)_nscd_get(
(nscd_acc_data_t *)nscd_nsw_config[i]);
/*
* If nsswitch config structure not created yet,
* get the config string from the passwd_compat
* or group_compat DB and create the structure.
*/
if (*nswcfg == NULL) {
/* Wait first if it's being created. */
nswcfg2 = (nscd_nsw_config_t **)_nscd_mutex_lock(
(nscd_acc_data_t *)nscd_nsw_config[i]);
/* still not created yet */
if (*nswcfg2 == NULL) {
/*
* get the nsswitch config string specified
* for passwd_compat or group_compat
*/
nswcfg1 = (nscd_nsw_config_t **)_nscd_get(
(nscd_acc_data_t *)
nscd_nsw_config[params->cfgdbi]);
if (nswcfg1 == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_ERROR)
(me, "no nsw config for %s\n",
params->p.name);
(void) _nscd_mutex_unlock(
(nscd_acc_data_t *)nswcfg2);
_nscd_release((nscd_acc_data_t *)
nswcfg);
return (NSCD_CREATE_NSW_STATE_FAILED);
}
rc = _nscd_create_sw_struct(i, params->cfgdbi,
params->p.name, (*nswcfg1)->nsw_cfg_str,
NULL, params);
_nscd_release((nscd_acc_data_t *)nswcfg1);
if (rc == NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_DEBUG)
(me, "nsw config created for %s (%s)\n",
params->p.name,
(*nswcfg1)->nsw_cfg_str);
} else {
(void) _nscd_mutex_unlock(
(nscd_acc_data_t *)nswcfg2);
_nscd_release((nscd_acc_data_t *)
nswcfg);
return (rc);
}
}
(void) _nscd_mutex_unlock((nscd_acc_data_t *)nswcfg2);
}
_nscd_release((nscd_acc_data_t *)nswcfg);
}
(void) rw_rdlock(&nscd_nsw_state_base_lock);
base = nscd_nsw_state_base[dbi];
(void) rw_unlock(&nscd_nsw_state_base_lock);
if (base == NULL)
assert(base != NULL);
/*
* If list is not empty, return the first one on list.
* Otherwise, create and return a new db state if the
* limit is not reached. if reacehed, wait for the 'one
* is available' signal.
*/
assert(base == (nscd_nsw_state_base_t *)_nscd_mutex_lock(
(nscd_acc_data_t *)base));
if (tid == NULL) {
ctrl_p = &base->nsw_state;
} else {
thread_only = 1;
ctrl_p = &base->nsw_state_thr;
_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
_nscd_logit(me, "per thread nsw state info: \n");
_nscd_logit(me, "tid = %d\n", *tid);
_nscd_logit(me, "tid in base = %d\n", base->tid);
_nscd_logit(me, "number of free nsw_state = %d\n",
ctrl_p->free);
_nscd_logit(me, "number of nsw state allocated = %d\n",
ctrl_p->allocated);
_nscd_logit(me, "first nsw state on list = %p\n",
ctrl_p->first);
_nscd_logit(me, "number of waiter = %d\n",
ctrl_p->waiter);
}
}
if (ctrl_p->first == NULL && ctrl_p->allocated == ctrl_p->max)
wait_cond = 1;
else if (thread_only && base->used_by_thr && base->tid != *tid)
wait_cond = 1;
if (wait_cond) {
ctrl_p->waiter++;
while (wait_cond) {
if (!thread_only)
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_DEBUG)
(me, "waiting for nsw state signal\n");
else
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_DEBUG)
(me, "waiting for per thread "
"nsw state signal\n");
if (thread_only) {
_nscd_cond_wait((nscd_acc_data_t *)base,
&base->thr_cond);
if (base->used_by_thr == 0 &&
ctrl_p->first != NULL)
wait_cond = 0;
} else {
_nscd_cond_wait((nscd_acc_data_t *)base, NULL);
if (ctrl_p->first != NULL)
wait_cond = 0;
}
if (!thread_only)
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_DEBUG)
(me, "woke from cond wait ...wait_cond = %d\n",
wait_cond);
else
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_DEBUG)
(me, "woke from cond wait (per thread) "
"...wait_cond = %d\n", wait_cond);
}
ctrl_p->waiter--;
}
if (ctrl_p->first == NULL) {
int geti;
/*
* for lookup calls from the compat backend
* uses the switch policy for passwd_compat
* or group_compat
*/
if (params->compati != -1)
geti = params->compati;
else
geti = params->dbi;
params->nswcfg = (nscd_nsw_config_t **)_nscd_get(
(nscd_acc_data_t *)nscd_nsw_config[geti]);
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "got a nsw config %p for index %d\n",
params->nswcfg, geti);
ctrl_p->first = _nscd_create_nsw_state(params);
if (ctrl_p->first != NULL) {
if (tid == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_DEBUG)
(me, "got a new nsw_state %p\n", ctrl_p->first);
} else {
_NSCD_LOG(NSCD_LOG_NSW_STATE,
NSCD_LOG_LEVEL_DEBUG)
(me, "got a new per thread nsw_state %p\n",
ctrl_p->first);
}
ctrl_p->allocated++;
ctrl_p->free++;
} else {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
(me, "error: unable to obtain a nsw state\n");
_nscd_mutex_unlock((nscd_acc_data_t *)base);
return (NSCD_CREATE_NSW_STATE_FAILED);
}
}
ret = ctrl_p->first;
if (ret->recheck_be == nscd_true)
check_be_array(ret);
ctrl_p->first = ret->next;
ret->next = NULL;
ctrl_p->free--;
if (thread_only) {
base->tid = *tid;
base->used_by_thr = 1;
_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
_nscd_logit(me, "\t\t\tgot a per thread nsw "
"state %p: \n", ret);
_nscd_logit(me, "tid = %d\n", *tid);
_nscd_logit(me, "tid in base = %d\n", base->tid);
_nscd_logit(me, "number of free nsw_state = %d\n",
ctrl_p->free);
_nscd_logit(me, "number od nsw state allocated = %d\n",
ctrl_p->allocated);
_nscd_logit(me, "first nsw state on list = %p\n",
ctrl_p->first);
_nscd_logit(me, "number of waiter = %d\n",
ctrl_p->waiter);
}
}
else
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "got old nsw state %p\n", ret);
/*
* reference count the nsswitch state base bfore handing out
* the nsswitch state
*/
ret->base = (nscd_nsw_state_base_t *)
_nscd_get((nscd_acc_data_t *)base);
_nscd_mutex_unlock((nscd_acc_data_t *)base);
rootp->s = (struct nss_db_state *)ret;
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_get_nsw_state(
nss_db_root_t *rootp,
nscd_nsw_params_t *params)
{
return (_get_nsw_state_int(rootp, params, NULL));
}
nscd_rc_t
_nscd_get_nsw_state_thread(
nss_db_root_t *rootp,
nscd_nsw_params_t *params)
{
thread_t tid = thr_self();
return (_get_nsw_state_int(rootp, params, &tid));
}
static void
_put_nsw_state_int(
nscd_nsw_state_t *s,
thread_t *tid)
{
nscd_nsw_state_base_t *base;
nscd_state_ctrl_t *ctrl_p;
int thread_only = 0;
char *me = "_put_nsw_state_int";
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "put back a nsw state\n");
if (s == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "nsw state is NULL, nothing to put back\n");
return;
}
/*
* no need to put back if the nsw state is not on any base
* but need to free the resources used
*/
if ((*s->nsw_cfg_p)->nobase == 1) {
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "no base nsw state, freeing resources ...\n");
_nscd_free_nsw_state(s);
return;
}
if (tid != NULL)
thread_only = 1;
base = s->base;
if (_nscd_mutex_lock((nscd_acc_data_t *)base) == NULL) {
/* base has been freed or no longer valid, free the nsw state */
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "nsw state base gone or no longer valid, freeing %p\n", s);
_nscd_free_nsw_state(s);
return;
}
if (thread_only)
ctrl_p = &base->nsw_state_thr;
else
ctrl_p = &base->nsw_state;
_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
_nscd_logit(me, "before returning the nsw state: \n");
_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
_nscd_logit(me, "tid in base = %d\n", base->tid);
_nscd_logit(me, "number of free nsw_state = %d\n",
ctrl_p->free);
_nscd_logit(me, "number od nsw state allocated = %d\n",
ctrl_p->allocated);
_nscd_logit(me, "first nsw state on list = %p\n",
ctrl_p->first);
_nscd_logit(me, "number of waiter = %d\n", ctrl_p->waiter);
}
if (ctrl_p->first != NULL) {
s->next = ctrl_p->first;
ctrl_p->first = s;
} else {
ctrl_p->first = s;
s->next = NULL;
}
ctrl_p->free++;
/*
* Remove reference to the nsswitch state base.
*/
_nscd_release((nscd_acc_data_t *)base);
s->base = NULL;
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "signaling waiter thread_only = %d..\n", thread_only);
if (thread_only && ctrl_p->free == ctrl_p->allocated) {
assert(ctrl_p->first != NULL);
base->used_by_thr = 0;
if (ctrl_p->waiter > 0) {
(void) cond_signal(&base->thr_cond);
}
}
if (!thread_only && ctrl_p->waiter > 0) {
_nscd_cond_signal((nscd_acc_data_t *)base);
}
_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
_nscd_logit(me, "after the nsw state is returned: \n");
_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
_nscd_logit(me, "tid in base = %d\n", base->tid);
_nscd_logit(me, "number of free nsw_state = %d\n",
ctrl_p->free);
_nscd_logit(me, "number od nsw state allocated = %d\n",
ctrl_p->allocated);
_nscd_logit(me, "first nsw state on list = %p\n",
ctrl_p->first);
_nscd_logit(me, "tnumber of waiter = %d\n", ctrl_p->waiter);
}
_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
(me, "done putting back nsw state %p, thread_only = %d\n",
s, thread_only);
_nscd_mutex_unlock((nscd_acc_data_t *)base);
}
void
_nscd_put_nsw_state(
nscd_nsw_state_t *s)
{
_put_nsw_state_int(s, NULL);
}
void
_nscd_put_nsw_state_thread(
nscd_nsw_state_t *s)
{
thread_t tid = thr_self();
_put_nsw_state_int(s, &tid);
}
nscd_rc_t
_nscd_init_nsw_state_base(
int dbi,
int compat_basei,
int lock)
{
int cfgdbi;
nscd_nsw_state_base_t *base = NULL;
char *me = "_nscd_init_nsw_state_base";
if (lock)
(void) rw_rdlock(&nscd_nsw_state_base_lock);
base = (nscd_nsw_state_base_t *)_nscd_alloc(
NSCD_DATA_NSW_STATE_BASE,
sizeof (nscd_nsw_state_base_t),
_nscd_free_nsw_state_base,
NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
if (base == NULL) {
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_ERROR)
(me, "not able to allocate a nsw state base\n");
if (lock)
(void) rw_unlock(&nscd_nsw_state_base_lock);
return (NSCD_NO_MEMORY);
}
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "nsw state base %p allocated\n", base);
/*
* initialize and activate the new nss_nsw_state base
*/
base->dbi = dbi;
if (compat_basei != -1)
cfgdbi = compat_basei;
else
cfgdbi = dbi;
base->nsw_state.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_db;
base->nsw_state_thr.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_thread;
nscd_nsw_state_base[dbi] = (nscd_nsw_state_base_t *)_nscd_set(
(nscd_acc_data_t *)nscd_nsw_state_base[dbi],
(nscd_acc_data_t *)base);
if (lock)
(void) rw_unlock(&nscd_nsw_state_base_lock);
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_init_all_nsw_state_base()
{
int i;
nscd_rc_t rc;
char *me = "_nscd_init_all_nsw_state_base";
(void) rw_rdlock(&nscd_nsw_state_base_lock);
for (i = 0; i < NSCD_NUM_DB; i++) {
rc = _nscd_init_nsw_state_base(i, -1, 0);
if (rc != NSCD_SUCCESS) {
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
NSCD_LOG_LEVEL_ERROR)
(me, "not able to initialize a nsw db state "
"base (%d)\n", i);
(void) rw_unlock(&nscd_nsw_state_base_lock);
return (rc);
}
}
_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
(me, "all nsw state base initialized\n");
(void) rw_unlock(&nscd_nsw_state_base_lock);
return (NSCD_SUCCESS);
}
nscd_rc_t
_nscd_alloc_nsw_state_base()
{
(void) rw_rdlock(&nscd_nsw_state_base_lock);
nscd_nsw_state_base = calloc(NSCD_NUM_DB,
sizeof (nscd_nsw_state_base_t *));
if (nscd_nsw_state_base == NULL) {
(void) rw_unlock(&nscd_nsw_state_base_lock);
return (NSCD_NO_MEMORY);
}
(void) rw_rdlock(&nscd_nsw_state_base_lock);
return (NSCD_SUCCESS);
}