xref: /illumos-gate/usr/src/cmd/nscd/nscd_nswstate.c (revision ad0e80f7538b612141768bfda60009eb76550ee7)
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, -1, (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 		dbi = i;
352 
353 		nswcfg = (nscd_nsw_config_t **)_nscd_get(
354 			(nscd_acc_data_t *)nscd_nsw_config[i]);
355 
356 		/*
357 		 * if nsw data structures not created yet, get the
358 		 * config string from the passwd_compat or
359 		 * group_compat DB and create the structures
360 		 */
361 		if (nswcfg == NULL) {
362 			nswcfg1 = (nscd_nsw_config_t **)_nscd_get(
363 			(nscd_acc_data_t *)nscd_nsw_config[params->cfgdbi]);
364 			if (nswcfg1 == NULL) {
365 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
366 					NSCD_LOG_LEVEL_ERROR)
367 				(me, "no nsw config for %s\n",
368 					params->p.name);
369 				return (NSCD_CREATE_NSW_STATE_FAILED);
370 			}
371 
372 			rc = _nscd_create_sw_struct(i, params->cfgdbi,
373 				params->p.name, (*nswcfg1)->nsw_cfg_str,
374 				NULL, params);
375 			_nscd_release((nscd_acc_data_t *)nswcfg1);
376 			if (rc != NSCD_SUCCESS)
377 				return (rc);
378 
379 			_NSCD_LOG(NSCD_LOG_NSW_STATE,
380 				NSCD_LOG_LEVEL_DEBUG)
381 				(me, "nsw config created for %s (%s)\n",
382 				params->p.name, (*nswcfg1)->nsw_cfg_str);
383 		} else
384 			_nscd_release((nscd_acc_data_t *)nswcfg);
385 	}
386 
387 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
388 	base = nscd_nsw_state_base[dbi];
389 	(void) rw_unlock(&nscd_nsw_state_base_lock);
390 	if (base == NULL)
391 		assert(base != NULL);
392 
393 	/*
394 	 * If list is not empty, return the first one on list.
395 	 * Otherwise, create and return a new db state if the
396 	 * limit is not reached. if reacehed, wait for the 'one
397 	 * is available' signal.
398 	 */
399 	assert(base == (nscd_nsw_state_base_t *)_nscd_mutex_lock(
400 		(nscd_acc_data_t *)base));
401 
402 	if (tid == NULL) {
403 		ctrl_p = &base->nsw_state;
404 	} else {
405 		thread_only = 1;
406 		ctrl_p = &base->nsw_state_thr;
407 
408 		_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
409 			_nscd_logit(me, "per thread nsw state info: \n");
410 			_nscd_logit(me, "tid = %d\n", *tid);
411 			_nscd_logit(me, "tid in base = %d\n", base->tid);
412 			_nscd_logit(me, "number of free nsw_state = %d\n",
413 				ctrl_p->free);
414 			_nscd_logit(me, "number of nsw state allocated = %d\n",
415 				ctrl_p->allocated);
416 			_nscd_logit(me, "first nsw state on list = %p\n",
417 				ctrl_p->first);
418 			_nscd_logit(me, "number of waiter = %d\n",
419 				ctrl_p->waiter);
420 		}
421 	}
422 
423 	if (ctrl_p->first == NULL && ctrl_p->allocated == ctrl_p->max)
424 		wait_cond = 1;
425 	else if (thread_only && base->used_by_thr && base->tid != *tid)
426 		wait_cond = 1;
427 
428 	if (wait_cond) {
429 
430 		ctrl_p->waiter++;
431 
432 		while (wait_cond) {
433 			if (!thread_only)
434 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
435 					NSCD_LOG_LEVEL_DEBUG)
436 				(me, "waiting for nsw state signal\n");
437 			else
438 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
439 					NSCD_LOG_LEVEL_DEBUG)
440 				(me, "waiting for per thread "
441 				    "nsw state signal\n");
442 
443 			if (thread_only) {
444 				_nscd_cond_wait((nscd_acc_data_t *)base,
445 					&base->thr_cond);
446 
447 				if (base->used_by_thr == 0 &&
448 					ctrl_p->first != NULL)
449 					wait_cond = 0;
450 			} else {
451 				_nscd_cond_wait((nscd_acc_data_t *)base, NULL);
452 
453 				if (ctrl_p->first != NULL)
454 					wait_cond = 0;
455 			}
456 
457 			if (!thread_only)
458 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
459 					NSCD_LOG_LEVEL_DEBUG)
460 				(me, "woke from cond wait ...wait_cond = %d\n",
461 					wait_cond);
462 			else
463 
464 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
465 					NSCD_LOG_LEVEL_DEBUG)
466 				(me, "woke from cond wait (per thread) "
467 					"...wait_cond = %d\n", wait_cond);
468 
469 		}
470 
471 		ctrl_p->waiter--;
472 	}
473 
474 	if (ctrl_p->first == NULL) {
475 		int	geti;
476 
477 		/*
478 		 * for lookup calls from the compat backend
479 		 * uses the switch policy for passwd_compat
480 		 * or group_compat
481 		 */
482 		if (params->compati != -1)
483 			geti = params->compati;
484 		else
485 			geti = params->dbi;
486 
487 		params->nswcfg = (nscd_nsw_config_t **)_nscd_get(
488 			(nscd_acc_data_t *)nscd_nsw_config[geti]);
489 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
490 		(me, "got a nsw config %p for index %d\n",
491 			params->nswcfg, geti);
492 
493 		ctrl_p->first = _nscd_create_nsw_state(params);
494 		if (ctrl_p->first != NULL) {
495 			ctrl_p->first->base = base;
496 
497 			if (tid == NULL) {
498 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
499 					NSCD_LOG_LEVEL_DEBUG)
500 				(me, "got a new nsw_state %p\n", ctrl_p->first);
501 			} else {
502 				_NSCD_LOG(NSCD_LOG_NSW_STATE,
503 					NSCD_LOG_LEVEL_DEBUG)
504 				(me, "got a new per thread nsw_state %p\n",
505 				ctrl_p->first);
506 			}
507 			ctrl_p->allocated++;
508 			ctrl_p->free++;
509 		} else {
510 			_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
511 				(me, "error: unable to obtain a nsw state\n");
512 			_nscd_mutex_unlock((nscd_acc_data_t *)base);
513 			return (NSCD_CREATE_NSW_STATE_FAILED);
514 		}
515 	}
516 
517 	ret = ctrl_p->first;
518 	ctrl_p->first = ret->next;
519 	ret->next = NULL;
520 	ctrl_p->free--;
521 	if (thread_only) {
522 		base->tid = *tid;
523 		base->used_by_thr = 1;
524 
525 		_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
526 			_nscd_logit(me, "\t\t\tgot a per thread nsw "
527 			    "state %p: \n", ret);
528 			_nscd_logit(me, "tid = %d\n", *tid);
529 			_nscd_logit(me, "tid in base = %d\n", base->tid);
530 			_nscd_logit(me, "number of free nsw_state = %d\n",
531 				ctrl_p->free);
532 			_nscd_logit(me, "number od nsw state allocated = %d\n",
533 				ctrl_p->allocated);
534 			_nscd_logit(me, "first nsw state on list = %p\n",
535 				ctrl_p->first);
536 			_nscd_logit(me, "number of waiter = %d\n",
537 				ctrl_p->waiter);
538 		}
539 	}
540 	else
541 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
542 		(me, "got old nsw state %p\n", ret);
543 
544 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
545 
546 	rootp->s = (struct nss_db_state *)ret;
547 
548 	return (NSCD_SUCCESS);
549 }
550 
551 nscd_rc_t
552 _nscd_get_nsw_state(
553 	nss_db_root_t		*rootp,
554 	nscd_nsw_params_t	*params)
555 {
556 	return (_get_nsw_state_int(rootp, params, NULL));
557 }
558 
559 nscd_rc_t
560 _nscd_get_nsw_state_thread(
561 	nss_db_root_t		*rootp,
562 	nscd_nsw_params_t	*params)
563 {
564 	thread_t	tid = thr_self();
565 	return (_get_nsw_state_int(rootp, params, &tid));
566 }
567 
568 
569 static void
570 _put_nsw_state_int(
571 	nscd_nsw_state_t	*s,
572 	thread_t		*tid)
573 {
574 
575 	nscd_nsw_state_base_t	*base;
576 	nscd_state_ctrl_t	*ctrl_p;
577 	int			thread_only = 0;
578 	char			*me = "_put_nsw_state_int";
579 
580 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
581 	(me, "put back a nsw state\n");
582 
583 	if (s == NULL) {
584 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
585 		(me, "nsw state is NULL, nothing to put back\n");
586 		return;
587 	}
588 
589 	/*
590 	 * no need to put back if the nsw state is not on any base
591 	 * but need to free the resources used
592 	 */
593 	if ((*s->nsw_cfg_p)->nobase  == 1) {
594 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
595 		(me, "no base nsw state, freeing resources ...\n");
596 
597 		_nscd_free_nsw_state(s);
598 		return;
599 	}
600 
601 	if (tid != NULL)
602 		thread_only = 1;
603 
604 	base = s->base;
605 
606 	if (_nscd_mutex_lock((nscd_acc_data_t *)base) == NULL) {
607 		/* base has been freed, free this db state */
608 		_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
609 		(me, "nsw state base has been freed, freeing %p\n", s);
610 		_nscd_free_nsw_state(s);
611 		return;
612 	}
613 
614 	if (thread_only)
615 		ctrl_p = &base->nsw_state_thr;
616 	else
617 		ctrl_p = &base->nsw_state;
618 
619 	_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
620 		_nscd_logit(me, "before returning the nsw state: \n");
621 		_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
622 		_nscd_logit(me, "tid in base = %d\n", base->tid);
623 		_nscd_logit(me, "number of free nsw_state = %d\n",
624 			ctrl_p->free);
625 		_nscd_logit(me, "number od nsw state allocated = %d\n",
626 			ctrl_p->allocated);
627 		_nscd_logit(me, "first nsw state on list = %p\n",
628 			ctrl_p->first);
629 		_nscd_logit(me, "number of waiter = %d\n",
630 			ctrl_p->waiter);
631 	}
632 
633 	if (ctrl_p->first != NULL) {
634 		s->next = ctrl_p->first;
635 		ctrl_p->first = s;
636 	} else {
637 		ctrl_p->first = s;
638 		s->next = NULL;
639 	}
640 	ctrl_p->free++;
641 
642 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
643 	(me, "signaling waiter thread_only = %d..\n", thread_only);
644 
645 	if (thread_only && ctrl_p->free == ctrl_p->allocated) {
646 		assert(ctrl_p->first != NULL);
647 		base->used_by_thr = 0;
648 		if (ctrl_p->waiter > 0) {
649 			(void) cond_signal(&base->thr_cond);
650 		}
651 	}
652 
653 	if (!thread_only && ctrl_p->waiter > 0) {
654 
655 		_nscd_cond_signal((nscd_acc_data_t *)base);
656 	}
657 
658 	_NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) {
659 		_nscd_logit(me, "after the nsw state is returned: \n");
660 		_nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid);
661 		_nscd_logit(me, "tid in base = %d\n", base->tid);
662 		_nscd_logit(me, "number of free nsw_state = %d\n",
663 			ctrl_p->free);
664 		_nscd_logit(me, "number od nsw state allocated = %d\n",
665 			ctrl_p->allocated);
666 		_nscd_logit(me, "first nsw state on list = %p\n",
667 			ctrl_p->first);
668 		_nscd_logit(me, "tnumber of waiter = %d\n",
669 			ctrl_p->waiter);
670 	}
671 
672 	_NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG)
673 	(me, "done putting back nsw state %p, thread_only = %d\n",
674 			s, thread_only);
675 
676 	_nscd_mutex_unlock((nscd_acc_data_t *)base);
677 
678 }
679 
680 void
681 _nscd_put_nsw_state(
682 	nscd_nsw_state_t	*s)
683 {
684 	_put_nsw_state_int(s, NULL);
685 }
686 
687 void
688 _nscd_put_nsw_state_thread(
689 	nscd_nsw_state_t	*s)
690 {
691 	thread_t		tid = thr_self();
692 	_put_nsw_state_int(s, &tid);
693 }
694 
695 nscd_rc_t
696 _nscd_init_nsw_state_base(
697 	int			dbi,
698 	int			compat_basei,
699 	int			lock)
700 {
701 	int			cfgdbi;
702 	nscd_nsw_state_base_t	*base = NULL;
703 	char			*me = "_nscd_init_nsw_state_base";
704 
705 	if (lock)
706 		(void) rw_rdlock(&nscd_nsw_state_base_lock);
707 
708 	base = (nscd_nsw_state_base_t *)_nscd_alloc(
709 		NSCD_DATA_NSW_STATE_BASE,
710 		sizeof (nscd_nsw_state_base_t),
711 		_nscd_free_nsw_state_base,
712 		NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND);
713 
714 	if (base == NULL) {
715 		_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
716 			NSCD_LOG_LEVEL_ERROR)
717 		(me, "not able to allocate a nsw state base\n");
718 		if (lock)
719 			(void) rw_unlock(&nscd_nsw_state_base_lock);
720 		return (NSCD_NO_MEMORY);
721 	}
722 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
723 			NSCD_LOG_LEVEL_DEBUG)
724 		(me, "nsw state base %p allocated\n", base);
725 
726 	/*
727 	 * initialize and activate the new nss_nsw_state base
728 	 */
729 	base->dbi = dbi;
730 	if (compat_basei != -1)
731 		cfgdbi = compat_basei;
732 	else
733 		cfgdbi = dbi;
734 
735 	base->nsw_state.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_db;
736 	base->nsw_state_thr.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_thread;
737 
738 	nscd_nsw_state_base[dbi] = (nscd_nsw_state_base_t *)_nscd_set(
739 		(nscd_acc_data_t *)nscd_nsw_state_base[dbi],
740 		(nscd_acc_data_t *)base);
741 
742 	if (lock)
743 		(void) rw_unlock(&nscd_nsw_state_base_lock);
744 
745 	return (NSCD_SUCCESS);
746 }
747 
748 nscd_rc_t
749 _nscd_init_all_nsw_state_base()
750 {
751 	int			i;
752 	nscd_rc_t		rc;
753 	char			*me = "_nscd_init_all_nsw_state_base";
754 
755 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
756 
757 	for (i = 0; i < NSCD_NUM_DB; i++) {
758 
759 		rc = _nscd_init_nsw_state_base(i, -1, 0);
760 
761 		if (rc != NSCD_SUCCESS) {
762 			_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
763 				NSCD_LOG_LEVEL_ERROR)
764 			(me, "not able to initialize a nsw db state "
765 				"base (%d)\n", i);
766 
767 			(void) rw_unlock(&nscd_nsw_state_base_lock);
768 			return (rc);
769 		}
770 	}
771 	_NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG,
772 			NSCD_LOG_LEVEL_DEBUG)
773 	(me, "all nsw state base initialized\n");
774 
775 	(void) rw_unlock(&nscd_nsw_state_base_lock);
776 
777 	return (NSCD_SUCCESS);
778 }
779 
780 nscd_rc_t
781 _nscd_alloc_nsw_state_base()
782 {
783 
784 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
785 
786 	nscd_nsw_state_base = calloc(NSCD_NUM_DB,
787 		sizeof (nscd_nsw_state_base_t *));
788 	if (nscd_nsw_state_base == NULL) {
789 		(void) rw_unlock(&nscd_nsw_state_base_lock);
790 		return (NSCD_NO_MEMORY);
791 	}
792 
793 	(void) rw_rdlock(&nscd_nsw_state_base_lock);
794 
795 	return (NSCD_SUCCESS);
796 }
797