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