Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| /* | |
| * 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); | |
| } |