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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Windows to Solaris Identity Mapping kernel API 29 * This module provides the kernel cache. 30 */ 31 32 #pragma ident "%Z%%M% %I% %E% SMI" 33 34 35 #include <sys/types.h> 36 #include <sys/avl.h> 37 #include <sys/systm.h> 38 #include <sys/sysmacros.h> 39 #include <sys/ksynch.h> 40 #include <sys/kidmap.h> 41 #include "idmap_prot.h" 42 #include "kidmap_priv.h" 43 44 45 /* 46 * External functions 47 */ 48 extern uintptr_t space_fetch(char *key); 49 extern int space_store(char *key, uintptr_t ptr); 50 51 52 /* 53 * Internal definitions and functions 54 */ 55 56 #define CACHE_TRIGGER_SIZE 4096 57 #define CACHE_PURGE_INTERVAL (60 * 3) 58 #define CACHE_TTL (60 * 10) 59 60 typedef struct sid_prefix_node { 61 avl_node_t avl_link; 62 const char *sid_prefix; 63 } sid_prefix_node_t; 64 65 66 typedef struct entry { 67 avl_node_t avl_link; 68 const char *sid_prefix; 69 uint32_t rid; 70 uid_t pid; 71 int is_user; 72 time_t ttl; 73 } entry_t; 74 75 typedef int (*avl_comp_fn)(const void*, const void*); 76 77 78 struct sid_prefix_store { 79 struct avl_tree tree; 80 krwlock_t lock; 81 }; 82 83 struct sid_prefix_store *kidmap_sid_prefix_store = NULL; 84 85 86 87 static void 88 kidmap_cache_purge_avl(idmap_avl_cache_t *cache); 89 90 /* 91 * kidmap_strdup() copied from uts/common/fs/sockfs/nl7c.c 92 */ 93 static char * 94 kidmap_strdup(const char *s) 95 { 96 int len = strlen(s) + 1; 97 char *ret = kmem_alloc(len, KM_SLEEP); 98 99 bcopy(s, ret, len); 100 return (ret); 101 } 102 103 104 static int 105 kidmap_compare_sid(const entry_t *entry1, const entry_t *entry2) 106 { 107 int64_t comp = ((int64_t)entry2->rid) - ((int64_t)entry1->rid); 108 109 if (comp == 0) 110 comp = strcmp(entry2->sid_prefix, entry1->sid_prefix); 111 112 if (comp < 0) 113 comp = -1; 114 else if (comp > 0) 115 comp = 1; 116 117 return ((int)comp); 118 } 119 120 121 static int 122 kidmap_compare_pid(const entry_t *entry1, const entry_t *entry2) 123 { 124 if (entry2->pid > entry1->pid) 125 return (1); 126 if (entry2->pid < entry1->pid) 127 return (-1); 128 return (0); 129 } 130 131 132 static int 133 kidmap_compare_sid_prefix(const sid_prefix_node_t *entry1, 134 const sid_prefix_node_t *entry2) 135 { 136 int comp; 137 138 comp = strcmp(entry2->sid_prefix, entry1->sid_prefix); 139 140 if (comp < 0) 141 comp = -1; 142 else if (comp > 0) 143 comp = 1; 144 145 return (comp); 146 } 147 148 149 void 150 kidmap_cache_create(idmap_cache_t *cache) 151 { 152 avl_create(&cache->uidbysid.tree, (avl_comp_fn)kidmap_compare_sid, 153 sizeof (entry_t), offsetof(entry_t, avl_link)); 154 mutex_init(&cache->uidbysid.mutex, NULL, MUTEX_DEFAULT, NULL); 155 cache->uidbysid.purge_time = 0; 156 157 avl_create(&cache->gidbysid.tree, (avl_comp_fn)kidmap_compare_sid, 158 sizeof (entry_t), offsetof(entry_t, avl_link)); 159 mutex_init(&cache->gidbysid.mutex, NULL, MUTEX_DEFAULT, NULL); 160 cache->gidbysid.purge_time = 0; 161 162 avl_create(&cache->pidbysid.tree, (avl_comp_fn)kidmap_compare_sid, 163 sizeof (entry_t), offsetof(entry_t, avl_link)); 164 mutex_init(&cache->pidbysid.mutex, NULL, MUTEX_DEFAULT, NULL); 165 cache->pidbysid.purge_time = 0; 166 167 avl_create(&cache->sidbyuid.tree, (avl_comp_fn)kidmap_compare_pid, 168 sizeof (entry_t), offsetof(entry_t, avl_link)); 169 mutex_init(&cache->sidbyuid.mutex, NULL, MUTEX_DEFAULT, NULL); 170 cache->sidbyuid.purge_time = 0; 171 172 avl_create(&cache->sidbygid.tree, (avl_comp_fn)kidmap_compare_pid, 173 sizeof (entry_t), offsetof(entry_t, avl_link)); 174 mutex_init(&cache->sidbygid.mutex, NULL, MUTEX_DEFAULT, NULL); 175 cache->sidbygid.purge_time = 0; 176 } 177 178 179 void 180 kidmap_cache_delete(idmap_cache_t *cache) 181 { 182 entry_t *entry; 183 void *cookie; 184 185 cookie = NULL; 186 while ((entry = avl_destroy_nodes(&cache->uidbysid.tree, &cookie)) 187 != NULL) { 188 kmem_free(entry, sizeof (entry_t)); 189 } 190 avl_destroy(&cache->uidbysid.tree); 191 mutex_destroy(&cache->uidbysid.mutex); 192 193 cookie = NULL; 194 while ((entry = avl_destroy_nodes(&cache->gidbysid.tree, &cookie)) 195 != NULL) { 196 kmem_free(entry, sizeof (entry_t)); 197 } 198 avl_destroy(&cache->gidbysid.tree); 199 mutex_destroy(&cache->gidbysid.mutex); 200 201 cookie = NULL; 202 while ((entry = avl_destroy_nodes(&cache->pidbysid.tree, &cookie)) 203 != NULL) { 204 kmem_free(entry, sizeof (entry_t)); 205 } 206 avl_destroy(&cache->pidbysid.tree); 207 mutex_destroy(&cache->pidbysid.mutex); 208 209 cookie = NULL; 210 while ((entry = avl_destroy_nodes(&cache->sidbyuid.tree, &cookie)) 211 != NULL) { 212 kmem_free(entry, sizeof (entry_t)); 213 } 214 avl_destroy(&cache->sidbyuid.tree); 215 mutex_destroy(&cache->sidbyuid.mutex); 216 217 cookie = NULL; 218 while ((entry = avl_destroy_nodes(&cache->sidbygid.tree, &cookie)) 219 != NULL) { 220 kmem_free(entry, sizeof (entry_t)); 221 } 222 avl_destroy(&cache->sidbygid.tree); 223 mutex_destroy(&cache->sidbygid.mutex); 224 } 225 226 227 void 228 kidmap_cache_get_data(idmap_cache_t *cache, size_t *uidbysid, size_t *gidbysid, 229 size_t *pidbysid, size_t *sidbyuid, size_t *sidbygid) 230 { 231 mutex_enter(&cache->uidbysid.mutex); 232 *uidbysid = avl_numnodes(&cache->uidbysid.tree); 233 mutex_exit(&cache->uidbysid.mutex); 234 235 mutex_enter(&cache->gidbysid.mutex); 236 *gidbysid = avl_numnodes(&cache->gidbysid.tree); 237 mutex_exit(&cache->gidbysid.mutex); 238 239 mutex_enter(&cache->pidbysid.mutex); 240 *pidbysid = avl_numnodes(&cache->pidbysid.tree); 241 mutex_exit(&cache->pidbysid.mutex); 242 243 mutex_enter(&cache->sidbyuid.mutex); 244 *sidbyuid = avl_numnodes(&cache->sidbyuid.tree); 245 mutex_exit(&cache->sidbyuid.mutex); 246 247 mutex_enter(&cache->sidbygid.mutex); 248 *sidbygid = avl_numnodes(&cache->sidbygid.tree); 249 mutex_exit(&cache->sidbygid.mutex); 250 } 251 252 253 void 254 kidmap_cache_purge(idmap_cache_t *cache) 255 { 256 entry_t *entry; 257 void *cookie; 258 259 mutex_enter(&cache->uidbysid.mutex); 260 cookie = NULL; 261 while ((entry = avl_destroy_nodes(&cache->uidbysid.tree, &cookie)) 262 != NULL) { 263 kmem_free(entry, sizeof (entry_t)); 264 } 265 avl_destroy(&cache->uidbysid.tree); 266 avl_create(&cache->uidbysid.tree, (avl_comp_fn)kidmap_compare_sid, 267 sizeof (entry_t), offsetof(entry_t, avl_link)); 268 mutex_exit(&cache->uidbysid.mutex); 269 270 mutex_enter(&cache->gidbysid.mutex); 271 cookie = NULL; 272 while ((entry = avl_destroy_nodes(&cache->gidbysid.tree, &cookie)) 273 != NULL) { 274 kmem_free(entry, sizeof (entry_t)); 275 } 276 avl_destroy(&cache->gidbysid.tree); 277 avl_create(&cache->gidbysid.tree, (avl_comp_fn)kidmap_compare_sid, 278 sizeof (entry_t), offsetof(entry_t, avl_link)); 279 mutex_exit(&cache->gidbysid.mutex); 280 281 mutex_enter(&cache->pidbysid.mutex); 282 cookie = NULL; 283 while ((entry = avl_destroy_nodes(&cache->pidbysid.tree, &cookie)) 284 != NULL) { 285 kmem_free(entry, sizeof (entry_t)); 286 } 287 avl_destroy(&cache->pidbysid.tree); 288 avl_create(&cache->pidbysid.tree, (avl_comp_fn)kidmap_compare_sid, 289 sizeof (entry_t), offsetof(entry_t, avl_link)); 290 mutex_exit(&cache->pidbysid.mutex); 291 292 mutex_enter(&cache->sidbyuid.mutex); 293 cookie = NULL; 294 while ((entry = avl_destroy_nodes(&cache->sidbyuid.tree, &cookie)) 295 != NULL) { 296 kmem_free(entry, sizeof (entry_t)); 297 } 298 avl_destroy(&cache->sidbyuid.tree); 299 avl_create(&cache->sidbyuid.tree, (avl_comp_fn)kidmap_compare_pid, 300 sizeof (entry_t), offsetof(entry_t, avl_link)); 301 mutex_exit(&cache->sidbyuid.mutex); 302 303 mutex_enter(&cache->sidbygid.mutex); 304 cookie = NULL; 305 while ((entry = avl_destroy_nodes(&cache->sidbygid.tree, &cookie)) 306 != NULL) { 307 kmem_free(entry, sizeof (entry_t)); 308 } 309 avl_destroy(&cache->sidbygid.tree); 310 avl_create(&cache->sidbygid.tree, (avl_comp_fn)kidmap_compare_pid, 311 sizeof (entry_t), offsetof(entry_t, avl_link)); 312 mutex_exit(&cache->sidbygid.mutex); 313 } 314 315 316 int 317 kidmap_cache_lookup_uidbysid(idmap_cache_t *cache, const char *sid_prefix, 318 uint32_t rid, uid_t *uid) 319 { 320 entry_t entry; 321 entry_t *result; 322 avl_index_t where; 323 int status; 324 time_t now = gethrestime_sec(); 325 326 entry.sid_prefix = sid_prefix; 327 entry.rid = rid; 328 329 mutex_enter(&cache->uidbysid.mutex); 330 331 result = avl_find(&cache->uidbysid.tree, &entry, &where); 332 333 if (result && result->ttl > now) { 334 *uid = result->pid; 335 status = IDMAP_SUCCESS; 336 } else 337 status = IDMAP_ERR_NOMAPPING; 338 339 mutex_exit(&cache->uidbysid.mutex); 340 341 return (status); 342 } 343 344 345 346 int 347 kidmap_cache_lookup_gidbysid(idmap_cache_t *cache, const char *sid_prefix, 348 uint32_t rid, gid_t *gid) 349 { 350 entry_t entry; 351 entry_t *result; 352 avl_index_t where; 353 int status; 354 time_t now = gethrestime_sec(); 355 356 entry.sid_prefix = sid_prefix; 357 entry.rid = rid; 358 359 mutex_enter(&cache->gidbysid.mutex); 360 361 result = avl_find(&cache->gidbysid.tree, &entry, &where); 362 363 if (result && result->ttl > now) { 364 *gid = result->pid; 365 status = IDMAP_SUCCESS; 366 } else 367 status = IDMAP_ERR_NOMAPPING; 368 369 mutex_exit(&cache->gidbysid.mutex); 370 371 return (status); 372 } 373 374 375 376 377 int 378 kidmap_cache_lookup_pidbysid(idmap_cache_t *cache, const char *sid_prefix, 379 uint32_t rid, uid_t *pid, int *is_user) 380 { 381 entry_t entry; 382 entry_t *result; 383 avl_index_t where; 384 int status; 385 time_t now = gethrestime_sec(); 386 387 entry.sid_prefix = sid_prefix; 388 entry.rid = rid; 389 390 mutex_enter(&cache->pidbysid.mutex); 391 392 result = avl_find(&cache->pidbysid.tree, &entry, &where); 393 394 if (result && result->ttl > now) { 395 *pid = result->pid; 396 *is_user = result->is_user; 397 status = IDMAP_SUCCESS; 398 } else 399 status = IDMAP_ERR_NOMAPPING; 400 401 mutex_exit(&cache->pidbysid.mutex); 402 403 return (status); 404 } 405 406 407 408 int 409 kidmap_cache_lookup_sidbyuid(idmap_cache_t *cache, const char **sid_prefix, 410 uint32_t *rid, uid_t uid) 411 { 412 entry_t entry; 413 entry_t *result; 414 avl_index_t where; 415 int status; 416 time_t now = gethrestime_sec(); 417 418 entry.pid = uid; 419 420 mutex_enter(&cache->sidbyuid.mutex); 421 422 result = avl_find(&cache->sidbyuid.tree, &entry, &where); 423 424 if (result && result->ttl > now) { 425 *sid_prefix = result->sid_prefix; 426 *rid = result->rid; 427 status = IDMAP_SUCCESS; 428 } else 429 status = IDMAP_ERR_NOMAPPING; 430 431 mutex_exit(&cache->sidbyuid.mutex); 432 433 return (status); 434 } 435 436 int 437 kidmap_cache_lookup_sidbygid(idmap_cache_t *cache, const char **sid_prefix, 438 uint32_t *rid, gid_t gid) 439 { 440 entry_t entry; 441 entry_t *result; 442 avl_index_t where; 443 int status; 444 time_t now = gethrestime_sec(); 445 446 entry.pid = gid; 447 448 mutex_enter(&cache->sidbygid.mutex); 449 450 result = avl_find(&cache->sidbygid.tree, &entry, &where); 451 452 if (result && result->ttl > now) { 453 *sid_prefix = result->sid_prefix; 454 *rid = result->rid; 455 status = IDMAP_SUCCESS; 456 } else 457 status = IDMAP_ERR_NOMAPPING; 458 459 mutex_exit(&cache->sidbygid.mutex); 460 461 return (status); 462 } 463 464 465 466 467 void 468 kidmap_cache_add_uidbysid(idmap_cache_t *cache, const char *sid_prefix, 469 uint32_t rid, uid_t uid) 470 471 { 472 entry_t find; 473 entry_t *result; 474 entry_t *new; 475 avl_index_t where; 476 int purge_required = FALSE; 477 time_t ttl = CACHE_TTL + gethrestime_sec(); 478 479 find.sid_prefix = sid_prefix; 480 find.rid = rid; 481 482 mutex_enter(&cache->uidbysid.mutex); 483 result = avl_find(&cache->uidbysid.tree, &find, &where); 484 485 if (result) { 486 result->pid = uid; 487 result->ttl = ttl; 488 } else { 489 new = kmem_alloc(sizeof (entry_t), KM_SLEEP); 490 new->pid = uid; 491 new->sid_prefix = sid_prefix; 492 new->rid = rid; 493 new->ttl = ttl; 494 495 avl_insert(&cache->uidbysid.tree, new, where); 496 497 if ((avl_numnodes(&cache->uidbysid.tree) > 498 CACHE_TRIGGER_SIZE) && 499 (cache->uidbysid.purge_time + CACHE_PURGE_INTERVAL < 500 gethrestime_sec())) 501 purge_required = TRUE; 502 } 503 504 mutex_exit(&cache->uidbysid.mutex); 505 506 if (purge_required) 507 kidmap_cache_purge_avl(&cache->uidbysid); 508 } 509 510 511 void 512 kidmap_cache_add_gidbysid(idmap_cache_t *cache, const char *sid_prefix, 513 uint32_t rid, gid_t gid) 514 515 { 516 entry_t find; 517 entry_t *result; 518 entry_t *new; 519 avl_index_t where; 520 int purge_required = FALSE; 521 time_t ttl = CACHE_TTL + gethrestime_sec(); 522 523 find.sid_prefix = sid_prefix; 524 find.rid = rid; 525 526 mutex_enter(&cache->gidbysid.mutex); 527 result = avl_find(&cache->gidbysid.tree, &find, &where); 528 529 if (result) { 530 result->pid = gid; 531 result->ttl = ttl; 532 } else { 533 new = kmem_alloc(sizeof (entry_t), KM_SLEEP); 534 new->pid = gid; 535 new->sid_prefix = sid_prefix; 536 new->rid = rid; 537 new->ttl = ttl; 538 539 avl_insert(&cache->gidbysid.tree, new, where); 540 541 if ((avl_numnodes(&cache->gidbysid.tree) > 542 CACHE_TRIGGER_SIZE) && 543 (cache->gidbysid.purge_time + CACHE_PURGE_INTERVAL < 544 gethrestime_sec())) 545 purge_required = TRUE; 546 } 547 548 mutex_exit(&cache->gidbysid.mutex); 549 550 if (purge_required) 551 kidmap_cache_purge_avl(&cache->gidbysid); 552 } 553 554 void 555 kidmap_cache_add_pidbysid(idmap_cache_t *cache, const char *sid_prefix, 556 uint32_t rid, uid_t pid, int is_user) 557 558 { 559 entry_t find; 560 entry_t *result; 561 entry_t *new; 562 avl_index_t where; 563 int purge_required = FALSE; 564 time_t ttl = CACHE_TTL + gethrestime_sec(); 565 566 find.sid_prefix = sid_prefix; 567 find.rid = rid; 568 569 mutex_enter(&cache->pidbysid.mutex); 570 result = avl_find(&cache->pidbysid.tree, &find, &where); 571 572 if (result) { 573 result->pid = pid; 574 result->is_user = is_user; 575 result->ttl = ttl; 576 } else { 577 new = kmem_alloc(sizeof (entry_t), KM_SLEEP); 578 new->pid = pid; 579 new->is_user = is_user; 580 new->sid_prefix = sid_prefix; 581 new->rid = rid; 582 new->ttl = ttl; 583 584 avl_insert(&cache->pidbysid.tree, new, where); 585 586 if ((avl_numnodes(&cache->pidbysid.tree) > 587 CACHE_TRIGGER_SIZE) && 588 (cache->pidbysid.purge_time + CACHE_PURGE_INTERVAL < 589 gethrestime_sec())) 590 purge_required = TRUE; 591 } 592 593 mutex_exit(&cache->pidbysid.mutex); 594 595 if (purge_required) 596 kidmap_cache_purge_avl(&cache->pidbysid); 597 } 598 599 600 601 void 602 kidmap_cache_add_sidbyuid(idmap_cache_t *cache, const char *sid_prefix, 603 uint32_t rid, uid_t uid) 604 { 605 entry_t find; 606 entry_t *result; 607 entry_t *new; 608 avl_index_t where; 609 int purge_required = FALSE; 610 time_t ttl = CACHE_TTL + gethrestime_sec(); 611 612 find.pid = uid; 613 614 mutex_enter(&cache->sidbyuid.mutex); 615 result = avl_find(&cache->sidbyuid.tree, &find, &where); 616 617 if (result) { 618 result->sid_prefix = sid_prefix; 619 result->rid = rid; 620 result->ttl = ttl; 621 } else { 622 new = kmem_alloc(sizeof (entry_t), KM_SLEEP); 623 new->pid = uid; 624 new->sid_prefix = sid_prefix; 625 new->rid = rid; 626 new->ttl = ttl; 627 628 avl_insert(&cache->sidbyuid.tree, new, where); 629 if ((avl_numnodes(&cache->sidbyuid.tree) > 630 CACHE_TRIGGER_SIZE) && 631 (cache->sidbyuid.purge_time + CACHE_PURGE_INTERVAL < 632 gethrestime_sec())) 633 purge_required = TRUE; 634 } 635 636 mutex_exit(&cache->sidbyuid.mutex); 637 638 if (purge_required) 639 kidmap_cache_purge_avl(&cache->sidbyuid); 640 } 641 642 643 void 644 kidmap_cache_add_sidbygid(idmap_cache_t *cache, const char *sid_prefix, 645 uint32_t rid, gid_t gid) 646 { 647 entry_t find; 648 entry_t *result; 649 entry_t *new; 650 avl_index_t where; 651 int purge_required = FALSE; 652 time_t ttl = CACHE_TTL + gethrestime_sec(); 653 654 find.pid = gid; 655 656 mutex_enter(&cache->sidbygid.mutex); 657 result = avl_find(&cache->sidbygid.tree, &find, &where); 658 659 if (result) { 660 result->sid_prefix = sid_prefix; 661 result->rid = rid; 662 result->ttl = ttl; 663 } else { 664 new = kmem_alloc(sizeof (entry_t), KM_SLEEP); 665 new->pid = gid; 666 new->sid_prefix = sid_prefix; 667 new->rid = rid; 668 new->ttl = ttl; 669 670 avl_insert(&cache->sidbygid.tree, new, where); 671 if ((avl_numnodes(&cache->sidbygid.tree) > 672 CACHE_TRIGGER_SIZE) && 673 (cache->sidbygid.purge_time + CACHE_PURGE_INTERVAL < 674 gethrestime_sec())) 675 purge_required = TRUE; 676 } 677 678 mutex_exit(&cache->sidbygid.mutex); 679 680 if (purge_required) 681 kidmap_cache_purge_avl(&cache->sidbygid); 682 } 683 684 685 static void 686 kidmap_cache_purge_avl(idmap_avl_cache_t *cache) 687 { 688 time_t now = gethrestime_sec(); 689 entry_t *curr; 690 entry_t *prev = NULL; 691 692 mutex_enter(&cache->mutex); 693 694 curr = avl_first(&cache->tree); 695 while (curr != NULL) { 696 if (curr->ttl < now) { 697 /* Old entry to remove */ 698 avl_remove(&cache->tree, curr); 699 kmem_free(curr, sizeof (entry_t)); 700 curr = prev; 701 if (curr == NULL) { 702 /* We removed the first entery */ 703 curr = avl_first(&cache->tree); 704 continue; 705 } 706 } 707 prev = curr; 708 curr = AVL_NEXT(&cache->tree, curr); 709 } 710 cache->purge_time = now; 711 712 mutex_exit(&cache->mutex); 713 } 714 715 716 void 717 kidmap_sid_prefix_store_init(void) 718 { 719 kidmap_sid_prefix_store = (struct sid_prefix_store *) 720 space_fetch("SUNW,idmap_sid_prefix"); 721 if (kidmap_sid_prefix_store == NULL) { 722 kidmap_sid_prefix_store = kmem_alloc( 723 sizeof (struct sid_prefix_store), KM_SLEEP); 724 rw_init(&kidmap_sid_prefix_store->lock, NULL, RW_DRIVER, NULL); 725 avl_create(&kidmap_sid_prefix_store->tree, 726 (avl_comp_fn)kidmap_compare_sid_prefix, 727 sizeof (sid_prefix_node_t), 728 offsetof(sid_prefix_node_t, avl_link)); 729 (void) space_store("SUNW,idmap_sid_prefix", 730 (uintptr_t)kidmap_sid_prefix_store); 731 } else { 732 /* 733 * The AVL comparison function must be re-initialised on 734 * re-load because may not be loaded into the same 735 * address space. 736 */ 737 kidmap_sid_prefix_store->tree.avl_compar = 738 (avl_comp_fn)kidmap_compare_sid_prefix; 739 } 740 } 741 742 743 const char * 744 kidmap_find_sid_prefix(const char *sid_prefix) { 745 sid_prefix_node_t find; 746 sid_prefix_node_t *result; 747 sid_prefix_node_t *new; 748 avl_index_t where; 749 750 if (sid_prefix == NULL || *sid_prefix == '\0') 751 return (NULL); 752 753 find.sid_prefix = sid_prefix; 754 755 756 rw_enter(&kidmap_sid_prefix_store->lock, RW_READER); 757 758 result = avl_find(&kidmap_sid_prefix_store->tree, &find, &where); 759 760 if (result) { 761 rw_exit(&kidmap_sid_prefix_store->lock); 762 return (result->sid_prefix); 763 } 764 765 if (rw_tryupgrade(&kidmap_sid_prefix_store->lock) == 0) { 766 /* 767 * Could not upgrade lock so release lock 768 * and acquire the write lock 769 */ 770 rw_exit(&kidmap_sid_prefix_store->lock); 771 rw_enter(&kidmap_sid_prefix_store->lock, RW_WRITER); 772 773 result = avl_find(&kidmap_sid_prefix_store->tree, 774 &find, &where); 775 if (result) { 776 rw_exit(&kidmap_sid_prefix_store->lock); 777 return (result->sid_prefix); 778 } 779 } 780 781 new = kmem_alloc(sizeof (sid_prefix_node_t), KM_SLEEP); 782 new->sid_prefix = kidmap_strdup(sid_prefix); 783 avl_insert(&kidmap_sid_prefix_store->tree, new, where); 784 rw_exit(&kidmap_sid_prefix_store->lock); 785 786 return (new->sid_prefix); 787 } 788