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