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 (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <assert.h> 28 #include <string.h> 29 #include "nscd_switch.h" 30 #include "nscd_log.h" 31 32 /* 33 * nscd_nsw_state_t list for each nss database. Protected 34 * by the readers/writer lock nscd_nsw_state_base_lock. 35 */ 36 nscd_nsw_state_base_t **nscd_nsw_state_base; 37 static rwlock_t nscd_nsw_state_base_lock = DEFAULTRWLOCK; 38 39 static void 40 _nscd_free_nsw_state( 41 nscd_nsw_state_t *s) 42 { 43 44 int i; 45 char *me = "_nscd_free_nsw_state"; 46 47 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 48 (me, "freeing nsw state = %p\n", s); 49 50 if (s == NULL) 51 return; 52 53 if (s->nsw_cfg_p != NULL) 54 /* 55 * an nsw state without base does not reference 56 * count the nsw config data (ie not using a 57 * shared one), so the one created for it should 58 * be freed 59 */ 60 if ((*s->nsw_cfg_p)->nobase != 1) 61 _nscd_release((nscd_acc_data_t *)s->nsw_cfg_p); 62 else 63 (void) _nscd_set((nscd_acc_data_t *)s->nsw_cfg_p, NULL); 64 65 if (s->be_db_pp != NULL) { 66 for (i = 0; i < s->max_src; i++) { 67 if (s->be_db_pp[i] == NULL) 68 continue; 69 _nscd_release((nscd_acc_data_t *)s->be_db_pp[i]); 70 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 71 (me, "release db be ptr %p\n", s->be_db_pp[i]); 72 } 73 free(s->be_db_pp); 74 } 75 76 if (s->be != NULL) { 77 for (i = 0; i < s->max_src; i++) { 78 if (s->be[i] == NULL) 79 continue; 80 if (s->getent == 1) 81 (void) NSS_INVOKE_DBOP(s->be[i], 82 NSS_DBOP_ENDENT, 0); 83 (void) NSS_INVOKE_DBOP(s->be[i], 84 NSS_DBOP_DESTRUCTOR, 0); 85 } 86 free(s->be); 87 } 88 89 if (s->be_constr != NULL) 90 free(s->be_constr); 91 92 if (s->be_version_p != NULL) 93 free(s->be_version_p); 94 95 /* remove reference to the nsw state base */ 96 if (s->base != NULL) { 97 _nscd_release((nscd_acc_data_t *)s->base); 98 s->base = NULL; 99 } 100 101 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 102 (me, "nsw state %p freed \n", s); 103 104 free(s); 105 } 106 107 static void 108 _nscd_free_nsw_state_base( 109 nscd_acc_data_t *data) 110 { 111 nscd_nsw_state_base_t *base = (nscd_nsw_state_base_t *)data; 112 nscd_nsw_state_t *s, *ts; 113 int i; 114 char *me = "_nscd_free_nsw_state_base"; 115 116 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 117 (me, "freeing db state base %p\n", base); 118 119 if (base == NULL) 120 return; 121 122 for (i = 0; i < 2; i++) { 123 if (i == 1) 124 s = base->nsw_state.first; 125 else 126 s = base->nsw_state_thr.first; 127 128 while (s != NULL) { 129 ts = s->next; 130 _nscd_free_nsw_state(s); 131 s = ts; 132 } 133 } 134 135 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 136 (me, "nsw state base %p freed \n", base); 137 } 138 139 void 140 _nscd_free_all_nsw_state_base() 141 { 142 nscd_nsw_state_base_t *base; 143 int i; 144 char *me = "_nscd_free_all_nsw_state_base"; 145 146 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 147 (me, "freeing all db state base\n"); 148 149 (void) rw_wrlock(&nscd_nsw_state_base_lock); 150 for (i = 0; i < NSCD_NUM_DB; i++) { 151 152 base = nscd_nsw_state_base[i]; 153 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, 154 NSCD_LOG_LEVEL_DEBUG) 155 (me, "freeing db state base (%d) %p \n", i, base); 156 157 if (base == NULL) 158 continue; 159 160 nscd_nsw_state_base[i] = (nscd_nsw_state_base_t *) 161 _nscd_set((nscd_acc_data_t *)base, NULL); 162 } 163 (void) rw_unlock(&nscd_nsw_state_base_lock); 164 } 165 166 static nscd_nsw_state_t * 167 _nscd_create_nsw_state( 168 nscd_nsw_params_t *params) 169 { 170 nscd_nsw_state_t *s; 171 nscd_nsw_config_t *nsw_cfg; 172 nscd_db_t **be_db_p, *be_db; 173 int i, nobe = 1; 174 char *me = "_nscd_create_nsw_state"; 175 176 177 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 178 (me, "creating nsw state...\n"); 179 180 s = calloc(1, sizeof (nscd_nsw_state_t)); 181 if (s == NULL) { 182 if ((*s->nsw_cfg_p)->nobase != 1) 183 _nscd_release((nscd_acc_data_t *)params->nswcfg); 184 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 185 (me, "not able to allocate a nsw state\n"); 186 return (NULL); 187 } else 188 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 189 (me, "nsw state %p allocated\n", s); 190 191 s->dbi = params->dbi; 192 s->next = NULL; 193 194 nsw_cfg = *params->nswcfg; 195 196 s->nsw_cfg_p = params->nswcfg; 197 s->config = nsw_cfg->nsw_config; 198 s->max_src = nsw_cfg->max_src; 199 s->p = params->p; 200 201 s->be = calloc(s->max_src, sizeof (nss_backend_t **)); 202 if (s->be == NULL) { 203 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 204 (me, "not able to allocate s->be\n"); 205 206 _nscd_free_nsw_state(s); 207 return (NULL); 208 } else { 209 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 210 (me, "db be array %p allocated\n", s->be); 211 } 212 213 s->be_constr = (nss_backend_constr_t *)calloc(s->max_src, 214 sizeof (nss_backend_constr_t)); 215 if (s->be_constr == NULL) { 216 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 217 (me, "not able to allocate s->be_constr\n"); 218 219 _nscd_free_nsw_state(s); 220 return (NULL); 221 } else { 222 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 223 (me, "db be constructor array %p allocated\n", s->be_constr); 224 } 225 226 s->be_version_p = (void **)calloc(s->max_src, sizeof (void *)); 227 if (s->be_version_p == NULL) { 228 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 229 (me, "not able to allocate s->be_version_p\n"); 230 231 _nscd_free_nsw_state(s); 232 return (NULL); 233 } else { 234 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 235 (me, "db be version ptr array %p allocated\n", s->be_version_p); 236 } 237 238 s->be_db_pp = calloc(s->max_src, sizeof (nscd_db_t ***)); 239 if (s->be_db_pp == NULL) { 240 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 241 (me, "not able to allocate s->be_db_pp\n"); 242 _nscd_free_nsw_state(s); 243 return (NULL); 244 } else { 245 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 246 (me, "be_db_pp array %p allocated\n", s->be_db_pp); 247 } 248 249 /* create the source:database backends */ 250 for (i = 0; i < s->max_src; i++) { 251 nss_backend_t *be; 252 int srci; 253 char *srcn; 254 const char *dbn; 255 struct __nsw_lookup_v1 *lkp; 256 const nscd_db_entry_t *dbe; 257 nscd_be_info_t *be_info; 258 259 if (i == 0) 260 lkp = s->config->lookups; 261 else 262 lkp = lkp->next; 263 if (lkp == NULL) { 264 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 265 (me, "error: lkp is NULL\n"); 266 _nscd_free_nsw_state(s); 267 return (NULL); 268 } 269 270 srci = nsw_cfg->src_idx[i]; 271 srcn = lkp->service_name; 272 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 273 (me, "source name = %s, index = %d\n", srcn, srci); 274 275 be_db_p = (nscd_db_t **)_nscd_get( 276 (nscd_acc_data_t *)nscd_src_backend_db[srci]); 277 if (be_db_p == NULL) { 278 _nscd_free_nsw_state(s); 279 return (NULL); 280 } 281 be_db = *be_db_p; 282 s->be_db_pp[i] = be_db_p; 283 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 284 (me, "be db ptr array %p referenced\n", be_db_p); 285 286 be_info = NULL; 287 be = NULL; 288 dbn = params->p.name; 289 dbe = _nscd_get_db_entry(be_db, NSCD_DATA_BACKEND_INFO, 290 (const char *)dbn, NSCD_GET_FIRST_DB_ENTRY, 0); 291 if (dbe != NULL) 292 be_info = (nscd_be_info_t *)*(dbe->data_array); 293 294 if (be_info == NULL || be_info->be_constr == NULL) { 295 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 296 (me, "no backend info or be_constr is NULL " 297 "for <%s : %s>\n", NSCD_NSW_SRC_NAME(srci), 298 dbn); 299 } else { 300 s->be_constr[i] = be_info->be_constr; 301 be = (be_info->be_constr)(dbn, 302 NSCD_NSW_SRC_NAME(srci), 0); 303 if (be == NULL) 304 s->recheck_be = nscd_true; 305 } 306 307 if (be == NULL) { 308 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 309 (me, "not able to init be for <%s : %s>\n", 310 NSCD_NSW_SRC_NAME(srci), dbn); 311 312 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 313 (me, "releasing db be ptr %p\n", be_db_p); 314 315 _nscd_release((nscd_acc_data_t *)be_db_p); 316 s->be_db_pp[i] = NULL; 317 318 continue; 319 } 320 321 s->be[i] = be; 322 s->be_version_p[i] = be_info->be_version; 323 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 324 (me, "backend version is %p\n", be_info->be_version); 325 nobe = 0; 326 } 327 328 if (nobe == 1) { 329 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 330 (me, "NO backend found, returning NULL\n"); 331 332 _nscd_free_nsw_state(s); 333 return (NULL); 334 } 335 336 return (s); 337 } 338 339 /* 340 * Try to initialize the backend instances one more time 341 * in case the dependencies the backend libraries depend 342 * on are now available 343 */ 344 static void 345 check_be_array( 346 nscd_nsw_state_t *s) 347 { 348 int i; 349 char *dbn; 350 char *srcn; 351 struct __nsw_lookup_v1 *lkp; 352 353 dbn = NSCD_NSW_DB_NAME(s->dbi); 354 355 s->recheck_be = nscd_false; 356 for (i = 0; i < s->max_src; i++) { 357 358 if (i == 0) 359 lkp = s->config->lookups; 360 else 361 lkp = lkp->next; 362 if (lkp == NULL) 363 return; 364 365 srcn = lkp->service_name; 366 367 /* 368 * it is possible that 's->be[i]' could not be 369 * initialized earlier due to a dependency not 370 * yet available (e.g., nis on domain name), 371 * try to initialize one more time 372 */ 373 if (s->be[i] == NULL && s->be_constr[i] != NULL) { 374 s->be[i] = (s->be_constr[i])(dbn, srcn, 0); 375 if (s->be[i] == NULL) 376 s->recheck_be = nscd_true; 377 } 378 } 379 } 380 381 static nscd_rc_t 382 _get_nsw_state_int( 383 nss_db_root_t *rootp, 384 nscd_nsw_params_t *params, 385 thread_t *tid) 386 { 387 388 nscd_nsw_state_t *ret = NULL; 389 nscd_nsw_config_t **nswcfg; 390 nscd_nsw_state_base_t *base; 391 nscd_state_ctrl_t *ctrl_p; 392 int thread_only = 0, wait_cond = 0; 393 char *me = "_get_nsw_state_int"; 394 int dbi; 395 nscd_rc_t rc; 396 397 dbi = params->dbi; 398 399 /* 400 * no nsw state will be reused, if asked to use 401 * default config. So create the new structures 402 * used by the switch engine and the new nsw state 403 */ 404 if (params->p.flags & NSS_USE_DEFAULT_CONFIG) { 405 rc = _nscd_create_sw_struct(dbi, -1, (char *)params->p.name, 406 (char *)params->p.default_config, NULL, params); 407 if (rc != NSCD_SUCCESS) 408 return (rc); 409 410 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 411 (me, "no base nsw config created for %s (sources: %s)\n", 412 params->p.name, params->p.default_config); 413 414 ret = _nscd_create_nsw_state(params); 415 if (ret == NULL) 416 return (NSCD_CREATE_NSW_STATE_FAILED); 417 rootp->s = (struct nss_db_state *)ret; 418 return (NSCD_SUCCESS); 419 } 420 421 /* 422 * if getting a nsw state for a request from the compat 423 * backend, create the new switch structures if this 424 * is the first time around for a passwd, shadow, group, 425 * or user_attr database 426 */ 427 if (params->compati != -1) { 428 429 nscd_nsw_config_t **nswcfg1, **nswcfg2; 430 int i = params->compati; 431 432 dbi = i; 433 434 /* 435 * retrieve the pointer space which contains a 436 * pointer pointing to the nsswitch config 437 * structure for the compat backend 438 */ 439 nswcfg = (nscd_nsw_config_t **)_nscd_get( 440 (nscd_acc_data_t *)nscd_nsw_config[i]); 441 442 /* 443 * If nsswitch config structure not created yet, 444 * get the config string from the passwd_compat 445 * or group_compat DB and create the structure. 446 */ 447 if (*nswcfg == NULL) { 448 /* Wait first if it's being created. */ 449 nswcfg2 = (nscd_nsw_config_t **)_nscd_mutex_lock( 450 (nscd_acc_data_t *)nscd_nsw_config[i]); 451 452 /* still not created yet */ 453 if (*nswcfg2 == NULL) { 454 /* 455 * get the nsswitch config string specified 456 * for passwd_compat or group_compat 457 */ 458 nswcfg1 = (nscd_nsw_config_t **)_nscd_get( 459 (nscd_acc_data_t *) 460 nscd_nsw_config[params->cfgdbi]); 461 if (nswcfg1 == NULL) { 462 _NSCD_LOG(NSCD_LOG_NSW_STATE, 463 NSCD_LOG_LEVEL_ERROR) 464 (me, "no nsw config for %s\n", 465 params->p.name); 466 467 (void) _nscd_mutex_unlock( 468 (nscd_acc_data_t *)nswcfg2); 469 _nscd_release((nscd_acc_data_t *) 470 nswcfg); 471 472 return (NSCD_CREATE_NSW_STATE_FAILED); 473 } 474 475 rc = _nscd_create_sw_struct(i, params->cfgdbi, 476 params->p.name, (*nswcfg1)->nsw_cfg_str, 477 NULL, params); 478 _nscd_release((nscd_acc_data_t *)nswcfg1); 479 480 if (rc == NSCD_SUCCESS) { 481 _NSCD_LOG(NSCD_LOG_NSW_STATE, 482 NSCD_LOG_LEVEL_DEBUG) 483 (me, "nsw config created for %s (%s)\n", 484 params->p.name, 485 (*nswcfg1)->nsw_cfg_str); 486 } else { 487 (void) _nscd_mutex_unlock( 488 (nscd_acc_data_t *)nswcfg2); 489 _nscd_release((nscd_acc_data_t *) 490 nswcfg); 491 return (rc); 492 } 493 } 494 (void) _nscd_mutex_unlock((nscd_acc_data_t *)nswcfg2); 495 } 496 _nscd_release((nscd_acc_data_t *)nswcfg); 497 } 498 499 (void) rw_rdlock(&nscd_nsw_state_base_lock); 500 base = nscd_nsw_state_base[dbi]; 501 (void) rw_unlock(&nscd_nsw_state_base_lock); 502 if (base == NULL) 503 assert(base != NULL); 504 505 /* 506 * If list is not empty, return the first one on list. 507 * Otherwise, create and return a new db state if the 508 * limit is not reached. if reacehed, wait for the 'one 509 * is available' signal. 510 */ 511 assert(base == (nscd_nsw_state_base_t *)_nscd_mutex_lock( 512 (nscd_acc_data_t *)base)); 513 514 if (tid == NULL) { 515 ctrl_p = &base->nsw_state; 516 } else { 517 thread_only = 1; 518 ctrl_p = &base->nsw_state_thr; 519 520 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { 521 _nscd_logit(me, "per thread nsw state info: \n"); 522 _nscd_logit(me, "tid = %d\n", *tid); 523 _nscd_logit(me, "tid in base = %d\n", base->tid); 524 _nscd_logit(me, "number of free nsw_state = %d\n", 525 ctrl_p->free); 526 _nscd_logit(me, "number of nsw state allocated = %d\n", 527 ctrl_p->allocated); 528 _nscd_logit(me, "first nsw state on list = %p\n", 529 ctrl_p->first); 530 _nscd_logit(me, "number of waiter = %d\n", 531 ctrl_p->waiter); 532 533 } 534 } 535 536 if (ctrl_p->first == NULL && ctrl_p->allocated == ctrl_p->max) 537 wait_cond = 1; 538 else if (thread_only && base->used_by_thr && base->tid != *tid) 539 wait_cond = 1; 540 541 if (wait_cond) { 542 543 ctrl_p->waiter++; 544 545 while (wait_cond) { 546 if (!thread_only) 547 _NSCD_LOG(NSCD_LOG_NSW_STATE, 548 NSCD_LOG_LEVEL_DEBUG) 549 (me, "waiting for nsw state signal\n"); 550 else 551 _NSCD_LOG(NSCD_LOG_NSW_STATE, 552 NSCD_LOG_LEVEL_DEBUG) 553 (me, "waiting for per thread " 554 "nsw state signal\n"); 555 556 if (thread_only) { 557 _nscd_cond_wait((nscd_acc_data_t *)base, 558 &base->thr_cond); 559 560 if (base->used_by_thr == 0 && 561 ctrl_p->first != NULL) 562 wait_cond = 0; 563 } else { 564 _nscd_cond_wait((nscd_acc_data_t *)base, NULL); 565 566 if (ctrl_p->first != NULL) 567 wait_cond = 0; 568 } 569 570 if (!thread_only) 571 _NSCD_LOG(NSCD_LOG_NSW_STATE, 572 NSCD_LOG_LEVEL_DEBUG) 573 (me, "woke from cond wait ...wait_cond = %d\n", 574 wait_cond); 575 else 576 577 _NSCD_LOG(NSCD_LOG_NSW_STATE, 578 NSCD_LOG_LEVEL_DEBUG) 579 (me, "woke from cond wait (per thread) " 580 "...wait_cond = %d\n", wait_cond); 581 582 } 583 584 ctrl_p->waiter--; 585 } 586 587 if (ctrl_p->first == NULL) { 588 int geti; 589 590 /* 591 * for lookup calls from the compat backend 592 * uses the switch policy for passwd_compat 593 * or group_compat 594 */ 595 if (params->compati != -1) 596 geti = params->compati; 597 else 598 geti = params->dbi; 599 600 params->nswcfg = (nscd_nsw_config_t **)_nscd_get( 601 (nscd_acc_data_t *)nscd_nsw_config[geti]); 602 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 603 (me, "got a nsw config %p for index %d\n", 604 params->nswcfg, geti); 605 606 ctrl_p->first = _nscd_create_nsw_state(params); 607 if (ctrl_p->first != NULL) { 608 if (tid == NULL) { 609 _NSCD_LOG(NSCD_LOG_NSW_STATE, 610 NSCD_LOG_LEVEL_DEBUG) 611 (me, "got a new nsw_state %p\n", ctrl_p->first); 612 } else { 613 _NSCD_LOG(NSCD_LOG_NSW_STATE, 614 NSCD_LOG_LEVEL_DEBUG) 615 (me, "got a new per thread nsw_state %p\n", 616 ctrl_p->first); 617 } 618 ctrl_p->allocated++; 619 ctrl_p->free++; 620 } else { 621 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR) 622 (me, "error: unable to obtain a nsw state\n"); 623 _nscd_mutex_unlock((nscd_acc_data_t *)base); 624 return (NSCD_CREATE_NSW_STATE_FAILED); 625 } 626 } 627 628 ret = ctrl_p->first; 629 if (ret->recheck_be == nscd_true) 630 check_be_array(ret); 631 ctrl_p->first = ret->next; 632 ret->next = NULL; 633 ctrl_p->free--; 634 if (thread_only) { 635 base->tid = *tid; 636 base->used_by_thr = 1; 637 638 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { 639 _nscd_logit(me, "\t\t\tgot a per thread nsw " 640 "state %p: \n", ret); 641 _nscd_logit(me, "tid = %d\n", *tid); 642 _nscd_logit(me, "tid in base = %d\n", base->tid); 643 _nscd_logit(me, "number of free nsw_state = %d\n", 644 ctrl_p->free); 645 _nscd_logit(me, "number od nsw state allocated = %d\n", 646 ctrl_p->allocated); 647 _nscd_logit(me, "first nsw state on list = %p\n", 648 ctrl_p->first); 649 _nscd_logit(me, "number of waiter = %d\n", 650 ctrl_p->waiter); 651 } 652 } 653 else 654 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 655 (me, "got old nsw state %p\n", ret); 656 657 /* 658 * reference count the nsswitch state base bfore handing out 659 * the nsswitch state 660 */ 661 ret->base = (nscd_nsw_state_base_t *) 662 _nscd_get((nscd_acc_data_t *)base); 663 664 _nscd_mutex_unlock((nscd_acc_data_t *)base); 665 666 rootp->s = (struct nss_db_state *)ret; 667 668 return (NSCD_SUCCESS); 669 } 670 671 nscd_rc_t 672 _nscd_get_nsw_state( 673 nss_db_root_t *rootp, 674 nscd_nsw_params_t *params) 675 { 676 return (_get_nsw_state_int(rootp, params, NULL)); 677 } 678 679 nscd_rc_t 680 _nscd_get_nsw_state_thread( 681 nss_db_root_t *rootp, 682 nscd_nsw_params_t *params) 683 { 684 thread_t tid = thr_self(); 685 return (_get_nsw_state_int(rootp, params, &tid)); 686 } 687 688 689 static void 690 _put_nsw_state_int( 691 nscd_nsw_state_t *s, 692 thread_t *tid) 693 { 694 695 nscd_nsw_state_base_t *base; 696 nscd_state_ctrl_t *ctrl_p; 697 int thread_only = 0; 698 char *me = "_put_nsw_state_int"; 699 700 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 701 (me, "put back a nsw state\n"); 702 703 if (s == NULL) { 704 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 705 (me, "nsw state is NULL, nothing to put back\n"); 706 return; 707 } 708 709 /* 710 * no need to put back if the nsw state is not on any base 711 * but need to free the resources used 712 */ 713 if ((*s->nsw_cfg_p)->nobase == 1) { 714 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 715 (me, "no base nsw state, freeing resources ...\n"); 716 717 _nscd_free_nsw_state(s); 718 return; 719 } 720 721 if (tid != NULL) 722 thread_only = 1; 723 724 base = s->base; 725 726 if (_nscd_mutex_lock((nscd_acc_data_t *)base) == NULL) { 727 /* base has been freed or no longer valid, free the nsw state */ 728 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 729 (me, "nsw state base gone or no longer valid, freeing %p\n", s); 730 _nscd_free_nsw_state(s); 731 return; 732 } 733 734 if (thread_only) 735 ctrl_p = &base->nsw_state_thr; 736 else 737 ctrl_p = &base->nsw_state; 738 739 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { 740 _nscd_logit(me, "before returning the nsw state: \n"); 741 _nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid); 742 _nscd_logit(me, "tid in base = %d\n", base->tid); 743 _nscd_logit(me, "number of free nsw_state = %d\n", 744 ctrl_p->free); 745 _nscd_logit(me, "number od nsw state allocated = %d\n", 746 ctrl_p->allocated); 747 _nscd_logit(me, "first nsw state on list = %p\n", 748 ctrl_p->first); 749 _nscd_logit(me, "number of waiter = %d\n", ctrl_p->waiter); 750 } 751 752 if (ctrl_p->first != NULL) { 753 s->next = ctrl_p->first; 754 ctrl_p->first = s; 755 } else { 756 ctrl_p->first = s; 757 s->next = NULL; 758 } 759 ctrl_p->free++; 760 761 /* 762 * Remove reference to the nsswitch state base. 763 */ 764 _nscd_release((nscd_acc_data_t *)base); 765 s->base = NULL; 766 767 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 768 (me, "signaling waiter thread_only = %d..\n", thread_only); 769 770 if (thread_only && ctrl_p->free == ctrl_p->allocated) { 771 assert(ctrl_p->first != NULL); 772 base->used_by_thr = 0; 773 if (ctrl_p->waiter > 0) { 774 (void) cond_signal(&base->thr_cond); 775 } 776 } 777 778 if (!thread_only && ctrl_p->waiter > 0) { 779 780 _nscd_cond_signal((nscd_acc_data_t *)base); 781 } 782 783 _NSCD_LOG_IF(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) { 784 _nscd_logit(me, "after the nsw state is returned: \n"); 785 _nscd_logit(me, "tid = %d\n", (tid == NULL) ? -1 : *tid); 786 _nscd_logit(me, "tid in base = %d\n", base->tid); 787 _nscd_logit(me, "number of free nsw_state = %d\n", 788 ctrl_p->free); 789 _nscd_logit(me, "number od nsw state allocated = %d\n", 790 ctrl_p->allocated); 791 _nscd_logit(me, "first nsw state on list = %p\n", 792 ctrl_p->first); 793 _nscd_logit(me, "tnumber of waiter = %d\n", ctrl_p->waiter); 794 } 795 796 _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_DEBUG) 797 (me, "done putting back nsw state %p, thread_only = %d\n", 798 s, thread_only); 799 800 _nscd_mutex_unlock((nscd_acc_data_t *)base); 801 802 } 803 804 void 805 _nscd_put_nsw_state( 806 nscd_nsw_state_t *s) 807 { 808 _put_nsw_state_int(s, NULL); 809 } 810 811 void 812 _nscd_put_nsw_state_thread( 813 nscd_nsw_state_t *s) 814 { 815 thread_t tid = thr_self(); 816 _put_nsw_state_int(s, &tid); 817 } 818 819 nscd_rc_t 820 _nscd_init_nsw_state_base( 821 int dbi, 822 int compat_basei, 823 int lock) 824 { 825 int cfgdbi; 826 nscd_nsw_state_base_t *base = NULL; 827 char *me = "_nscd_init_nsw_state_base"; 828 829 if (lock) 830 (void) rw_rdlock(&nscd_nsw_state_base_lock); 831 832 base = (nscd_nsw_state_base_t *)_nscd_alloc( 833 NSCD_DATA_NSW_STATE_BASE, 834 sizeof (nscd_nsw_state_base_t), 835 _nscd_free_nsw_state_base, 836 NSCD_ALLOC_MUTEX | NSCD_ALLOC_COND); 837 838 if (base == NULL) { 839 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, 840 NSCD_LOG_LEVEL_ERROR) 841 (me, "not able to allocate a nsw state base\n"); 842 if (lock) 843 (void) rw_unlock(&nscd_nsw_state_base_lock); 844 return (NSCD_NO_MEMORY); 845 } 846 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 847 (me, "nsw state base %p allocated\n", base); 848 849 /* 850 * initialize and activate the new nss_nsw_state base 851 */ 852 base->dbi = dbi; 853 if (compat_basei != -1) 854 cfgdbi = compat_basei; 855 else 856 cfgdbi = dbi; 857 858 base->nsw_state.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_db; 859 base->nsw_state_thr.max = NSCD_SW_CFG(cfgdbi).max_nsw_state_per_thread; 860 861 nscd_nsw_state_base[dbi] = (nscd_nsw_state_base_t *)_nscd_set( 862 (nscd_acc_data_t *)nscd_nsw_state_base[dbi], 863 (nscd_acc_data_t *)base); 864 865 if (lock) 866 (void) rw_unlock(&nscd_nsw_state_base_lock); 867 868 return (NSCD_SUCCESS); 869 } 870 871 nscd_rc_t 872 _nscd_init_all_nsw_state_base() 873 { 874 int i; 875 nscd_rc_t rc; 876 char *me = "_nscd_init_all_nsw_state_base"; 877 878 (void) rw_rdlock(&nscd_nsw_state_base_lock); 879 880 for (i = 0; i < NSCD_NUM_DB; i++) { 881 882 rc = _nscd_init_nsw_state_base(i, -1, 0); 883 884 if (rc != NSCD_SUCCESS) { 885 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, 886 NSCD_LOG_LEVEL_ERROR) 887 (me, "not able to initialize a nsw db state " 888 "base (%d)\n", i); 889 890 (void) rw_unlock(&nscd_nsw_state_base_lock); 891 return (rc); 892 } 893 } 894 _NSCD_LOG(NSCD_LOG_NSW_STATE | NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_DEBUG) 895 (me, "all nsw state base initialized\n"); 896 897 (void) rw_unlock(&nscd_nsw_state_base_lock); 898 899 return (NSCD_SUCCESS); 900 } 901 902 nscd_rc_t 903 _nscd_alloc_nsw_state_base() 904 { 905 906 (void) rw_rdlock(&nscd_nsw_state_base_lock); 907 908 nscd_nsw_state_base = calloc(NSCD_NUM_DB, 909 sizeof (nscd_nsw_state_base_t *)); 910 if (nscd_nsw_state_base == NULL) { 911 (void) rw_unlock(&nscd_nsw_state_base_lock); 912 return (NSCD_NO_MEMORY); 913 } 914 915 (void) rw_rdlock(&nscd_nsw_state_base_lock); 916 917 return (NSCD_SUCCESS); 918 } 919