xref: /illumos-gate/usr/src/cmd/nscd/nscd_nswstate.c (revision 06e1a714)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <assert.h>
31 #include <string.h>
32 #include "nscd_switch.h"
33 #include "nscd_log.h"
34 
35 /*
36  * nscd_nsw_state_t list for each nss database. Protected
37  * by the readers/writer lock nscd_nsw_state_base_lock.
38  */
39 nscd_nsw_state_base_t **nscd_nsw_state_base;
40 static rwlock_t nscd_nsw_state_base_lock = DEFAULTRWLOCK;
41 
42 static void
43 _nscd_free_nsw_state(
44 	nscd_nsw_state_t	*s)
45 {
46 
47 	int			i;
48 	char			*me = "_nscd_free_nsw_state";
49 
50 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
51 	(me, "freeing nsw state = %p\n", s);
52 
53 	if (s == NULL)
54 		return;
55 
56 	if (s->nsw_cfg_p != NULL)
57 		/*
58 		 * an nsw state without base does not reference
59 		 * count the nsw config data (ie not using a
60 		 * shared one), so the one created for it should
61 		 * be freed
62 		 */
63 		if ((*s->nsw_cfg_p)->nobase != 1)
64 			_nscd_release((nscd_acc_data_t *)s->nsw_cfg_p);
65 		else
66 			_nscd_free_nsw_config(*s->nsw_cfg_p);
67 
68 	if (s->be_db_pp != NULL) {
69 		for (i = 0; i < s->max_src; i++) {
70 			if (s->be_db_pp[i] == NULL)
71 				continue;
72 			_nscd_release((nscd_acc_data_t *)s->be_db_pp[i]);
73 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
74 			(me, "release db be ptr %p\n", s->be_db_pp[i]);
75 		}
76 		free(s->be_db_pp);
77 	}
78 
79 	if (s->be != NULL) {
80 		for (i = 0; i < s->max_src; i++) {
81 			if (s->be[i] == NULL)
82 				continue;
83 			if (s->getent == 1)
84 				(void) NSS_INVOKE_DBOP(s->be[i],
85 					NSS_DBOP_ENDENT, 0);
86 			(void) NSS_INVOKE_DBOP(s->be[i],
87 				NSS_DBOP_DESTRUCTOR, 0);
88 		}
89 		free(s->be);
90 	}
91 
92 	s->base = NULL;
93 
94 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
95 	(me, "nsw state %p freed \n", s);
96 
97 	free(s);
98 }
99 
100 static void
101 _nscd_free_nsw_state_base(
102 	nscd_acc_data_t		*data)
103 {
104 	nscd_nsw_state_base_t	*base = (nscd_nsw_state_base_t *)data;
105 	nscd_nsw_state_t	*s, *ts;
106 	int			i;
107 	char			*me = "_nscd_free_nsw_state_base";
108 
109 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
110 	(me, "freeing db state base %p\n", base);
111 
112 	if (base == NULL)
113 		return;
114 
115 	for (i = 0; i < 2; i++) {
116 		if (i == 1)
117 			s = base->nsw_state.first;
118 		else
119 			s = base->nsw_state_thr.first;
120 
121 		while (s != NULL) {
122 			ts = s->next;
123 			_nscd_free_nsw_state(s);
124 			s = ts;
125 		}
126 	}
127 
128 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
129 	(me, "nsw state base %p freed \n", base);
130 }
131 
132 void
133 _nscd_free_all_nsw_state_base()
134 {
135 	nscd_nsw_state_base_t	*base;
136 	int			i;
137 	char			*me = "_nscd_free_all_nsw_state_base";
138 
139 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG)
140 	(me, "freeing all db state base\n");
141 
142 	(void) rw_wrlock(&nscd_nsw_state_base_lock);
143 	for (i = 0; i < NSCD_NUM_DB; i++) {
144 
145 		base = nscd_nsw_state_base[i];
146 		_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
147 			NSCD_LOG_LEVEL_DEBUG)
148 		(me, "freeing db state base (%d) %p \n", i, base);
149 
150 		if (base == NULL)
151 			continue;
152 
153 		nscd_nsw_state_base[i] = (nscd_nsw_state_base_t *)
154 			_nscd_set((nscd_acc_data_t *)base, NULL);
155 	}
156 	(void) rw_unlock(&nscd_nsw_state_base_lock);
157 }
158 
159 static nscd_nsw_state_t *
160 _nscd_create_nsw_state(
161 	nscd_nsw_params_t	*params)
162 {
163 	nscd_nsw_state_t	*s;
164 	nscd_nsw_config_t	*nsw_cfg;
165 	nscd_db_t		**be_db_p, *be_db;
166 	int			i, nobe = 1;
167 	char			*me = "_nscd_create_nsw_state";
168 
169 
170 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
171 	(me, "creating nsw state...\n");
172 
173 	s = calloc(1, sizeof (nscd_nsw_state_t));
174 	if (s == NULL) {
175 		if ((*s->nsw_cfg_p)->nobase  != 1)
176 			_nscd_release((nscd_acc_data_t *)params->nswcfg);
177 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
178 		(me, "not able to allocate a nsw state\n");
179 		return (NULL);
180 	} else
181 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
182 		(me, "nsw state %p allocated\n", s);
183 
184 	s->dbi = params->dbi;
185 	s->next = NULL;
186 
187 	nsw_cfg = *params->nswcfg;
188 
189 	s->nsw_cfg_p = params->nswcfg;
190 	s->config = nsw_cfg->nsw_config;
191 	s->max_src = nsw_cfg->max_src;
192 	s->p = params->p;
193 
194 	s->be = calloc(s->max_src, sizeof (nss_backend_t **));
195 	if (s->be == NULL) {
196 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
197 		(me, "not able to allocate s->be\n");
198 
199 		_nscd_free_nsw_state(s);
200 		return (NULL);
201 	} else {
202 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
203 		(me, "db be array %p allocated\n", s->be);
204 	}
205 
206 	s->be_db_pp = calloc(s->max_src, sizeof (nscd_db_t ***));
207 	if (s->be_db_pp == NULL) {
208 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
209 		(me, "not able to allocate s->be_db_pp\n");
210 		_nscd_free_nsw_state(s);
211 		return (NULL);
212 	} else {
213 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
214 		(me, "be_db_pp array %p allocated\n", s->be_db_pp);
215 	}
216 
217 	/* create the source:database backends */
218 	for (i = 0;  i < s->max_src;  i++) {
219 		nss_backend_t		*be;
220 		int			srci;
221 		char			*srcn;
222 		const char		*dbn;
223 		struct __nsw_lookup_v1	*lkp;
224 		const nscd_db_entry_t	*dbe;
225 		nscd_be_info_t		*be_info;
226 
227 		if (i == 0)
228 			lkp = s->config->lookups;
229 		else
230 			lkp = lkp->next;
231 		if (lkp == NULL) {
232 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
233 			(me, "error: lkp is NULL\n");
234 			_nscd_free_nsw_state(s);
235 			return (NULL);
236 		}
237 
238 		srci = nsw_cfg->src_idx[i];
239 		srcn = lkp->service_name;
240 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
241 		(me, "source name = %s, index = %d\n", srcn, srci);
242 
243 		be_db_p = (nscd_db_t **)_nscd_get(
244 				(nscd_acc_data_t *)nscd_src_backend_db[srci]);
245 		if (be_db_p == NULL) {
246 			_nscd_free_nsw_state(s);
247 			return (NULL);
248 		}
249 		be_db = *be_db_p;
250 		s->be_db_pp[i] = be_db_p;
251 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
252 		(me, "be db ptr array %p referenced\n", be_db_p);
253 
254 		be_info = NULL;
255 		be = NULL;
256 		dbn = params->p.name;
257 		dbe = _nscd_get_db_entry(be_db, NSCD_DATA_BACKEND_INFO,
258 			(const char *)dbn, NSCD_GET_FIRST_DB_ENTRY, 0);
259 		if (dbe != NULL)
260 			be_info = (nscd_be_info_t *)*(dbe->data_array);
261 
262 		if (be_info == NULL || be_info->be_constr == NULL) {
263 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
264 			(me, "no backend info or be_constr is NULL "
265 			    "for <%s : %s>\n", NSCD_NSW_SRC_NAME(srci),
266 				dbn);
267 		} else
268 			be = (be_info->be_constr)(dbn,
269 				NSCD_NSW_SRC_NAME(srci), 0);
270 
271 		if (be == NULL) {
272 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
273 			(me, "not able to init be for <%s : %s>\n",
274 			NSCD_NSW_SRC_NAME(srci), dbn);
275 
276 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
277 			(me, "releasing db be ptr %p\n", be_db_p);
278 
279 			_nscd_release((nscd_acc_data_t *)be_db_p);
280 			s->be_db_pp[i] = NULL;
281 
282 			continue;
283 		}
284 
285 		s->be[i] = be;
286 		nobe = 0;
287 	}
288 
289 	if (nobe == 1) {
290 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
291 		(me, "NO backend found, returning NULL\n");
292 
293 		_nscd_free_nsw_state(s);
294 		return (NULL);
295 	}
296 
297 	return (s);
298 }
299 
300 static nscd_rc_t
301 _get_nsw_state_int(
302 	nss_db_root_t		*rootp,
303 	nscd_nsw_params_t	*params,
304 	thread_t		*tid)
305 {
306 
307 	nscd_nsw_state_t	*ret = NULL;
308 	nscd_nsw_config_t	**nswcfg;
309 	nscd_nsw_state_base_t	*base;
310 	nscd_state_ctrl_t	*ctrl_p;
311 	int			thread_only = 0, wait_cond = 0;
312 	char			*me = "_get_nsw_state_int";
313 	int			dbi;
314 	nscd_rc_t		rc;
315 
316 	dbi = params->dbi;
317 
318 	/*
319 	 * no nsw state will be reused, if asked to use
320 	 * default config. So create the new structures
321 	 * used by the switch engine and the new nsw state
322 	 */
323 	if (params->p.flags & NSS_USE_DEFAULT_CONFIG) {
324 		rc = _nscd_create_sw_struct(dbi, (char *)params->p.name,
325 			(char *)params->p.default_config, NULL, params);
326 		if (rc != NSCD_SUCCESS)
327 			return (rc);
328 
329 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
330 		(me, "no base nsw config created for %s (sources: %s)\n",
331 				params->p.name, params->p.default_config);
332 
333 		ret = _nscd_create_nsw_state(params);
334 		if (ret == NULL)
335 			return (NSCD_CREATE_NSW_STATE_FAILED);
336 		rootp->s = (struct nss_db_state *)ret;
337 		return (NSCD_SUCCESS);
338 	}
339 
340 	/*
341 	 * if getting a nsw state for a request from the compat
342 	 * backend, create the new switch structures if this
343 	 * is the first time around for a passwd, shadow, group,
344 	 * audit_user, or user_attr database
345 	 */
346 	if (params->compati != -1) {
347 
348 		nscd_nsw_config_t	**nswcfg1;
349 		int			i = params->compati;
350 
351 		nswcfg = (nscd_nsw_config_t **)_nscd_get(
352 			(nscd_acc_data_t *)nscd_nsw_config[i]);
353 
354 		/*
355 		 * if nsw data structures not created yet, get the
356 		 * config string from the passwd_compat or
357 		 * group_compat DB and create the structures
358 		 */
359 		if (nswcfg == NULL) {
360 			nswcfg1 = (nscd_nsw_config_t **)_nscd_get(
361 			(nscd_acc_data_t *)nscd_nsw_config[params->cfgdbi]);
362 			if (nswcfg1 == NULL) {
363 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
364 					NSCD_LOG_LEVEL_ERROR)
365 				(me, "no nsw config for %s\n",
366 					params->p.name);
367 				return (NSCD_CREATE_NSW_STATE_FAILED);
368 			}
369 
370 			rc = _nscd_create_sw_struct(i, params->p.name,
371 				(*nswcfg1)->nsw_cfg_str, NULL, params);
372 			_nscd_release((nscd_acc_data_t *)nswcfg1);
373 			if (rc != NSCD_SUCCESS)
374 				return (rc);
375 
376 			_NSCD_LOG(NSCD_LOG_NSW_STATE,
377 				NSCD_LOG_LEVEL_DEBUG)
378 				(me, "nsw config created for %s (%s)\n",
379 				params->p.name, (*nswcfg1)->nsw_cfg_str);
380 		} else
381 			_nscd_release((nscd_acc_data_t *)nswcfg);
382 	}
383 
384 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
385 	base = nscd_nsw_state_base[dbi];
386 	(void) rw_unlock(&nscd_nsw_state_base_lock);
387 	if (base == NULL)
388 		assert(base != NULL);
389 
390 	/*
391 	 * If list is not empty, return the first one on list.
392 	 * Otherwise, create and return a new db state if the
393 	 * limit is not reached. if reacehed, wait for the 'one
394 	 * is available' signal.
395 	 */
396 	assert(base == (nscd_nsw_state_base_t *)_nscd_mutex_lock(
397 		(nscd_acc_data_t *)base));
398 
399 	if (tid == NULL) {
400 		ctrl_p = &base->nsw_state;
401 	} else {
402 		thread_only = 1;
403 		ctrl_p = &base->nsw_state_thr;
404 
405 		_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
406 			_nscd_logit(me, "per thread nsw state info: \n");
407 			_nscd_logit(me, "tid = %d\n", *tid);
408 			_nscd_logit(me, "tid in base = %d\n", base->tid);
409 			_nscd_logit(me, "number of free nsw_state = %d\n",
410 				ctrl_p->free);
411 			_nscd_logit(me, "number of nsw state allocated = %d\n",
412 				ctrl_p->allocated);
413 			_nscd_logit(me, "first nsw state on list = %p\n",
414 				ctrl_p->first);
415 			_nscd_logit(me, "number of waiter = %d\n",
416 				ctrl_p->waiter);
417 		}
418 	}
419 
420 	if (ctrl_p->first == NULL && ctrl_p->allocated == ctrl_p->max)
421 		wait_cond = 1;
422 	else if (thread_only && base->used_by_thr && base->tid != *tid)
423 		wait_cond = 1;
424 
425 	if (wait_cond) {
426 
427 		ctrl_p->waiter++;
428 
429 		while (wait_cond) {
430 			if (!thread_only)
431 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
432 					NSCD_LOG_LEVEL_DEBUG)
433 				(me, "waiting for nsw state signal\n");
434 			else
435 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
436 					NSCD_LOG_LEVEL_DEBUG)
437 				(me, "waiting for per thread "
438 				    "nsw state signal\n");
439 
440 			if (thread_only) {
441 				_nscd_cond_wait((nscd_acc_data_t *)base,
442 					&base->thr_cond);
443 
444 				if (base->used_by_thr == 0 &&
445 					ctrl_p->first != NULL)
446 					wait_cond = 0;
447 			} else {
448 				_nscd_cond_wait((nscd_acc_data_t *)base, NULL);
449 
450 				if (ctrl_p->first != NULL)
451 					wait_cond = 0;
452 			}
453 
454 			if (!thread_only)
455 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
456 					NSCD_LOG_LEVEL_DEBUG)
457 				(me, "woke from cond wait ...wait_cond = %d\n",
458 					wait_cond);
459 			else
460 
461 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
462 					NSCD_LOG_LEVEL_DEBUG)
463 				(me, "woke from cond wait (per thread) "
464 					"...wait_cond = %d\n", wait_cond);
465 
466 		}
467 
468 		ctrl_p->waiter--;
469 	}
470 
471 	if (ctrl_p->first == NULL) {
472 		int	geti;
473 
474 		/*
475 		 * for lookup calls from the compat backend
476 		 * uses the switch policy for passwd_compat
477 		 * or group_compat
478 		 */
479 		if (params->compati != -1)
480 			geti = params->compati;
481 		else
482 			geti = params->dbi;
483 
484 		params->nswcfg = (nscd_nsw_config_t **)_nscd_get(
485 			(nscd_acc_data_t *)nscd_nsw_config[geti]);
486 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
487 		(me, "got a nsw config %p for index %d\n",
488 			params->nswcfg, geti);
489 
490 		ctrl_p->first = _nscd_create_nsw_state(params);
491 		if (ctrl_p->first != NULL) {
492 			ctrl_p->first->base = base;
493 
494 			if (tid == NULL) {
495 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
496 					NSCD_LOG_LEVEL_DEBUG)
497 				(me, "got a new nsw_state %p\n", ctrl_p->first);
498 			} else {
499 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
500 					NSCD_LOG_LEVEL_DEBUG)
501 				(me, "got a new per thread nsw_state %p\n",
502 				ctrl_p->first);
503 			}
504 			ctrl_p->allocated++;
505 			ctrl_p->free++;
506 		} else {
507 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
508 				(me, "error: unable to obtain a nsw state\n");
509 			_nscd_mutex_unlock((nscd_acc_data_t *)base);
510 			return (NSCD_CREATE_NSW_STATE_FAILED);
511 		}
512 	}
513 
514 	ret = ctrl_p->first;
515 	ctrl_p->first = ret->next;
516 	ret->next = NULL;
517 	ctrl_p->free--;
518 	if (thread_only) {
519 		base->tid = *tid;
520 		base->used_by_thr = 1;
521 
522 		_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
523 			_nscd_logit(me, "\t\t\tgot a per thread nsw "
524 			    "state %p: \n", ret);
525 			_nscd_logit(me, "tid = %d\n", *tid);
526 			_nscd_logit(me, "tid in base = %d\n", base->tid);
527 			_nscd_logit(me, "number of free nsw_state = %d\n",
528 				ctrl_p->free);
529 			_nscd_logit(me, "number od nsw state allocated = %d\n",
530 				ctrl_p->allocated);
531 			_nscd_logit(me, "first nsw state on list = %p\n",
532 				ctrl_p->first);
533 			_nscd_logit(me, "number of waiter = %d\n",
534 				ctrl_p->waiter);
535 		}
536 	}
537 	else
538 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
539 		(me, "got old nsw state %p\n", ret);
540 
541 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
542 
543 	rootp->s = (struct nss_db_state *)ret;
544 
545 	return (NSCD_SUCCESS);
546 }
547 
548 nscd_rc_t
549 _nscd_get_nsw_state(
550 	nss_db_root_t		*rootp,
551 	nscd_nsw_params_t	*params)
552 {
553 	return (_get_nsw_state_int(rootp, params, NULL));
554 }
555 
556 nscd_rc_t
557 _nscd_get_nsw_state_thread(
558 	nss_db_root_t		*rootp,
559 	nscd_nsw_params_t	*params)
560 {
561 	thread_t	tid = thr_self();
562 	return (_get_nsw_state_int(rootp, params, &tid));
563 }
564 
565 
566 static void
567 _put_nsw_state_int(
568 	nscd_nsw_state_t	*s,
569 	thread_t		*tid)
570 {
571 
572 	nscd_nsw_state_base_t	*base;
573 	nscd_state_ctrl_t	*ctrl_p;
574 	int			thread_only = 0;
575 	char			*me = "_put_nsw_state_int";
576 
577 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
578 	(me, "put back a nsw state\n");
579 
580 	if (s == NULL) {
581 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
582 		(me, "nsw state is NULL, nothing to put back\n");
583 		return;
584 	}
585 
586 	/*
587 	 * no need to put back if the nsw state is not on any base
588 	 * but need to free the resources used
589 	 */
590 	if ((*s->nsw_cfg_p)->nobase  == 1) {
591 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
592 		(me, "no base nsw state, freeing resources ...\n");
593 
594 		_nscd_free_nsw_state(s);
595 		return;
596 	}
597 
598 	if (tid != NULL)
599 		thread_only = 1;
600 
601 	base = s->base;
602 
603 	if (_nscd_mutex_lock((nscd_acc_data_t *)base) == NULL) {
604 		/* base has been freed, free this db state */
605 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
606 		(me, "nsw state base has been freed, freeing %p\n", s);
607 		_nscd_free_nsw_state(s);
608 		return;
609 	}
610 
611 	if (thread_only)
612 		ctrl_p = &base->nsw_state_thr;
613 	else
614 		ctrl_p = &base->nsw_state;
615 
616 	_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
617 		_nscd_logit(me, "before returning the nsw state: \n");
618 		_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
619 		_nscd_logit(me, "tid in base = %d\n", base->tid);
620 		_nscd_logit(me, "number of free nsw_state = %d\n",
621 			ctrl_p->free);
622 		_nscd_logit(me, "number od nsw state allocated = %d\n",
623 			ctrl_p->allocated);
624 		_nscd_logit(me, "first nsw state on list = %p\n",
625 			ctrl_p->first);
626 		_nscd_logit(me, "number of waiter = %d\n",
627 			ctrl_p->waiter);
628 	}
629 
630 	if (ctrl_p->first != NULL) {
631 		s->next = ctrl_p->first;
632 		ctrl_p->first = s;
633 	} else {
634 		ctrl_p->first = s;
635 		s->next = NULL;
636 	}
637 	ctrl_p->free++;
638 
639 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
640 	(me, "signaling waiter thread_only = %d..\n", thread_only);
641 
642 	if (thread_only && ctrl_p->free == ctrl_p->allocated) {
643 		assert(ctrl_p->first != NULL);
644 		base->used_by_thr = 0;
645 		if (ctrl_p->waiter > 0) {
646 			(void) cond_signal(&base->thr_cond);
647 		}
648 	}
649 
650 	if (!thread_only && ctrl_p->waiter > 0) {
651 
652 		_nscd_cond_signal((nscd_acc_data_t *)base);
653 	}
654 
655 	_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
656 		_nscd_logit(me, "after the nsw state is returned: \n");
657 		_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
658 		_nscd_logit(me, "tid in base = %d\n", base->tid);
659 		_nscd_logit(me, "number of free nsw_state = %d\n",
660 			ctrl_p->free);
661 		_nscd_logit(me, "number od nsw state allocated = %d\n",
662 			ctrl_p->allocated);
663 		_nscd_logit(me, "first nsw state on list = %p\n",
664 			ctrl_p->first);
665 		_nscd_logit(me, "tnumber of waiter = %d\n",
666 			ctrl_p->waiter);
667 	}
668 
669 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
670 	(me, "done putting back nsw state %p, thread_only = %d\n",
671 			s, thread_only);
672 
673 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
674 
675 }
676 
677 void
678 _nscd_put_nsw_state(
679 	nscd_nsw_state_t	*s)
680 {
681 	_put_nsw_state_int(s, NULL);
682 }
683 
684 void
685 _nscd_put_nsw_state_thread(
686 	nscd_nsw_state_t	*s)
687 {
688 	thread_t		tid = thr_self();
689 	_put_nsw_state_int(s, &tid);
690 }
691 
692 nscd_rc_t
693 _nscd_init_nsw_state_base(
694 	int			dbi,
695 	int			lock)
696 {
697 	nscd_nsw_state_base_t	*base = NULL;
698 	char			*me = "_nscd_init_nsw_state_base";
699 
700 	if (lock)
701 		(void) rw_rdlock(&nscd_nsw_state_base_lock);
702 
703 	base = (nscd_nsw_state_base_t *)_nscd_alloc(
704 		NSCD_DATA_NSW_STATE_BASE,
705 		sizeof (nscd_nsw_state_base_t),
706 		_nscd_free_nsw_state_base,
707 		NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
708 
709 	if (base == NULL) {
710 		_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
711 			NSCD_LOG_LEVEL_ERROR)
712 		(me, "not able to allocate a nsw state base\n");
713 		if (lock)
714 			(void) rw_unlock(&nscd_nsw_state_base_lock);
715 		return (NSCD_NO_MEMORY);
716 	}
717 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
718 			NSCD_LOG_LEVEL_DEBUG)
719 		(me, "nsw state base %p allocated\n", base);
720 
721 	/*
722 	 * initialize and activate the new nss_nsw_state base
723 	 */
724 	base->dbi = dbi;
725 	base->nsw_state.max = NSCD_SW_CFG(dbi).max_nsw_state_per_db;
726 	base->nsw_state_thr.max = NSCD_SW_CFG(dbi).max_nsw_state_per_thread;
727 
728 	nscd_nsw_state_base[dbi] = (nscd_nsw_state_base_t *)_nscd_set(
729 		(nscd_acc_data_t *)nscd_nsw_state_base[dbi],
730 		(nscd_acc_data_t *)base);
731 
732 	if (lock)
733 		(void) rw_unlock(&nscd_nsw_state_base_lock);
734 
735 	return (NSCD_SUCCESS);
736 }
737 
738 nscd_rc_t
739 _nscd_init_all_nsw_state_base()
740 {
741 	int			i;
742 	nscd_rc_t		rc;
743 	char			*me = "_nscd_init_all_nsw_state_base";
744 
745 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
746 
747 	for (i = 0; i < NSCD_NUM_DB; i++) {
748 
749 		rc = _nscd_init_nsw_state_base(i, 0);
750 
751 		if (rc != NSCD_SUCCESS) {
752 			_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
753 				NSCD_LOG_LEVEL_ERROR)
754 			(me, "not able to initialize a nsw db state "
755 				"base (%d)\n", i);
756 
757 			(void) rw_unlock(&nscd_nsw_state_base_lock);
758 			return (rc);
759 		}
760 	}
761 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
762 			NSCD_LOG_LEVEL_DEBUG)
763 	(me, "all nsw state base initialized\n");
764 
765 	(void) rw_unlock(&nscd_nsw_state_base_lock);
766 
767 	return (NSCD_SUCCESS);
768 }
769 
770 nscd_rc_t
771 _nscd_alloc_nsw_state_base()
772 {
773 
774 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
775 
776 	nscd_nsw_state_base = calloc(NSCD_NUM_DB,
777 		sizeof (nscd_nsw_state_base_t *));
778 	if (nscd_nsw_state_base == NULL) {
779 		(void) rw_unlock(&nscd_nsw_state_base_lock);
780 		return (NSCD_NO_MEMORY);
781 	}
782 
783 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
784 
785 	return (NSCD_SUCCESS);
786 }
787