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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 24 * Copyright 2018 Nexenta Systems, Inc. All rights reserved. 25 * Copyright 2022 RackTop Systems, Inc. 26 */ 27 28 #include <sys/param.h> 29 #include <sys/types.h> 30 #include <sys/tzfile.h> 31 #include <sys/atomic.h> 32 #include <sys/time.h> 33 #include <sys/spl.h> 34 #include <sys/random.h> 35 #include <smbsrv/smb_kproto.h> 36 #include <smbsrv/smb_fsops.h> 37 #include <smbsrv/smbinfo.h> 38 #include <smbsrv/smb_xdr.h> 39 #include <smbsrv/smb_vops.h> 40 #include <smbsrv/smb_idmap.h> 41 42 #include <sys/sid.h> 43 #include <sys/priv_names.h> 44 #include <sys/bitmap.h> 45 46 static kmem_cache_t *smb_dtor_cache = NULL; 47 48 static boolean_t smb_avl_hold(smb_avl_t *); 49 static void smb_avl_rele(smb_avl_t *); 50 51 time_t tzh_leapcnt = 0; 52 53 struct tm 54 *smb_gmtime_r(time_t *clock, struct tm *result); 55 56 time_t 57 smb_timegm(struct tm *tm); 58 59 struct tm { 60 int tm_sec; 61 int tm_min; 62 int tm_hour; 63 int tm_mday; 64 int tm_mon; 65 int tm_year; 66 int tm_wday; 67 int tm_yday; 68 int tm_isdst; 69 }; 70 71 static const int days_in_month[] = { 72 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 73 }; 74 75 /* 76 * Given a UTF-8 string (our internal form everywhere) 77 * return either the Unicode (UTF-16) length in bytes, 78 * or the OEM length in bytes. Which we return is 79 * determined by whether the client supports Unicode. 80 * This length does NOT include the null. 81 */ 82 int 83 smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str) 84 { 85 if (sr->session->dialect >= SMB_VERS_2_BASE || 86 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0) 87 return (smb_wcequiv_strlen(str)); 88 return (smb_sbequiv_strlen(str)); 89 } 90 91 /* 92 * Given a UTF-8 string (our internal form everywhere) 93 * return either the Unicode (UTF-16) length in bytes, 94 * or the OEM length in bytes. Which we return is 95 * determined by whether the client supports Unicode. 96 * This length DOES include the null. 97 */ 98 int 99 smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str) 100 { 101 if (sr->session->dialect >= SMB_VERS_2_BASE || 102 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0) 103 return (smb_wcequiv_strlen(str) + 2); 104 return (smb_sbequiv_strlen(str) + 1); 105 } 106 107 int 108 smb_ascii_or_unicode_null_len(struct smb_request *sr) 109 { 110 if (sr->session->dialect >= SMB_VERS_2_BASE || 111 (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0) 112 return (2); 113 return (1); 114 } 115 116 /* 117 * 118 * Convert old-style (DOS, LanMan) wildcard strings to NT style. 119 * This should ONLY happen to patterns that come from old clients, 120 * meaning dialect LANMAN2_1 etc. (dialect < NT_LM_0_12). 121 * 122 * ? is converted to > 123 * * is converted to < if it is followed by . 124 * . is converted to " if it is followed by ? or * or end of pattern 125 * 126 * Note: modifies pattern in place. 127 */ 128 void 129 smb_convert_wildcards(char *pattern) 130 { 131 char *p; 132 133 for (p = pattern; *p != '\0'; p++) { 134 switch (*p) { 135 case '?': 136 *p = '>'; 137 break; 138 case '*': 139 if (p[1] == '.') 140 *p = '<'; 141 break; 142 case '.': 143 if (p[1] == '?' || p[1] == '*' || p[1] == '\0') 144 *p = '\"'; 145 break; 146 } 147 } 148 } 149 150 /* 151 * smb_sattr_check 152 * 153 * Check file attributes against a search attribute (sattr) mask. 154 * 155 * Normal files, which includes READONLY and ARCHIVE, always pass 156 * this check. If the DIRECTORY, HIDDEN or SYSTEM special attributes 157 * are set then they must appear in the search mask. The special 158 * attributes are inclusive, i.e. all special attributes that appear 159 * in sattr must also appear in the file attributes for the check to 160 * pass. 161 * 162 * The following examples show how this works: 163 * 164 * fileA: READONLY 165 * fileB: 0 (no attributes = normal file) 166 * fileC: READONLY, ARCHIVE 167 * fileD: HIDDEN 168 * fileE: READONLY, HIDDEN, SYSTEM 169 * dirA: DIRECTORY 170 * 171 * search attribute: 0 172 * Returns: fileA, fileB and fileC. 173 * search attribute: HIDDEN 174 * Returns: fileA, fileB, fileC and fileD. 175 * search attribute: SYSTEM 176 * Returns: fileA, fileB and fileC. 177 * search attribute: DIRECTORY 178 * Returns: fileA, fileB, fileC and dirA. 179 * search attribute: HIDDEN and SYSTEM 180 * Returns: fileA, fileB, fileC, fileD and fileE. 181 * 182 * Returns true if the file and sattr match; otherwise, returns false. 183 */ 184 boolean_t 185 smb_sattr_check(uint16_t dosattr, uint16_t sattr) 186 { 187 if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) && 188 !(sattr & FILE_ATTRIBUTE_DIRECTORY)) 189 return (B_FALSE); 190 191 if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && 192 !(sattr & FILE_ATTRIBUTE_HIDDEN)) 193 return (B_FALSE); 194 195 if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && 196 !(sattr & FILE_ATTRIBUTE_SYSTEM)) 197 return (B_FALSE); 198 199 return (B_TRUE); 200 } 201 202 time_t 203 smb_get_boottime(void) 204 { 205 extern time_t boot_time; 206 zone_t *z = curzone; 207 208 /* Unfortunately, the GZ doesn't set zone_boot_time. */ 209 if (z->zone_id == GLOBAL_ZONEID) 210 return (boot_time); 211 212 return (z->zone_boot_time); 213 } 214 215 /* 216 * smb_idpool_increment 217 * 218 * This function increments the ID pool by doubling the current size. This 219 * function assumes the caller entered the mutex of the pool. 220 */ 221 static int 222 smb_idpool_increment( 223 smb_idpool_t *pool) 224 { 225 uint8_t *new_pool; 226 uint32_t new_size; 227 228 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 229 230 new_size = pool->id_size * 2; 231 if (new_size <= SMB_IDPOOL_MAX_SIZE) { 232 new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP); 233 if (new_pool) { 234 bzero(new_pool, new_size / 8); 235 bcopy(pool->id_pool, new_pool, pool->id_size / 8); 236 kmem_free(pool->id_pool, pool->id_size / 8); 237 pool->id_pool = new_pool; 238 pool->id_free_counter += new_size - pool->id_size; 239 pool->id_max_free_counter += new_size - pool->id_size; 240 pool->id_size = new_size; 241 pool->id_idx_msk = (new_size / 8) - 1; 242 if (new_size >= SMB_IDPOOL_MAX_SIZE) { 243 /* id -1 made unavailable */ 244 pool->id_pool[pool->id_idx_msk] = 0x80; 245 pool->id_free_counter--; 246 pool->id_max_free_counter--; 247 } 248 return (0); 249 } 250 } 251 return (-1); 252 } 253 254 /* 255 * smb_idpool_constructor 256 * 257 * This function initializes the pool structure provided. 258 */ 259 int 260 smb_idpool_constructor( 261 smb_idpool_t *pool) 262 { 263 264 ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC); 265 266 pool->id_size = SMB_IDPOOL_MIN_SIZE; 267 pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1; 268 pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1; 269 pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1; 270 pool->id_bit = 0x02; 271 pool->id_bit_idx = 1; 272 pool->id_idx = 0; 273 pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8), 274 KM_SLEEP); 275 bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8)); 276 /* -1 id made unavailable */ 277 pool->id_pool[0] = 0x01; /* id 0 made unavailable */ 278 mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL); 279 pool->id_magic = SMB_IDPOOL_MAGIC; 280 return (0); 281 } 282 283 /* 284 * smb_idpool_destructor 285 * 286 * This function tears down and frees the resources associated with the 287 * pool provided. 288 */ 289 void 290 smb_idpool_destructor( 291 smb_idpool_t *pool) 292 { 293 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 294 ASSERT(pool->id_free_counter == pool->id_max_free_counter); 295 pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC; 296 mutex_destroy(&pool->id_mutex); 297 kmem_free(pool->id_pool, (size_t)(pool->id_size / 8)); 298 } 299 300 /* 301 * smb_idpool_alloc 302 * 303 * This function allocates an ID from the pool provided. 304 */ 305 int 306 smb_idpool_alloc( 307 smb_idpool_t *pool, 308 uint16_t *id) 309 { 310 uint32_t i; 311 uint8_t bit; 312 uint8_t bit_idx; 313 uint8_t byte; 314 315 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 316 317 mutex_enter(&pool->id_mutex); 318 if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) { 319 mutex_exit(&pool->id_mutex); 320 return (-1); 321 } 322 323 i = pool->id_size; 324 while (i) { 325 bit = pool->id_bit; 326 bit_idx = pool->id_bit_idx; 327 byte = pool->id_pool[pool->id_idx]; 328 while (bit) { 329 if (byte & bit) { 330 bit = bit << 1; 331 bit_idx++; 332 continue; 333 } 334 pool->id_pool[pool->id_idx] |= bit; 335 *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx); 336 pool->id_free_counter--; 337 /* 338 * Leave position at next bit to allocate, 339 * so we don't keep re-using the last in an 340 * alloc/free/alloc/free sequence. Doing 341 * that can confuse some SMB clients. 342 */ 343 if (bit & 0x80) { 344 pool->id_bit = 1; 345 pool->id_bit_idx = 0; 346 pool->id_idx++; 347 pool->id_idx &= pool->id_idx_msk; 348 } else { 349 pool->id_bit = (bit << 1); 350 pool->id_bit_idx = bit_idx + 1; 351 /* keep id_idx */ 352 } 353 mutex_exit(&pool->id_mutex); 354 return (0); 355 } 356 pool->id_bit = 1; 357 pool->id_bit_idx = 0; 358 pool->id_idx++; 359 pool->id_idx &= pool->id_idx_msk; 360 --i; 361 } 362 /* 363 * This section of code shouldn't be reached. If there are IDs 364 * available and none could be found there's a problem. 365 */ 366 ASSERT(0); 367 mutex_exit(&pool->id_mutex); 368 return (-1); 369 } 370 371 /* 372 * smb_idpool_free 373 * 374 * This function frees the ID provided. 375 */ 376 void 377 smb_idpool_free( 378 smb_idpool_t *pool, 379 uint16_t id) 380 { 381 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 382 ASSERT(id != 0); 383 ASSERT(id != 0xFFFF); 384 385 mutex_enter(&pool->id_mutex); 386 if (pool->id_pool[id >> 3] & (1 << (id & 7))) { 387 pool->id_pool[id >> 3] &= ~(1 << (id & 7)); 388 pool->id_free_counter++; 389 ASSERT(pool->id_free_counter <= pool->id_max_free_counter); 390 mutex_exit(&pool->id_mutex); 391 return; 392 } 393 /* Freeing a free ID. */ 394 ASSERT(0); 395 mutex_exit(&pool->id_mutex); 396 } 397 398 /* 399 * smb_lavl_constructor 400 * 401 * This function initializes a locked avl. 402 */ 403 void 404 smb_lavl_constructor( 405 smb_lavl_t *la, 406 int (*compar) (const void *, const void *), 407 size_t size, 408 size_t offset) 409 { 410 rw_init(&la->la_lock, NULL, RW_DEFAULT, NULL); 411 mutex_init(&la->la_mutex, NULL, MUTEX_DEFAULT, NULL); 412 avl_create(&la->la_tree, compar, size, offset); 413 list_create(&la->la_deleteq, sizeof (smb_dtor_t), 414 offsetof(smb_dtor_t, dt_lnd)); 415 la->la_wrop = 0; 416 la->la_deleteq_count = 0; 417 la->la_flushing = B_FALSE; 418 } 419 420 /* 421 * Flush the delete queue and destroy a locked avl. 422 */ 423 void 424 smb_lavl_destructor( 425 smb_lavl_t *la) 426 { 427 smb_lavl_flush(la); 428 429 ASSERT(la->la_deleteq_count == 0); 430 ASSERT0(avl_numnodes(&la->la_tree)); 431 432 rw_destroy(&la->la_lock); 433 avl_destroy(&la->la_tree); 434 list_destroy(&la->la_deleteq); 435 mutex_destroy(&la->la_mutex); 436 } 437 438 /* 439 * smb_lavl_enter 440 * Not a macro so dtrace smbsrv:* can see it. 441 */ 442 void 443 smb_lavl_enter(smb_lavl_t *la, krw_t mode) 444 { 445 rw_enter(&la->la_lock, mode); 446 } 447 448 /* 449 * Post an object to the delete queue. The delete queue will be processed 450 * during smb_lavl_exit or lavl destruction. Objects are often posted for 451 * deletion during avl iteration (while the lavl is locked) but that is 452 * not required, and an object can be posted at any time. 453 */ 454 void 455 smb_lavl_post(smb_lavl_t *la, void *object, smb_dtorproc_t dtorproc) 456 { 457 smb_dtor_t *dtor; 458 459 ASSERT((object != NULL) && (dtorproc != NULL)); 460 461 dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP); 462 bzero(dtor, sizeof (smb_dtor_t)); 463 dtor->dt_magic = SMB_DTOR_MAGIC; 464 dtor->dt_object = object; 465 dtor->dt_proc = dtorproc; 466 467 mutex_enter(&la->la_mutex); 468 list_insert_tail(&la->la_deleteq, dtor); 469 ++la->la_deleteq_count; 470 mutex_exit(&la->la_mutex); 471 } 472 473 /* 474 * Exit the lavl lock and process the delete queue. 475 */ 476 void 477 smb_lavl_exit(smb_lavl_t *la) 478 { 479 rw_exit(&la->la_lock); 480 smb_lavl_flush(la); 481 } 482 483 /* 484 * Flush the lavl delete queue. The mutex is dropped across the destructor 485 * call in case this leads to additional objects being posted to the delete 486 * queue. 487 */ 488 void 489 smb_lavl_flush(smb_lavl_t *la) 490 { 491 smb_dtor_t *dtor; 492 493 mutex_enter(&la->la_mutex); 494 if (la->la_flushing) { 495 mutex_exit(&la->la_mutex); 496 return; 497 } 498 la->la_flushing = B_TRUE; 499 500 dtor = list_head(&la->la_deleteq); 501 while (dtor != NULL) { 502 SMB_DTOR_VALID(dtor); 503 ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL)); 504 list_remove(&la->la_deleteq, dtor); 505 --la->la_deleteq_count; 506 mutex_exit(&la->la_mutex); 507 508 dtor->dt_proc(dtor->dt_object); 509 510 dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC; 511 kmem_cache_free(smb_dtor_cache, dtor); 512 mutex_enter(&la->la_mutex); 513 dtor = list_head(&la->la_deleteq); 514 } 515 la->la_flushing = B_FALSE; 516 517 mutex_exit(&la->la_mutex); 518 } 519 520 /* 521 * smb_lavl_upgrade 522 * 523 * This function tries to upgrade the lock of the locked avl. It assumes the 524 * locked has already been entered in RW_READER mode. It first tries using the 525 * Solaris function rw_tryupgrade(). If that call fails the lock is released 526 * and reentered in RW_WRITER mode. In that last case a window is opened during 527 * which the contents of the avl may have changed. The return code indicates 528 * whether or not the avl was modified when the lock was exited. 529 */ 530 int smb_lavl_upgrade( 531 smb_lavl_t *la) 532 { 533 uint64_t wrop; 534 535 if (rw_tryupgrade(&la->la_lock) != 0) { 536 return (0); 537 } 538 wrop = la->la_wrop; 539 rw_exit(&la->la_lock); 540 rw_enter(&la->la_lock, RW_WRITER); 541 return (wrop != la->la_wrop); 542 } 543 544 /* 545 * smb_lavl_insert 546 * 547 * This function inserts the object passed into the tree 548 * at the position determined by the AVL comparator. 549 */ 550 void 551 smb_lavl_insert( 552 smb_lavl_t *la, 553 void *obj) 554 { 555 avl_add(&la->la_tree, obj); 556 ++la->la_wrop; 557 } 558 559 /* 560 * smb_lavl_remove 561 * 562 * This function removes the object passed from the lavl. This function 563 * assumes the lock of the lavl has already been entered. 564 */ 565 void 566 smb_lavl_remove( 567 smb_lavl_t *la, 568 void *obj) 569 { 570 avl_remove(&la->la_tree, obj); 571 ++la->la_wrop; 572 } 573 574 /* 575 * smb_lavl_get_count 576 * 577 * This function returns the number of elements in the specified avl. 578 */ 579 uint32_t 580 smb_lavl_get_count( 581 smb_lavl_t *la) 582 { 583 return ((uint32_t)avl_numnodes(&la->la_tree)); 584 } 585 586 /* 587 * Initialize the llist delete queue object cache. 588 */ 589 void 590 smb_llist_init(void) 591 { 592 if (smb_dtor_cache != NULL) 593 return; 594 595 smb_dtor_cache = kmem_cache_create("smb_dtor_cache", 596 sizeof (smb_dtor_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 597 } 598 599 /* 600 * Destroy the llist delete queue object cache. 601 */ 602 void 603 smb_llist_fini(void) 604 { 605 if (smb_dtor_cache != NULL) { 606 kmem_cache_destroy(smb_dtor_cache); 607 smb_dtor_cache = NULL; 608 } 609 } 610 611 /* 612 * smb_llist_constructor 613 * 614 * This function initializes a locked list. 615 */ 616 void 617 smb_llist_constructor( 618 smb_llist_t *ll, 619 size_t size, 620 size_t offset) 621 { 622 rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL); 623 mutex_init(&ll->ll_mutex, NULL, MUTEX_DEFAULT, NULL); 624 list_create(&ll->ll_list, size, offset); 625 list_create(&ll->ll_deleteq, sizeof (smb_dtor_t), 626 offsetof(smb_dtor_t, dt_lnd)); 627 ll->ll_count = 0; 628 ll->ll_wrop = 0; 629 ll->ll_deleteq_count = 0; 630 ll->ll_flushing = B_FALSE; 631 } 632 633 /* 634 * Flush the delete queue and destroy a locked list. 635 */ 636 void 637 smb_llist_destructor( 638 smb_llist_t *ll) 639 { 640 smb_llist_flush(ll); 641 642 ASSERT(ll->ll_count == 0); 643 ASSERT(ll->ll_deleteq_count == 0); 644 645 rw_destroy(&ll->ll_lock); 646 list_destroy(&ll->ll_list); 647 list_destroy(&ll->ll_deleteq); 648 mutex_destroy(&ll->ll_mutex); 649 } 650 651 /* 652 * smb_llist_enter 653 * Not a macro so dtrace smbsrv:* can see it. 654 */ 655 void 656 smb_llist_enter(smb_llist_t *ll, krw_t mode) 657 { 658 rw_enter(&ll->ll_lock, mode); 659 } 660 661 /* 662 * Post an object to the delete queue. The delete queue will be processed 663 * during list exit or list destruction. Objects are often posted for 664 * deletion during list iteration (while the list is locked) but that is 665 * not required, and an object can be posted at any time. 666 */ 667 void 668 smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc) 669 { 670 smb_dtor_t *dtor; 671 672 ASSERT((object != NULL) && (dtorproc != NULL)); 673 674 dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP); 675 bzero(dtor, sizeof (smb_dtor_t)); 676 dtor->dt_magic = SMB_DTOR_MAGIC; 677 dtor->dt_object = object; 678 dtor->dt_proc = dtorproc; 679 680 mutex_enter(&ll->ll_mutex); 681 list_insert_tail(&ll->ll_deleteq, dtor); 682 ++ll->ll_deleteq_count; 683 mutex_exit(&ll->ll_mutex); 684 } 685 686 /* 687 * Exit the list lock and process the delete queue. 688 */ 689 void 690 smb_llist_exit(smb_llist_t *ll) 691 { 692 rw_exit(&ll->ll_lock); 693 smb_llist_flush(ll); 694 } 695 696 /* 697 * Flush the list delete queue. The mutex is dropped across the destructor 698 * call in case this leads to additional objects being posted to the delete 699 * queue. 700 */ 701 void 702 smb_llist_flush(smb_llist_t *ll) 703 { 704 smb_dtor_t *dtor; 705 706 mutex_enter(&ll->ll_mutex); 707 if (ll->ll_flushing) { 708 mutex_exit(&ll->ll_mutex); 709 return; 710 } 711 ll->ll_flushing = B_TRUE; 712 713 dtor = list_head(&ll->ll_deleteq); 714 while (dtor != NULL) { 715 SMB_DTOR_VALID(dtor); 716 ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL)); 717 list_remove(&ll->ll_deleteq, dtor); 718 --ll->ll_deleteq_count; 719 mutex_exit(&ll->ll_mutex); 720 721 dtor->dt_proc(dtor->dt_object); 722 723 dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC; 724 kmem_cache_free(smb_dtor_cache, dtor); 725 mutex_enter(&ll->ll_mutex); 726 dtor = list_head(&ll->ll_deleteq); 727 } 728 ll->ll_flushing = B_FALSE; 729 730 mutex_exit(&ll->ll_mutex); 731 } 732 733 /* 734 * smb_llist_upgrade 735 * 736 * This function tries to upgrade the lock of the locked list. It assumes the 737 * locked has already been entered in RW_READER mode. It first tries using the 738 * Solaris function rw_tryupgrade(). If that call fails the lock is released 739 * and reentered in RW_WRITER mode. In that last case a window is opened during 740 * which the contents of the list may have changed. The return code indicates 741 * whether or not the list was modified when the lock was exited. 742 */ 743 int smb_llist_upgrade( 744 smb_llist_t *ll) 745 { 746 uint64_t wrop; 747 748 if (rw_tryupgrade(&ll->ll_lock) != 0) { 749 return (0); 750 } 751 wrop = ll->ll_wrop; 752 rw_exit(&ll->ll_lock); 753 rw_enter(&ll->ll_lock, RW_WRITER); 754 return (wrop != ll->ll_wrop); 755 } 756 757 /* 758 * smb_llist_insert_head 759 * 760 * This function inserts the object passed a the beginning of the list. This 761 * function assumes the lock of the list has already been entered. 762 */ 763 void 764 smb_llist_insert_head( 765 smb_llist_t *ll, 766 void *obj) 767 { 768 list_insert_head(&ll->ll_list, obj); 769 ++ll->ll_wrop; 770 ++ll->ll_count; 771 } 772 773 /* 774 * smb_llist_insert_tail 775 * 776 * This function appends to the object passed to the list. This function assumes 777 * the lock of the list has already been entered. 778 * 779 */ 780 void 781 smb_llist_insert_tail( 782 smb_llist_t *ll, 783 void *obj) 784 { 785 list_insert_tail(&ll->ll_list, obj); 786 ++ll->ll_wrop; 787 ++ll->ll_count; 788 } 789 790 /* 791 * smb_llist_remove 792 * 793 * This function removes the object passed from the list. This function assumes 794 * the lock of the list has already been entered. 795 */ 796 void 797 smb_llist_remove( 798 smb_llist_t *ll, 799 void *obj) 800 { 801 list_remove(&ll->ll_list, obj); 802 ++ll->ll_wrop; 803 --ll->ll_count; 804 } 805 806 /* 807 * smb_llist_get_count 808 * 809 * This function returns the number of elements in the specified list. 810 */ 811 uint32_t 812 smb_llist_get_count( 813 smb_llist_t *ll) 814 { 815 return (ll->ll_count); 816 } 817 818 /* 819 * smb_slist_constructor 820 * 821 * Synchronized list constructor. 822 */ 823 void 824 smb_slist_constructor( 825 smb_slist_t *sl, 826 size_t size, 827 size_t offset) 828 { 829 mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL); 830 cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL); 831 list_create(&sl->sl_list, size, offset); 832 sl->sl_count = 0; 833 sl->sl_waiting = B_FALSE; 834 } 835 836 /* 837 * smb_slist_destructor 838 * 839 * Synchronized list destructor. 840 */ 841 void 842 smb_slist_destructor( 843 smb_slist_t *sl) 844 { 845 VERIFY(sl->sl_count == 0); 846 847 mutex_destroy(&sl->sl_mutex); 848 cv_destroy(&sl->sl_cv); 849 list_destroy(&sl->sl_list); 850 } 851 852 /* 853 * smb_slist_enter 854 * Not a macro so dtrace smbsrv:* can see it. 855 */ 856 void 857 smb_slist_enter(smb_slist_t *sl) 858 { 859 mutex_enter(&(sl)->sl_mutex); 860 } 861 862 /* 863 * smb_slist_insert_head 864 * 865 * This function inserts the object passed a the beginning of the list. 866 */ 867 void 868 smb_slist_insert_head( 869 smb_slist_t *sl, 870 void *obj) 871 { 872 mutex_enter(&sl->sl_mutex); 873 list_insert_head(&sl->sl_list, obj); 874 ++sl->sl_count; 875 mutex_exit(&sl->sl_mutex); 876 } 877 878 /* 879 * smb_slist_insert_tail 880 * 881 * This function appends the object passed to the list. 882 */ 883 void 884 smb_slist_insert_tail( 885 smb_slist_t *sl, 886 void *obj) 887 { 888 mutex_enter(&sl->sl_mutex); 889 list_insert_tail(&sl->sl_list, obj); 890 ++sl->sl_count; 891 mutex_exit(&sl->sl_mutex); 892 } 893 894 /* 895 * smb_llist_remove 896 * 897 * This function removes the object passed by the caller from the list. 898 */ 899 void 900 smb_slist_remove( 901 smb_slist_t *sl, 902 void *obj) 903 { 904 mutex_enter(&sl->sl_mutex); 905 list_remove(&sl->sl_list, obj); 906 if ((--sl->sl_count == 0) && (sl->sl_waiting)) { 907 sl->sl_waiting = B_FALSE; 908 cv_broadcast(&sl->sl_cv); 909 } 910 mutex_exit(&sl->sl_mutex); 911 } 912 913 /* 914 * smb_slist_move_tail 915 * 916 * This function transfers all the contents of the synchronized list to the 917 * list_t provided. It returns the number of objects transferred. 918 */ 919 uint32_t 920 smb_slist_move_tail( 921 list_t *lst, 922 smb_slist_t *sl) 923 { 924 uint32_t rv; 925 926 mutex_enter(&sl->sl_mutex); 927 rv = sl->sl_count; 928 if (sl->sl_count) { 929 list_move_tail(lst, &sl->sl_list); 930 sl->sl_count = 0; 931 if (sl->sl_waiting) { 932 sl->sl_waiting = B_FALSE; 933 cv_broadcast(&sl->sl_cv); 934 } 935 } 936 mutex_exit(&sl->sl_mutex); 937 return (rv); 938 } 939 940 /* 941 * smb_slist_obj_move 942 * 943 * This function moves an object from one list to the end of the other list. It 944 * assumes the mutex of each list has been entered. 945 */ 946 void 947 smb_slist_obj_move( 948 smb_slist_t *dst, 949 smb_slist_t *src, 950 void *obj) 951 { 952 ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset); 953 ASSERT(dst->sl_list.list_size == src->sl_list.list_size); 954 955 list_remove(&src->sl_list, obj); 956 list_insert_tail(&dst->sl_list, obj); 957 dst->sl_count++; 958 src->sl_count--; 959 if ((src->sl_count == 0) && (src->sl_waiting)) { 960 src->sl_waiting = B_FALSE; 961 cv_broadcast(&src->sl_cv); 962 } 963 } 964 965 /* 966 * smb_slist_wait_for_empty 967 * 968 * This function waits for a list to be emptied. 969 */ 970 void 971 smb_slist_wait_for_empty( 972 smb_slist_t *sl) 973 { 974 mutex_enter(&sl->sl_mutex); 975 while (sl->sl_count) { 976 sl->sl_waiting = B_TRUE; 977 cv_wait(&sl->sl_cv, &sl->sl_mutex); 978 } 979 mutex_exit(&sl->sl_mutex); 980 } 981 982 /* 983 * smb_slist_exit 984 * 985 * This function exits the muetx of the list and signal the condition variable 986 * if the list is empty. 987 */ 988 void 989 smb_slist_exit(smb_slist_t *sl) 990 { 991 if ((sl->sl_count == 0) && (sl->sl_waiting)) { 992 sl->sl_waiting = B_FALSE; 993 cv_broadcast(&sl->sl_cv); 994 } 995 mutex_exit(&sl->sl_mutex); 996 } 997 998 /* smb_thread_... moved to smb_thread.c */ 999 1000 /* 1001 * smb_rwx_init 1002 */ 1003 void 1004 smb_rwx_init( 1005 smb_rwx_t *rwx) 1006 { 1007 bzero(rwx, sizeof (smb_rwx_t)); 1008 cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL); 1009 mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL); 1010 rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL); 1011 } 1012 1013 /* 1014 * smb_rwx_destroy 1015 */ 1016 void 1017 smb_rwx_destroy( 1018 smb_rwx_t *rwx) 1019 { 1020 mutex_destroy(&rwx->rwx_mutex); 1021 cv_destroy(&rwx->rwx_cv); 1022 rw_destroy(&rwx->rwx_lock); 1023 } 1024 1025 /* 1026 * smb_rwx_rwenter 1027 */ 1028 void 1029 smb_rwx_rwenter(smb_rwx_t *rwx, krw_t mode) 1030 { 1031 rw_enter(&rwx->rwx_lock, mode); 1032 } 1033 1034 /* 1035 * smb_rwx_rwexit 1036 */ 1037 void 1038 smb_rwx_rwexit( 1039 smb_rwx_t *rwx) 1040 { 1041 rw_exit(&rwx->rwx_lock); 1042 } 1043 1044 1045 /* 1046 * smb_rwx_cvwait 1047 * 1048 * Wait on rwx->rw_cv, dropping the rw lock and retake after wakeup. 1049 * Assumes the smb_rwx lock was entered in RW_READER or RW_WRITER 1050 * mode. It will: 1051 * 1052 * 1) release the lock and save its current mode. 1053 * 2) wait until the condition variable is signaled. 1054 * 3) re-acquire the lock in the mode saved in (1). 1055 * 1056 * Lock order: rwlock, mutex 1057 */ 1058 int 1059 smb_rwx_cvwait( 1060 smb_rwx_t *rwx, 1061 clock_t timeout) 1062 { 1063 krw_t mode; 1064 int rc = 1; 1065 1066 if (rw_write_held(&rwx->rwx_lock)) { 1067 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1068 mode = RW_WRITER; 1069 } else { 1070 ASSERT(rw_read_held(&rwx->rwx_lock)); 1071 mode = RW_READER; 1072 } 1073 1074 mutex_enter(&rwx->rwx_mutex); 1075 rw_exit(&rwx->rwx_lock); 1076 1077 rwx->rwx_waiting = B_TRUE; 1078 if (timeout == -1) { 1079 cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex); 1080 } else { 1081 rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex, 1082 timeout, TR_CLOCK_TICK); 1083 } 1084 mutex_exit(&rwx->rwx_mutex); 1085 1086 rw_enter(&rwx->rwx_lock, mode); 1087 return (rc); 1088 } 1089 1090 /* 1091 * smb_rwx_cvbcast 1092 * 1093 * Wake up threads waiting on rx_cv 1094 * The rw lock may or may not be held. 1095 * The mutex MUST NOT be held. 1096 */ 1097 void 1098 smb_rwx_cvbcast(smb_rwx_t *rwx) 1099 { 1100 mutex_enter(&rwx->rwx_mutex); 1101 if (rwx->rwx_waiting) { 1102 rwx->rwx_waiting = B_FALSE; 1103 cv_broadcast(&rwx->rwx_cv); 1104 } 1105 mutex_exit(&rwx->rwx_mutex); 1106 } 1107 1108 /* smb_idmap_... moved to smb_idmap.c */ 1109 1110 uint64_t 1111 smb_time_unix_to_nt(timestruc_t *unix_time) 1112 { 1113 uint64_t nt_time; 1114 1115 if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0)) 1116 return (0); 1117 1118 nt_time = unix_time->tv_sec; 1119 nt_time *= 10000000; /* seconds to 100ns */ 1120 nt_time += unix_time->tv_nsec / 100; 1121 return (nt_time + NT_TIME_BIAS); 1122 } 1123 1124 void 1125 smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time) 1126 { 1127 uint32_t seconds; 1128 1129 ASSERT(unix_time); 1130 1131 if ((nt_time == 0) || (nt_time == -1)) { 1132 unix_time->tv_sec = 0; 1133 unix_time->tv_nsec = 0; 1134 return; 1135 } 1136 1137 /* 1138 * Can't represent times less than or equal NT_TIME_BIAS, 1139 * so convert them to the oldest date we can store. 1140 * Note that time zero is "special" being converted 1141 * both directions as 0:0 (unix-to-nt, nt-to-unix). 1142 */ 1143 if (nt_time <= NT_TIME_BIAS) { 1144 unix_time->tv_sec = 0; 1145 unix_time->tv_nsec = 100; 1146 return; 1147 } 1148 1149 nt_time -= NT_TIME_BIAS; 1150 seconds = nt_time / 10000000; 1151 unix_time->tv_sec = seconds; 1152 unix_time->tv_nsec = (nt_time % 10000000) * 100; 1153 } 1154 1155 /* 1156 * smb_time_gmt_to_local, smb_time_local_to_gmt 1157 * 1158 * Apply the gmt offset to convert between local time and gmt 1159 */ 1160 int32_t 1161 smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt) 1162 { 1163 if ((gmt == 0) || (gmt == -1)) 1164 return (0); 1165 1166 return (gmt - sr->sr_gmtoff); 1167 } 1168 1169 int32_t 1170 smb_time_local_to_gmt(smb_request_t *sr, int32_t local) 1171 { 1172 if ((local == 0) || (local == -1)) 1173 return (0); 1174 1175 return (local + sr->sr_gmtoff); 1176 } 1177 1178 1179 /* 1180 * smb_time_dos_to_unix 1181 * 1182 * Convert SMB_DATE & SMB_TIME values to a unix timestamp. 1183 * 1184 * A date/time field of 0 means that that server file system 1185 * assigned value need not be changed. The behaviour when the 1186 * date/time field is set to -1 is not documented but is 1187 * generally treated like 0. 1188 * If date or time is 0 or -1 the unix time is returned as 0 1189 * so that the caller can identify and handle this special case. 1190 */ 1191 int32_t 1192 smb_time_dos_to_unix(int16_t date, int16_t time) 1193 { 1194 struct tm atm; 1195 1196 if (((date == 0) || (time == 0)) || 1197 ((date == -1) || (time == -1))) { 1198 return (0); 1199 } 1200 1201 atm.tm_year = ((date >> 9) & 0x3F) + 80; 1202 atm.tm_mon = ((date >> 5) & 0x0F) - 1; 1203 atm.tm_mday = ((date >> 0) & 0x1F); 1204 atm.tm_hour = ((time >> 11) & 0x1F); 1205 atm.tm_min = ((time >> 5) & 0x3F); 1206 atm.tm_sec = ((time >> 0) & 0x1F) << 1; 1207 1208 return (smb_timegm(&atm)); 1209 } 1210 1211 void 1212 smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p) 1213 { 1214 struct tm atm; 1215 int i; 1216 time_t tmp_time; 1217 1218 if (ux_time == 0) { 1219 *date_p = 0; 1220 *time_p = 0; 1221 return; 1222 } 1223 1224 tmp_time = (time_t)ux_time; 1225 (void) smb_gmtime_r(&tmp_time, &atm); 1226 1227 if (date_p) { 1228 i = 0; 1229 i += atm.tm_year - 80; 1230 i <<= 4; 1231 i += atm.tm_mon + 1; 1232 i <<= 5; 1233 i += atm.tm_mday; 1234 1235 *date_p = (short)i; 1236 } 1237 if (time_p) { 1238 i = 0; 1239 i += atm.tm_hour; 1240 i <<= 6; 1241 i += atm.tm_min; 1242 i <<= 5; 1243 i += atm.tm_sec >> 1; 1244 1245 *time_p = (short)i; 1246 } 1247 } 1248 1249 1250 /* 1251 * smb_gmtime_r 1252 * 1253 * Thread-safe version of smb_gmtime. Returns a null pointer if either 1254 * input parameter is a null pointer. Otherwise returns a pointer 1255 * to result. 1256 * 1257 * Day of the week calculation: the Epoch was a thursday. 1258 * 1259 * There are no timezone corrections so tm_isdst and tm_gmtoff are 1260 * always zero, and the zone is always WET. 1261 */ 1262 struct tm * 1263 smb_gmtime_r(time_t *clock, struct tm *result) 1264 { 1265 time_t tsec; 1266 int year; 1267 int month; 1268 int sec_per_month; 1269 1270 if (clock == 0 || result == 0) 1271 return (0); 1272 1273 bzero(result, sizeof (struct tm)); 1274 tsec = *clock; 1275 tsec -= tzh_leapcnt; 1276 1277 result->tm_wday = tsec / SECSPERDAY; 1278 result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK; 1279 1280 year = EPOCH_YEAR; 1281 while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) : 1282 (SECSPERDAY * DAYSPERNYEAR))) { 1283 if (isleap(year)) 1284 tsec -= SECSPERDAY * DAYSPERLYEAR; 1285 else 1286 tsec -= SECSPERDAY * DAYSPERNYEAR; 1287 1288 ++year; 1289 } 1290 1291 result->tm_year = year - TM_YEAR_BASE; 1292 result->tm_yday = tsec / SECSPERDAY; 1293 1294 for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) { 1295 sec_per_month = days_in_month[month] * SECSPERDAY; 1296 1297 if (month == TM_FEBRUARY && isleap(year)) 1298 sec_per_month += SECSPERDAY; 1299 1300 if (tsec < sec_per_month) 1301 break; 1302 1303 tsec -= sec_per_month; 1304 } 1305 1306 result->tm_mon = month; 1307 result->tm_mday = (tsec / SECSPERDAY) + 1; 1308 tsec %= SECSPERDAY; 1309 result->tm_sec = tsec % 60; 1310 tsec /= 60; 1311 result->tm_min = tsec % 60; 1312 tsec /= 60; 1313 result->tm_hour = (int)tsec; 1314 1315 return (result); 1316 } 1317 1318 1319 /* 1320 * smb_timegm 1321 * 1322 * Converts the broken-down time in tm to a time value, i.e. the number 1323 * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is 1324 * not a POSIX or ANSI function. Per the man page, the input values of 1325 * tm_wday and tm_yday are ignored and, as the input data is assumed to 1326 * represent GMT, we force tm_isdst and tm_gmtoff to 0. 1327 * 1328 * Before returning the clock time, we use smb_gmtime_r to set up tm_wday 1329 * and tm_yday, and bring the other fields within normal range. I don't 1330 * think this is really how it should be done but it's convenient for 1331 * now. 1332 */ 1333 time_t 1334 smb_timegm(struct tm *tm) 1335 { 1336 time_t tsec; 1337 int dd; 1338 int mm; 1339 int yy; 1340 int year; 1341 1342 if (tm == 0) 1343 return (-1); 1344 1345 year = tm->tm_year + TM_YEAR_BASE; 1346 tsec = tzh_leapcnt; 1347 1348 for (yy = EPOCH_YEAR; yy < year; ++yy) { 1349 if (isleap(yy)) 1350 tsec += SECSPERDAY * DAYSPERLYEAR; 1351 else 1352 tsec += SECSPERDAY * DAYSPERNYEAR; 1353 } 1354 1355 for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) { 1356 dd = days_in_month[mm] * SECSPERDAY; 1357 1358 if (mm == TM_FEBRUARY && isleap(year)) 1359 dd += SECSPERDAY; 1360 1361 tsec += dd; 1362 } 1363 1364 tsec += (tm->tm_mday - 1) * SECSPERDAY; 1365 tsec += tm->tm_sec; 1366 tsec += tm->tm_min * SECSPERMIN; 1367 tsec += tm->tm_hour * SECSPERHOUR; 1368 1369 tm->tm_isdst = 0; 1370 (void) smb_gmtime_r(&tsec, tm); 1371 return (tsec); 1372 } 1373 1374 /* 1375 * smb_pad_align 1376 * 1377 * Returns the number of bytes required to pad an offset to the 1378 * specified alignment. 1379 */ 1380 uint32_t 1381 smb_pad_align(uint32_t offset, uint32_t align) 1382 { 1383 uint32_t pad = offset % align; 1384 1385 if (pad != 0) 1386 pad = align - pad; 1387 1388 return (pad); 1389 } 1390 1391 /* 1392 * smb_panic 1393 * 1394 * Logs the file name, function name and line number passed in and panics the 1395 * system. 1396 */ 1397 void 1398 smb_panic(char *file, const char *func, int line) 1399 { 1400 cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line); 1401 } 1402 1403 /* 1404 * Creates an AVL tree and initializes the given smb_avl_t 1405 * structure using the passed args 1406 */ 1407 void 1408 smb_avl_create(smb_avl_t *avl, size_t size, size_t offset, 1409 const smb_avl_nops_t *ops) 1410 { 1411 ASSERT(avl); 1412 ASSERT(ops); 1413 1414 rw_init(&avl->avl_lock, NULL, RW_DEFAULT, NULL); 1415 mutex_init(&avl->avl_mutex, NULL, MUTEX_DEFAULT, NULL); 1416 1417 avl->avl_nops = ops; 1418 avl->avl_state = SMB_AVL_STATE_READY; 1419 avl->avl_refcnt = 0; 1420 (void) random_get_pseudo_bytes((uint8_t *)&avl->avl_sequence, 1421 sizeof (uint32_t)); 1422 1423 avl_create(&avl->avl_tree, ops->avln_cmp, size, offset); 1424 } 1425 1426 /* 1427 * Destroys the specified AVL tree. 1428 * It waits for all the in-flight operations to finish 1429 * before destroying the AVL. 1430 */ 1431 void 1432 smb_avl_destroy(smb_avl_t *avl) 1433 { 1434 void *cookie = NULL; 1435 void *node; 1436 1437 ASSERT(avl); 1438 1439 mutex_enter(&avl->avl_mutex); 1440 if (avl->avl_state != SMB_AVL_STATE_READY) { 1441 mutex_exit(&avl->avl_mutex); 1442 return; 1443 } 1444 1445 avl->avl_state = SMB_AVL_STATE_DESTROYING; 1446 1447 while (avl->avl_refcnt > 0) 1448 (void) cv_wait(&avl->avl_cv, &avl->avl_mutex); 1449 mutex_exit(&avl->avl_mutex); 1450 1451 rw_enter(&avl->avl_lock, RW_WRITER); 1452 while ((node = avl_destroy_nodes(&avl->avl_tree, &cookie)) != NULL) 1453 avl->avl_nops->avln_destroy(node); 1454 1455 avl_destroy(&avl->avl_tree); 1456 rw_exit(&avl->avl_lock); 1457 1458 rw_destroy(&avl->avl_lock); 1459 1460 mutex_destroy(&avl->avl_mutex); 1461 bzero(avl, sizeof (smb_avl_t)); 1462 } 1463 1464 /* 1465 * Adds the given item to the AVL if it's 1466 * not already there. 1467 * 1468 * Returns: 1469 * 1470 * ENOTACTIVE AVL is not in READY state 1471 * EEXIST The item is already in AVL 1472 */ 1473 int 1474 smb_avl_add(smb_avl_t *avl, void *item) 1475 { 1476 avl_index_t where; 1477 1478 ASSERT(avl); 1479 ASSERT(item); 1480 1481 if (!smb_avl_hold(avl)) 1482 return (ENOTACTIVE); 1483 1484 rw_enter(&avl->avl_lock, RW_WRITER); 1485 if (avl_find(&avl->avl_tree, item, &where) != NULL) { 1486 rw_exit(&avl->avl_lock); 1487 smb_avl_rele(avl); 1488 return (EEXIST); 1489 } 1490 1491 avl_insert(&avl->avl_tree, item, where); 1492 avl->avl_sequence++; 1493 rw_exit(&avl->avl_lock); 1494 1495 smb_avl_rele(avl); 1496 return (0); 1497 } 1498 1499 /* 1500 * Removes the given item from the AVL. 1501 * If no reference is left on the item 1502 * it will also be destroyed by calling the 1503 * registered destroy operation. 1504 */ 1505 void 1506 smb_avl_remove(smb_avl_t *avl, void *item) 1507 { 1508 avl_index_t where; 1509 void *rm_item; 1510 1511 ASSERT(avl); 1512 ASSERT(item); 1513 1514 if (!smb_avl_hold(avl)) 1515 return; 1516 1517 rw_enter(&avl->avl_lock, RW_WRITER); 1518 if ((rm_item = avl_find(&avl->avl_tree, item, &where)) == NULL) { 1519 rw_exit(&avl->avl_lock); 1520 smb_avl_rele(avl); 1521 return; 1522 } 1523 1524 avl_remove(&avl->avl_tree, rm_item); 1525 if (avl->avl_nops->avln_rele(rm_item)) 1526 avl->avl_nops->avln_destroy(rm_item); 1527 avl->avl_sequence++; 1528 rw_exit(&avl->avl_lock); 1529 1530 smb_avl_rele(avl); 1531 } 1532 1533 /* 1534 * Looks up the AVL for the given item. 1535 * If the item is found a hold on the object 1536 * is taken before the pointer to it is 1537 * returned to the caller. The caller MUST 1538 * always call smb_avl_release() after it's done 1539 * using the returned object to release the hold 1540 * taken on the object. 1541 */ 1542 void * 1543 smb_avl_lookup(smb_avl_t *avl, void *item) 1544 { 1545 void *node = NULL; 1546 1547 ASSERT(avl); 1548 ASSERT(item); 1549 1550 if (!smb_avl_hold(avl)) 1551 return (NULL); 1552 1553 rw_enter(&avl->avl_lock, RW_READER); 1554 node = avl_find(&avl->avl_tree, item, NULL); 1555 if (node != NULL) 1556 avl->avl_nops->avln_hold(node); 1557 rw_exit(&avl->avl_lock); 1558 1559 if (node == NULL) 1560 smb_avl_rele(avl); 1561 1562 return (node); 1563 } 1564 1565 /* 1566 * The hold on the given object is released. 1567 * This function MUST always be called after 1568 * smb_avl_lookup() and smb_avl_iterate() for 1569 * the returned object. 1570 * 1571 * If AVL is in DESTROYING state, the destroying 1572 * thread will be notified. 1573 */ 1574 void 1575 smb_avl_release(smb_avl_t *avl, void *item) 1576 { 1577 ASSERT(avl); 1578 ASSERT(item); 1579 1580 if (avl->avl_nops->avln_rele(item)) 1581 avl->avl_nops->avln_destroy(item); 1582 1583 smb_avl_rele(avl); 1584 } 1585 1586 /* 1587 * Initializes the given cursor for the AVL. 1588 * The cursor will be used to iterate through the AVL 1589 */ 1590 void 1591 smb_avl_iterinit(smb_avl_t *avl, smb_avl_cursor_t *cursor) 1592 { 1593 ASSERT(avl); 1594 ASSERT(cursor); 1595 1596 cursor->avlc_next = NULL; 1597 cursor->avlc_sequence = avl->avl_sequence; 1598 } 1599 1600 /* 1601 * Iterates through the AVL using the given cursor. 1602 * It always starts at the beginning and then returns 1603 * a pointer to the next object on each subsequent call. 1604 * 1605 * If a new object is added to or removed from the AVL 1606 * between two calls to this function, the iteration 1607 * will terminate prematurely. 1608 * 1609 * The caller MUST always call smb_avl_release() after it's 1610 * done using the returned object to release the hold taken 1611 * on the object. 1612 */ 1613 void * 1614 smb_avl_iterate(smb_avl_t *avl, smb_avl_cursor_t *cursor) 1615 { 1616 void *node; 1617 1618 ASSERT(avl); 1619 ASSERT(cursor); 1620 1621 if (!smb_avl_hold(avl)) 1622 return (NULL); 1623 1624 rw_enter(&avl->avl_lock, RW_READER); 1625 if (cursor->avlc_sequence != avl->avl_sequence) { 1626 rw_exit(&avl->avl_lock); 1627 smb_avl_rele(avl); 1628 return (NULL); 1629 } 1630 1631 if (cursor->avlc_next == NULL) 1632 node = avl_first(&avl->avl_tree); 1633 else 1634 node = AVL_NEXT(&avl->avl_tree, cursor->avlc_next); 1635 1636 if (node != NULL) 1637 avl->avl_nops->avln_hold(node); 1638 1639 cursor->avlc_next = node; 1640 rw_exit(&avl->avl_lock); 1641 1642 if (node == NULL) 1643 smb_avl_rele(avl); 1644 1645 return (node); 1646 } 1647 1648 /* 1649 * Increments the AVL reference count in order to 1650 * prevent the avl from being destroyed while it's 1651 * being accessed. 1652 */ 1653 static boolean_t 1654 smb_avl_hold(smb_avl_t *avl) 1655 { 1656 mutex_enter(&avl->avl_mutex); 1657 if (avl->avl_state != SMB_AVL_STATE_READY) { 1658 mutex_exit(&avl->avl_mutex); 1659 return (B_FALSE); 1660 } 1661 avl->avl_refcnt++; 1662 mutex_exit(&avl->avl_mutex); 1663 1664 return (B_TRUE); 1665 } 1666 1667 /* 1668 * Decrements the AVL reference count to release the 1669 * hold. If another thread is trying to destroy the 1670 * AVL and is waiting for the reference count to become 1671 * 0, it is signaled to wake up. 1672 */ 1673 static void 1674 smb_avl_rele(smb_avl_t *avl) 1675 { 1676 mutex_enter(&avl->avl_mutex); 1677 ASSERT(avl->avl_refcnt > 0); 1678 avl->avl_refcnt--; 1679 if (avl->avl_state == SMB_AVL_STATE_DESTROYING) 1680 cv_broadcast(&avl->avl_cv); 1681 mutex_exit(&avl->avl_mutex); 1682 } 1683 1684 /* 1685 * smb_latency_init 1686 */ 1687 void 1688 smb_latency_init(smb_latency_t *lat) 1689 { 1690 bzero(lat, sizeof (*lat)); 1691 mutex_init(&lat->ly_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); 1692 } 1693 1694 /* 1695 * smb_latency_destroy 1696 */ 1697 void 1698 smb_latency_destroy(smb_latency_t *lat) 1699 { 1700 mutex_destroy(&lat->ly_mutex); 1701 } 1702 1703 /* 1704 * smb_latency_add_sample 1705 * 1706 * Uses the new sample to calculate the new mean and standard deviation. The 1707 * sample must be a scaled value. 1708 */ 1709 void 1710 smb_latency_add_sample(smb_latency_t *lat, hrtime_t sample) 1711 { 1712 hrtime_t a_mean; 1713 hrtime_t d_mean; 1714 1715 mutex_enter(&lat->ly_mutex); 1716 lat->ly_a_nreq++; 1717 lat->ly_a_sum += sample; 1718 if (lat->ly_a_nreq != 0) { 1719 a_mean = lat->ly_a_sum / lat->ly_a_nreq; 1720 lat->ly_a_stddev = 1721 (sample - a_mean) * (sample - lat->ly_a_mean); 1722 lat->ly_a_mean = a_mean; 1723 } 1724 lat->ly_d_nreq++; 1725 lat->ly_d_sum += sample; 1726 if (lat->ly_d_nreq != 0) { 1727 d_mean = lat->ly_d_sum / lat->ly_d_nreq; 1728 lat->ly_d_stddev = 1729 (sample - d_mean) * (sample - lat->ly_d_mean); 1730 lat->ly_d_mean = d_mean; 1731 } 1732 mutex_exit(&lat->ly_mutex); 1733 } 1734 1735 /* 1736 * smb_srqueue_init 1737 */ 1738 void 1739 smb_srqueue_init(smb_srqueue_t *srq) 1740 { 1741 bzero(srq, sizeof (*srq)); 1742 mutex_init(&srq->srq_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); 1743 srq->srq_wlastupdate = srq->srq_rlastupdate = gethrtime_unscaled(); 1744 } 1745 1746 /* 1747 * smb_srqueue_destroy 1748 */ 1749 void 1750 smb_srqueue_destroy(smb_srqueue_t *srq) 1751 { 1752 mutex_destroy(&srq->srq_mutex); 1753 } 1754 1755 /* 1756 * smb_srqueue_waitq_enter 1757 */ 1758 void 1759 smb_srqueue_waitq_enter(smb_srqueue_t *srq) 1760 { 1761 hrtime_t new; 1762 hrtime_t delta; 1763 uint32_t wcnt; 1764 1765 mutex_enter(&srq->srq_mutex); 1766 new = gethrtime_unscaled(); 1767 delta = new - srq->srq_wlastupdate; 1768 srq->srq_wlastupdate = new; 1769 wcnt = srq->srq_wcnt++; 1770 if (wcnt != 0) { 1771 srq->srq_wlentime += delta * wcnt; 1772 srq->srq_wtime += delta; 1773 } 1774 mutex_exit(&srq->srq_mutex); 1775 } 1776 1777 /* 1778 * smb_srqueue_runq_exit 1779 */ 1780 void 1781 smb_srqueue_runq_exit(smb_srqueue_t *srq) 1782 { 1783 hrtime_t new; 1784 hrtime_t delta; 1785 uint32_t rcnt; 1786 1787 mutex_enter(&srq->srq_mutex); 1788 new = gethrtime_unscaled(); 1789 delta = new - srq->srq_rlastupdate; 1790 srq->srq_rlastupdate = new; 1791 rcnt = srq->srq_rcnt--; 1792 ASSERT(rcnt > 0); 1793 srq->srq_rlentime += delta * rcnt; 1794 srq->srq_rtime += delta; 1795 mutex_exit(&srq->srq_mutex); 1796 } 1797 1798 /* 1799 * smb_srqueue_waitq_to_runq 1800 */ 1801 void 1802 smb_srqueue_waitq_to_runq(smb_srqueue_t *srq) 1803 { 1804 hrtime_t new; 1805 hrtime_t delta; 1806 uint32_t wcnt; 1807 uint32_t rcnt; 1808 1809 mutex_enter(&srq->srq_mutex); 1810 new = gethrtime_unscaled(); 1811 delta = new - srq->srq_wlastupdate; 1812 srq->srq_wlastupdate = new; 1813 wcnt = srq->srq_wcnt--; 1814 ASSERT(wcnt > 0); 1815 srq->srq_wlentime += delta * wcnt; 1816 srq->srq_wtime += delta; 1817 delta = new - srq->srq_rlastupdate; 1818 srq->srq_rlastupdate = new; 1819 rcnt = srq->srq_rcnt++; 1820 if (rcnt != 0) { 1821 srq->srq_rlentime += delta * rcnt; 1822 srq->srq_rtime += delta; 1823 } 1824 mutex_exit(&srq->srq_mutex); 1825 } 1826 1827 /* 1828 * smb_srqueue_update 1829 * 1830 * Takes a snapshot of the smb_sr_stat_t structure passed in. 1831 */ 1832 void 1833 smb_srqueue_update(smb_srqueue_t *srq, smb_kstat_utilization_t *kd) 1834 { 1835 hrtime_t delta; 1836 hrtime_t snaptime; 1837 1838 mutex_enter(&srq->srq_mutex); 1839 snaptime = gethrtime_unscaled(); 1840 delta = snaptime - srq->srq_wlastupdate; 1841 srq->srq_wlastupdate = snaptime; 1842 if (srq->srq_wcnt != 0) { 1843 srq->srq_wlentime += delta * srq->srq_wcnt; 1844 srq->srq_wtime += delta; 1845 } 1846 delta = snaptime - srq->srq_rlastupdate; 1847 srq->srq_rlastupdate = snaptime; 1848 if (srq->srq_rcnt != 0) { 1849 srq->srq_rlentime += delta * srq->srq_rcnt; 1850 srq->srq_rtime += delta; 1851 } 1852 kd->ku_rlentime = srq->srq_rlentime; 1853 kd->ku_rtime = srq->srq_rtime; 1854 kd->ku_wlentime = srq->srq_wlentime; 1855 kd->ku_wtime = srq->srq_wtime; 1856 mutex_exit(&srq->srq_mutex); 1857 scalehrtime(&kd->ku_rlentime); 1858 scalehrtime(&kd->ku_rtime); 1859 scalehrtime(&kd->ku_wlentime); 1860 scalehrtime(&kd->ku_wtime); 1861 } 1862 1863 void 1864 smb_threshold_init(smb_cmd_threshold_t *ct, char *cmd, 1865 uint_t threshold, uint_t timeout) 1866 { 1867 bzero(ct, sizeof (smb_cmd_threshold_t)); 1868 mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 1869 cv_init(&ct->ct_cond, NULL, CV_DEFAULT, NULL); 1870 1871 ct->ct_cmd = cmd; 1872 ct->ct_threshold = threshold; 1873 ct->ct_timeout = timeout; 1874 } 1875 1876 void 1877 smb_threshold_fini(smb_cmd_threshold_t *ct) 1878 { 1879 cv_destroy(&ct->ct_cond); 1880 mutex_destroy(&ct->ct_mutex); 1881 } 1882 1883 /* 1884 * This threshold mechanism is used to limit the number of simultaneous 1885 * named pipe connections, concurrent authentication conversations, etc. 1886 * Requests that would take us over the threshold wait until either the 1887 * resources are available (return zero) or timeout (return error). 1888 */ 1889 int 1890 smb_threshold_enter(smb_cmd_threshold_t *ct) 1891 { 1892 clock_t time, rem; 1893 1894 time = MSEC_TO_TICK(ct->ct_timeout) + ddi_get_lbolt(); 1895 mutex_enter(&ct->ct_mutex); 1896 1897 while (ct->ct_threshold != 0 && 1898 ct->ct_threshold <= ct->ct_active_cnt) { 1899 ct->ct_blocked_cnt++; 1900 rem = cv_timedwait(&ct->ct_cond, &ct->ct_mutex, time); 1901 ct->ct_blocked_cnt--; 1902 if (rem < 0) { 1903 mutex_exit(&ct->ct_mutex); 1904 return (ETIME); 1905 } 1906 } 1907 if (ct->ct_threshold == 0) { 1908 mutex_exit(&ct->ct_mutex); 1909 return (ECANCELED); 1910 } 1911 1912 ASSERT3U(ct->ct_active_cnt, <, ct->ct_threshold); 1913 ct->ct_active_cnt++; 1914 1915 mutex_exit(&ct->ct_mutex); 1916 return (0); 1917 } 1918 1919 void 1920 smb_threshold_exit(smb_cmd_threshold_t *ct) 1921 { 1922 mutex_enter(&ct->ct_mutex); 1923 ASSERT3U(ct->ct_active_cnt, >, 0); 1924 ct->ct_active_cnt--; 1925 if (ct->ct_blocked_cnt) 1926 cv_signal(&ct->ct_cond); 1927 mutex_exit(&ct->ct_mutex); 1928 } 1929 1930 void 1931 smb_threshold_wake_all(smb_cmd_threshold_t *ct) 1932 { 1933 mutex_enter(&ct->ct_mutex); 1934 ct->ct_threshold = 0; 1935 cv_broadcast(&ct->ct_cond); 1936 mutex_exit(&ct->ct_mutex); 1937 } 1938 1939 /* taken from mod_hash_byptr */ 1940 uint_t 1941 smb_hash_uint64(smb_hash_t *hash, uint64_t val) 1942 { 1943 uint64_t k = val >> hash->rshift; 1944 uint_t idx = ((uint_t)k) & (hash->num_buckets - 1); 1945 1946 return (idx); 1947 } 1948 1949 boolean_t 1950 smb_is_pow2(size_t n) 1951 { 1952 return ((n & (n - 1)) == 0); 1953 } 1954 1955 smb_hash_t * 1956 smb_hash_create(size_t elemsz, size_t link_offset, 1957 uint32_t num_buckets) 1958 { 1959 smb_hash_t *hash = kmem_alloc(sizeof (*hash), KM_SLEEP); 1960 int i; 1961 1962 if (!smb_is_pow2(num_buckets)) 1963 num_buckets = 1 << highbit(num_buckets); 1964 1965 hash->rshift = highbit(elemsz); 1966 hash->num_buckets = num_buckets; 1967 hash->buckets = kmem_zalloc(num_buckets * sizeof (smb_bucket_t), 1968 KM_SLEEP); 1969 for (i = 0; i < num_buckets; i++) 1970 smb_llist_constructor(&hash->buckets[i].b_list, elemsz, 1971 link_offset); 1972 return (hash); 1973 } 1974 1975 void 1976 smb_hash_destroy(smb_hash_t *hash) 1977 { 1978 int i; 1979 1980 for (i = 0; i < hash->num_buckets; i++) 1981 smb_llist_destructor(&hash->buckets[i].b_list); 1982 1983 kmem_free(hash->buckets, hash->num_buckets * sizeof (smb_bucket_t)); 1984 kmem_free(hash, sizeof (*hash)); 1985 } 1986