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-2023 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 const timestruc_t smb_nttime_m1 = { -1, -1 }; /* minus 1 */ 1119 const timestruc_t smb_nttime_m2 = { -1, -2 }; /* minus 2 */ 1120 1121 void 1122 smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time) 1123 { 1124 static const timestruc_t tzero = { 0, 0 }; 1125 uint32_t seconds; 1126 1127 ASSERT(unix_time); 1128 1129 /* 1130 * NT time values (0, -1, -2) get special treatment in SMB. 1131 * See notes above smb_node_setattr() for details. 1132 */ 1133 if (nt_time == 0) { 1134 *unix_time = tzero; 1135 return; 1136 } 1137 if ((int64_t)nt_time == -1) { 1138 *unix_time = smb_nttime_m1; 1139 return; 1140 } 1141 if ((int64_t)nt_time == -2) { 1142 *unix_time = smb_nttime_m2; 1143 return; 1144 } 1145 1146 /* 1147 * Can't represent times less than or equal NT_TIME_BIAS, 1148 * so convert them to the oldest date we can store. 1149 * Note that time zero is "special" being converted 1150 * both directions as 0:0 (unix-to-nt, nt-to-unix). 1151 */ 1152 if (nt_time <= NT_TIME_BIAS) { 1153 unix_time->tv_sec = 0; 1154 unix_time->tv_nsec = 100; 1155 return; 1156 } 1157 1158 nt_time -= NT_TIME_BIAS; 1159 seconds = nt_time / 10000000; 1160 unix_time->tv_sec = seconds; 1161 unix_time->tv_nsec = (nt_time % 10000000) * 100; 1162 } 1163 1164 /* 1165 * smb_time_gmt_to_local, smb_time_local_to_gmt 1166 * 1167 * Apply the gmt offset to convert between local time and gmt 1168 */ 1169 int32_t 1170 smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt) 1171 { 1172 if ((gmt == 0) || (gmt == -1)) 1173 return (0); 1174 1175 return (gmt - sr->sr_gmtoff); 1176 } 1177 1178 int32_t 1179 smb_time_local_to_gmt(smb_request_t *sr, int32_t local) 1180 { 1181 if ((local == 0) || (local == -1)) 1182 return (0); 1183 1184 return (local + sr->sr_gmtoff); 1185 } 1186 1187 1188 /* 1189 * smb_time_dos_to_unix 1190 * 1191 * Convert SMB_DATE & SMB_TIME values to a unix timestamp. 1192 * 1193 * A date/time field of 0 means that that server file system 1194 * assigned value need not be changed. The behaviour when the 1195 * date/time field is set to -1 is not documented but is 1196 * generally treated like 0. 1197 * If date or time is 0 or -1 the unix time is returned as 0 1198 * so that the caller can identify and handle this special case. 1199 */ 1200 int32_t 1201 smb_time_dos_to_unix(int16_t date, int16_t time) 1202 { 1203 struct tm atm; 1204 1205 if (((date == 0) || (time == 0)) || 1206 ((date == -1) || (time == -1))) { 1207 return (0); 1208 } 1209 1210 atm.tm_year = ((date >> 9) & 0x3F) + 80; 1211 atm.tm_mon = ((date >> 5) & 0x0F) - 1; 1212 atm.tm_mday = ((date >> 0) & 0x1F); 1213 atm.tm_hour = ((time >> 11) & 0x1F); 1214 atm.tm_min = ((time >> 5) & 0x3F); 1215 atm.tm_sec = ((time >> 0) & 0x1F) << 1; 1216 1217 return (smb_timegm(&atm)); 1218 } 1219 1220 void 1221 smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p) 1222 { 1223 struct tm atm; 1224 int i; 1225 time_t tmp_time; 1226 1227 if (ux_time == 0) { 1228 *date_p = 0; 1229 *time_p = 0; 1230 return; 1231 } 1232 1233 tmp_time = (time_t)ux_time; 1234 (void) smb_gmtime_r(&tmp_time, &atm); 1235 1236 if (date_p) { 1237 i = 0; 1238 i += atm.tm_year - 80; 1239 i <<= 4; 1240 i += atm.tm_mon + 1; 1241 i <<= 5; 1242 i += atm.tm_mday; 1243 1244 *date_p = (short)i; 1245 } 1246 if (time_p) { 1247 i = 0; 1248 i += atm.tm_hour; 1249 i <<= 6; 1250 i += atm.tm_min; 1251 i <<= 5; 1252 i += atm.tm_sec >> 1; 1253 1254 *time_p = (short)i; 1255 } 1256 } 1257 1258 1259 /* 1260 * smb_gmtime_r 1261 * 1262 * Thread-safe version of smb_gmtime. Returns a null pointer if either 1263 * input parameter is a null pointer. Otherwise returns a pointer 1264 * to result. 1265 * 1266 * Day of the week calculation: the Epoch was a thursday. 1267 * 1268 * There are no timezone corrections so tm_isdst and tm_gmtoff are 1269 * always zero, and the zone is always WET. 1270 */ 1271 struct tm * 1272 smb_gmtime_r(time_t *clock, struct tm *result) 1273 { 1274 time_t tsec; 1275 int year; 1276 int month; 1277 int sec_per_month; 1278 1279 if (clock == 0 || result == 0) 1280 return (0); 1281 1282 bzero(result, sizeof (struct tm)); 1283 tsec = *clock; 1284 tsec -= tzh_leapcnt; 1285 1286 result->tm_wday = tsec / SECSPERDAY; 1287 result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK; 1288 1289 year = EPOCH_YEAR; 1290 while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) : 1291 (SECSPERDAY * DAYSPERNYEAR))) { 1292 if (isleap(year)) 1293 tsec -= SECSPERDAY * DAYSPERLYEAR; 1294 else 1295 tsec -= SECSPERDAY * DAYSPERNYEAR; 1296 1297 ++year; 1298 } 1299 1300 result->tm_year = year - TM_YEAR_BASE; 1301 result->tm_yday = tsec / SECSPERDAY; 1302 1303 for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) { 1304 sec_per_month = days_in_month[month] * SECSPERDAY; 1305 1306 if (month == TM_FEBRUARY && isleap(year)) 1307 sec_per_month += SECSPERDAY; 1308 1309 if (tsec < sec_per_month) 1310 break; 1311 1312 tsec -= sec_per_month; 1313 } 1314 1315 result->tm_mon = month; 1316 result->tm_mday = (tsec / SECSPERDAY) + 1; 1317 tsec %= SECSPERDAY; 1318 result->tm_sec = tsec % 60; 1319 tsec /= 60; 1320 result->tm_min = tsec % 60; 1321 tsec /= 60; 1322 result->tm_hour = (int)tsec; 1323 1324 return (result); 1325 } 1326 1327 1328 /* 1329 * smb_timegm 1330 * 1331 * Converts the broken-down time in tm to a time value, i.e. the number 1332 * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is 1333 * not a POSIX or ANSI function. Per the man page, the input values of 1334 * tm_wday and tm_yday are ignored and, as the input data is assumed to 1335 * represent GMT, we force tm_isdst and tm_gmtoff to 0. 1336 * 1337 * Before returning the clock time, we use smb_gmtime_r to set up tm_wday 1338 * and tm_yday, and bring the other fields within normal range. I don't 1339 * think this is really how it should be done but it's convenient for 1340 * now. 1341 */ 1342 time_t 1343 smb_timegm(struct tm *tm) 1344 { 1345 time_t tsec; 1346 int dd; 1347 int mm; 1348 int yy; 1349 int year; 1350 1351 if (tm == 0) 1352 return (-1); 1353 1354 year = tm->tm_year + TM_YEAR_BASE; 1355 tsec = tzh_leapcnt; 1356 1357 for (yy = EPOCH_YEAR; yy < year; ++yy) { 1358 if (isleap(yy)) 1359 tsec += SECSPERDAY * DAYSPERLYEAR; 1360 else 1361 tsec += SECSPERDAY * DAYSPERNYEAR; 1362 } 1363 1364 for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) { 1365 dd = days_in_month[mm] * SECSPERDAY; 1366 1367 if (mm == TM_FEBRUARY && isleap(year)) 1368 dd += SECSPERDAY; 1369 1370 tsec += dd; 1371 } 1372 1373 tsec += (tm->tm_mday - 1) * SECSPERDAY; 1374 tsec += tm->tm_sec; 1375 tsec += tm->tm_min * SECSPERMIN; 1376 tsec += tm->tm_hour * SECSPERHOUR; 1377 1378 tm->tm_isdst = 0; 1379 (void) smb_gmtime_r(&tsec, tm); 1380 return (tsec); 1381 } 1382 1383 /* 1384 * smb_pad_align 1385 * 1386 * Returns the number of bytes required to pad an offset to the 1387 * specified alignment. 1388 */ 1389 uint32_t 1390 smb_pad_align(uint32_t offset, uint32_t align) 1391 { 1392 uint32_t pad = offset % align; 1393 1394 if (pad != 0) 1395 pad = align - pad; 1396 1397 return (pad); 1398 } 1399 1400 /* 1401 * smb_panic 1402 * 1403 * Logs the file name, function name and line number passed in and panics the 1404 * system. 1405 */ 1406 void 1407 smb_panic(char *file, const char *func, int line) 1408 { 1409 cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line); 1410 } 1411 1412 /* 1413 * Creates an AVL tree and initializes the given smb_avl_t 1414 * structure using the passed args 1415 */ 1416 void 1417 smb_avl_create(smb_avl_t *avl, size_t size, size_t offset, 1418 const smb_avl_nops_t *ops) 1419 { 1420 ASSERT(avl); 1421 ASSERT(ops); 1422 1423 rw_init(&avl->avl_lock, NULL, RW_DEFAULT, NULL); 1424 mutex_init(&avl->avl_mutex, NULL, MUTEX_DEFAULT, NULL); 1425 1426 avl->avl_nops = ops; 1427 avl->avl_state = SMB_AVL_STATE_READY; 1428 avl->avl_refcnt = 0; 1429 (void) random_get_pseudo_bytes((uint8_t *)&avl->avl_sequence, 1430 sizeof (uint32_t)); 1431 1432 avl_create(&avl->avl_tree, ops->avln_cmp, size, offset); 1433 } 1434 1435 /* 1436 * Destroys the specified AVL tree. 1437 * It waits for all the in-flight operations to finish 1438 * before destroying the AVL. 1439 */ 1440 void 1441 smb_avl_destroy(smb_avl_t *avl) 1442 { 1443 void *cookie = NULL; 1444 void *node; 1445 1446 ASSERT(avl); 1447 1448 mutex_enter(&avl->avl_mutex); 1449 if (avl->avl_state != SMB_AVL_STATE_READY) { 1450 mutex_exit(&avl->avl_mutex); 1451 return; 1452 } 1453 1454 avl->avl_state = SMB_AVL_STATE_DESTROYING; 1455 1456 while (avl->avl_refcnt > 0) 1457 (void) cv_wait(&avl->avl_cv, &avl->avl_mutex); 1458 mutex_exit(&avl->avl_mutex); 1459 1460 rw_enter(&avl->avl_lock, RW_WRITER); 1461 while ((node = avl_destroy_nodes(&avl->avl_tree, &cookie)) != NULL) 1462 avl->avl_nops->avln_destroy(node); 1463 1464 avl_destroy(&avl->avl_tree); 1465 rw_exit(&avl->avl_lock); 1466 1467 rw_destroy(&avl->avl_lock); 1468 1469 mutex_destroy(&avl->avl_mutex); 1470 bzero(avl, sizeof (smb_avl_t)); 1471 } 1472 1473 /* 1474 * Adds the given item to the AVL if it's 1475 * not already there. 1476 * 1477 * Returns: 1478 * 1479 * ENOTACTIVE AVL is not in READY state 1480 * EEXIST The item is already in AVL 1481 */ 1482 int 1483 smb_avl_add(smb_avl_t *avl, void *item) 1484 { 1485 avl_index_t where; 1486 1487 ASSERT(avl); 1488 ASSERT(item); 1489 1490 if (!smb_avl_hold(avl)) 1491 return (ENOTACTIVE); 1492 1493 rw_enter(&avl->avl_lock, RW_WRITER); 1494 if (avl_find(&avl->avl_tree, item, &where) != NULL) { 1495 rw_exit(&avl->avl_lock); 1496 smb_avl_rele(avl); 1497 return (EEXIST); 1498 } 1499 1500 avl_insert(&avl->avl_tree, item, where); 1501 avl->avl_sequence++; 1502 rw_exit(&avl->avl_lock); 1503 1504 smb_avl_rele(avl); 1505 return (0); 1506 } 1507 1508 /* 1509 * Removes the given item from the AVL. 1510 * If no reference is left on the item 1511 * it will also be destroyed by calling the 1512 * registered destroy operation. 1513 */ 1514 void 1515 smb_avl_remove(smb_avl_t *avl, void *item) 1516 { 1517 avl_index_t where; 1518 void *rm_item; 1519 1520 ASSERT(avl); 1521 ASSERT(item); 1522 1523 if (!smb_avl_hold(avl)) 1524 return; 1525 1526 rw_enter(&avl->avl_lock, RW_WRITER); 1527 if ((rm_item = avl_find(&avl->avl_tree, item, &where)) == NULL) { 1528 rw_exit(&avl->avl_lock); 1529 smb_avl_rele(avl); 1530 return; 1531 } 1532 1533 avl_remove(&avl->avl_tree, rm_item); 1534 if (avl->avl_nops->avln_rele(rm_item)) 1535 avl->avl_nops->avln_destroy(rm_item); 1536 avl->avl_sequence++; 1537 rw_exit(&avl->avl_lock); 1538 1539 smb_avl_rele(avl); 1540 } 1541 1542 /* 1543 * Looks up the AVL for the given item. 1544 * If the item is found a hold on the object 1545 * is taken before the pointer to it is 1546 * returned to the caller. The caller MUST 1547 * always call smb_avl_release() after it's done 1548 * using the returned object to release the hold 1549 * taken on the object. 1550 */ 1551 void * 1552 smb_avl_lookup(smb_avl_t *avl, void *item) 1553 { 1554 void *node = NULL; 1555 1556 ASSERT(avl); 1557 ASSERT(item); 1558 1559 if (!smb_avl_hold(avl)) 1560 return (NULL); 1561 1562 rw_enter(&avl->avl_lock, RW_READER); 1563 node = avl_find(&avl->avl_tree, item, NULL); 1564 if (node != NULL) 1565 avl->avl_nops->avln_hold(node); 1566 rw_exit(&avl->avl_lock); 1567 1568 if (node == NULL) 1569 smb_avl_rele(avl); 1570 1571 return (node); 1572 } 1573 1574 /* 1575 * The hold on the given object is released. 1576 * This function MUST always be called after 1577 * smb_avl_lookup() and smb_avl_iterate() for 1578 * the returned object. 1579 * 1580 * If AVL is in DESTROYING state, the destroying 1581 * thread will be notified. 1582 */ 1583 void 1584 smb_avl_release(smb_avl_t *avl, void *item) 1585 { 1586 ASSERT(avl); 1587 ASSERT(item); 1588 1589 if (avl->avl_nops->avln_rele(item)) 1590 avl->avl_nops->avln_destroy(item); 1591 1592 smb_avl_rele(avl); 1593 } 1594 1595 /* 1596 * Initializes the given cursor for the AVL. 1597 * The cursor will be used to iterate through the AVL 1598 */ 1599 void 1600 smb_avl_iterinit(smb_avl_t *avl, smb_avl_cursor_t *cursor) 1601 { 1602 ASSERT(avl); 1603 ASSERT(cursor); 1604 1605 cursor->avlc_next = NULL; 1606 cursor->avlc_sequence = avl->avl_sequence; 1607 } 1608 1609 /* 1610 * Iterates through the AVL using the given cursor. 1611 * It always starts at the beginning and then returns 1612 * a pointer to the next object on each subsequent call. 1613 * 1614 * If a new object is added to or removed from the AVL 1615 * between two calls to this function, the iteration 1616 * will terminate prematurely. 1617 * 1618 * The caller MUST always call smb_avl_release() after it's 1619 * done using the returned object to release the hold taken 1620 * on the object. 1621 */ 1622 void * 1623 smb_avl_iterate(smb_avl_t *avl, smb_avl_cursor_t *cursor) 1624 { 1625 void *node; 1626 1627 ASSERT(avl); 1628 ASSERT(cursor); 1629 1630 if (!smb_avl_hold(avl)) 1631 return (NULL); 1632 1633 rw_enter(&avl->avl_lock, RW_READER); 1634 if (cursor->avlc_sequence != avl->avl_sequence) { 1635 rw_exit(&avl->avl_lock); 1636 smb_avl_rele(avl); 1637 return (NULL); 1638 } 1639 1640 if (cursor->avlc_next == NULL) 1641 node = avl_first(&avl->avl_tree); 1642 else 1643 node = AVL_NEXT(&avl->avl_tree, cursor->avlc_next); 1644 1645 if (node != NULL) 1646 avl->avl_nops->avln_hold(node); 1647 1648 cursor->avlc_next = node; 1649 rw_exit(&avl->avl_lock); 1650 1651 if (node == NULL) 1652 smb_avl_rele(avl); 1653 1654 return (node); 1655 } 1656 1657 /* 1658 * Increments the AVL reference count in order to 1659 * prevent the avl from being destroyed while it's 1660 * being accessed. 1661 */ 1662 static boolean_t 1663 smb_avl_hold(smb_avl_t *avl) 1664 { 1665 mutex_enter(&avl->avl_mutex); 1666 if (avl->avl_state != SMB_AVL_STATE_READY) { 1667 mutex_exit(&avl->avl_mutex); 1668 return (B_FALSE); 1669 } 1670 avl->avl_refcnt++; 1671 mutex_exit(&avl->avl_mutex); 1672 1673 return (B_TRUE); 1674 } 1675 1676 /* 1677 * Decrements the AVL reference count to release the 1678 * hold. If another thread is trying to destroy the 1679 * AVL and is waiting for the reference count to become 1680 * 0, it is signaled to wake up. 1681 */ 1682 static void 1683 smb_avl_rele(smb_avl_t *avl) 1684 { 1685 mutex_enter(&avl->avl_mutex); 1686 ASSERT(avl->avl_refcnt > 0); 1687 avl->avl_refcnt--; 1688 if (avl->avl_state == SMB_AVL_STATE_DESTROYING) 1689 cv_broadcast(&avl->avl_cv); 1690 mutex_exit(&avl->avl_mutex); 1691 } 1692 1693 /* 1694 * smb_latency_init 1695 */ 1696 void 1697 smb_latency_init(smb_latency_t *lat) 1698 { 1699 bzero(lat, sizeof (*lat)); 1700 mutex_init(&lat->ly_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); 1701 } 1702 1703 /* 1704 * smb_latency_destroy 1705 */ 1706 void 1707 smb_latency_destroy(smb_latency_t *lat) 1708 { 1709 mutex_destroy(&lat->ly_mutex); 1710 } 1711 1712 /* 1713 * smb_latency_add_sample 1714 * 1715 * Uses the new sample to calculate the new mean and standard deviation. The 1716 * sample must be a scaled value. 1717 */ 1718 void 1719 smb_latency_add_sample(smb_latency_t *lat, hrtime_t sample) 1720 { 1721 hrtime_t a_mean; 1722 hrtime_t d_mean; 1723 1724 mutex_enter(&lat->ly_mutex); 1725 lat->ly_a_nreq++; 1726 lat->ly_a_sum += sample; 1727 if (lat->ly_a_nreq != 0) { 1728 a_mean = lat->ly_a_sum / lat->ly_a_nreq; 1729 lat->ly_a_stddev = 1730 (sample - a_mean) * (sample - lat->ly_a_mean); 1731 lat->ly_a_mean = a_mean; 1732 } 1733 lat->ly_d_nreq++; 1734 lat->ly_d_sum += sample; 1735 if (lat->ly_d_nreq != 0) { 1736 d_mean = lat->ly_d_sum / lat->ly_d_nreq; 1737 lat->ly_d_stddev = 1738 (sample - d_mean) * (sample - lat->ly_d_mean); 1739 lat->ly_d_mean = d_mean; 1740 } 1741 mutex_exit(&lat->ly_mutex); 1742 } 1743 1744 /* 1745 * smb_srqueue_init 1746 */ 1747 void 1748 smb_srqueue_init(smb_srqueue_t *srq) 1749 { 1750 bzero(srq, sizeof (*srq)); 1751 mutex_init(&srq->srq_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); 1752 srq->srq_wlastupdate = srq->srq_rlastupdate = gethrtime_unscaled(); 1753 } 1754 1755 /* 1756 * smb_srqueue_destroy 1757 */ 1758 void 1759 smb_srqueue_destroy(smb_srqueue_t *srq) 1760 { 1761 mutex_destroy(&srq->srq_mutex); 1762 } 1763 1764 /* 1765 * smb_srqueue_waitq_enter 1766 */ 1767 void 1768 smb_srqueue_waitq_enter(smb_srqueue_t *srq) 1769 { 1770 hrtime_t new; 1771 hrtime_t delta; 1772 uint32_t wcnt; 1773 1774 mutex_enter(&srq->srq_mutex); 1775 new = gethrtime_unscaled(); 1776 delta = new - srq->srq_wlastupdate; 1777 srq->srq_wlastupdate = new; 1778 wcnt = srq->srq_wcnt++; 1779 if (wcnt != 0) { 1780 srq->srq_wlentime += delta * wcnt; 1781 srq->srq_wtime += delta; 1782 } 1783 mutex_exit(&srq->srq_mutex); 1784 } 1785 1786 /* 1787 * smb_srqueue_runq_exit 1788 */ 1789 void 1790 smb_srqueue_runq_exit(smb_srqueue_t *srq) 1791 { 1792 hrtime_t new; 1793 hrtime_t delta; 1794 uint32_t rcnt; 1795 1796 mutex_enter(&srq->srq_mutex); 1797 new = gethrtime_unscaled(); 1798 delta = new - srq->srq_rlastupdate; 1799 srq->srq_rlastupdate = new; 1800 rcnt = srq->srq_rcnt--; 1801 ASSERT(rcnt > 0); 1802 srq->srq_rlentime += delta * rcnt; 1803 srq->srq_rtime += delta; 1804 mutex_exit(&srq->srq_mutex); 1805 } 1806 1807 /* 1808 * smb_srqueue_waitq_to_runq 1809 */ 1810 void 1811 smb_srqueue_waitq_to_runq(smb_srqueue_t *srq) 1812 { 1813 hrtime_t new; 1814 hrtime_t delta; 1815 uint32_t wcnt; 1816 uint32_t rcnt; 1817 1818 mutex_enter(&srq->srq_mutex); 1819 new = gethrtime_unscaled(); 1820 delta = new - srq->srq_wlastupdate; 1821 srq->srq_wlastupdate = new; 1822 wcnt = srq->srq_wcnt--; 1823 ASSERT(wcnt > 0); 1824 srq->srq_wlentime += delta * wcnt; 1825 srq->srq_wtime += delta; 1826 delta = new - srq->srq_rlastupdate; 1827 srq->srq_rlastupdate = new; 1828 rcnt = srq->srq_rcnt++; 1829 if (rcnt != 0) { 1830 srq->srq_rlentime += delta * rcnt; 1831 srq->srq_rtime += delta; 1832 } 1833 mutex_exit(&srq->srq_mutex); 1834 } 1835 1836 /* 1837 * smb_srqueue_update 1838 * 1839 * Takes a snapshot of the smb_sr_stat_t structure passed in. 1840 */ 1841 void 1842 smb_srqueue_update(smb_srqueue_t *srq, smb_kstat_utilization_t *kd) 1843 { 1844 hrtime_t delta; 1845 hrtime_t snaptime; 1846 1847 mutex_enter(&srq->srq_mutex); 1848 snaptime = gethrtime_unscaled(); 1849 delta = snaptime - srq->srq_wlastupdate; 1850 srq->srq_wlastupdate = snaptime; 1851 if (srq->srq_wcnt != 0) { 1852 srq->srq_wlentime += delta * srq->srq_wcnt; 1853 srq->srq_wtime += delta; 1854 } 1855 delta = snaptime - srq->srq_rlastupdate; 1856 srq->srq_rlastupdate = snaptime; 1857 if (srq->srq_rcnt != 0) { 1858 srq->srq_rlentime += delta * srq->srq_rcnt; 1859 srq->srq_rtime += delta; 1860 } 1861 kd->ku_rlentime = srq->srq_rlentime; 1862 kd->ku_rtime = srq->srq_rtime; 1863 kd->ku_wlentime = srq->srq_wlentime; 1864 kd->ku_wtime = srq->srq_wtime; 1865 mutex_exit(&srq->srq_mutex); 1866 scalehrtime(&kd->ku_rlentime); 1867 scalehrtime(&kd->ku_rtime); 1868 scalehrtime(&kd->ku_wlentime); 1869 scalehrtime(&kd->ku_wtime); 1870 } 1871 1872 void 1873 smb_threshold_init(smb_cmd_threshold_t *ct, char *cmd, 1874 uint_t threshold, uint_t timeout) 1875 { 1876 bzero(ct, sizeof (smb_cmd_threshold_t)); 1877 mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 1878 cv_init(&ct->ct_cond, NULL, CV_DEFAULT, NULL); 1879 1880 ct->ct_cmd = cmd; 1881 ct->ct_threshold = threshold; 1882 ct->ct_timeout = timeout; 1883 } 1884 1885 void 1886 smb_threshold_fini(smb_cmd_threshold_t *ct) 1887 { 1888 cv_destroy(&ct->ct_cond); 1889 mutex_destroy(&ct->ct_mutex); 1890 } 1891 1892 /* 1893 * This threshold mechanism is used to limit the number of simultaneous 1894 * named pipe connections, concurrent authentication conversations, etc. 1895 * Requests that would take us over the threshold wait until either the 1896 * resources are available (return zero) or timeout (return error). 1897 */ 1898 int 1899 smb_threshold_enter(smb_cmd_threshold_t *ct) 1900 { 1901 clock_t time, rem; 1902 1903 time = MSEC_TO_TICK(ct->ct_timeout) + ddi_get_lbolt(); 1904 mutex_enter(&ct->ct_mutex); 1905 1906 while (ct->ct_threshold != 0 && 1907 ct->ct_threshold <= ct->ct_active_cnt) { 1908 ct->ct_blocked_cnt++; 1909 rem = cv_timedwait(&ct->ct_cond, &ct->ct_mutex, time); 1910 ct->ct_blocked_cnt--; 1911 if (rem < 0) { 1912 mutex_exit(&ct->ct_mutex); 1913 return (ETIME); 1914 } 1915 } 1916 if (ct->ct_threshold == 0) { 1917 mutex_exit(&ct->ct_mutex); 1918 return (ECANCELED); 1919 } 1920 1921 ASSERT3U(ct->ct_active_cnt, <, ct->ct_threshold); 1922 ct->ct_active_cnt++; 1923 1924 mutex_exit(&ct->ct_mutex); 1925 return (0); 1926 } 1927 1928 void 1929 smb_threshold_exit(smb_cmd_threshold_t *ct) 1930 { 1931 mutex_enter(&ct->ct_mutex); 1932 ASSERT3U(ct->ct_active_cnt, >, 0); 1933 ct->ct_active_cnt--; 1934 if (ct->ct_blocked_cnt) 1935 cv_signal(&ct->ct_cond); 1936 mutex_exit(&ct->ct_mutex); 1937 } 1938 1939 void 1940 smb_threshold_wake_all(smb_cmd_threshold_t *ct) 1941 { 1942 mutex_enter(&ct->ct_mutex); 1943 ct->ct_threshold = 0; 1944 cv_broadcast(&ct->ct_cond); 1945 mutex_exit(&ct->ct_mutex); 1946 } 1947 1948 /* taken from mod_hash_byptr */ 1949 uint_t 1950 smb_hash_uint64(smb_hash_t *hash, uint64_t val) 1951 { 1952 uint64_t k = val >> hash->rshift; 1953 uint_t idx = ((uint_t)k) & (hash->num_buckets - 1); 1954 1955 return (idx); 1956 } 1957 1958 boolean_t 1959 smb_is_pow2(size_t n) 1960 { 1961 return ((n & (n - 1)) == 0); 1962 } 1963 1964 smb_hash_t * 1965 smb_hash_create(size_t elemsz, size_t link_offset, 1966 uint32_t num_buckets) 1967 { 1968 smb_hash_t *hash = kmem_alloc(sizeof (*hash), KM_SLEEP); 1969 int i; 1970 1971 if (!smb_is_pow2(num_buckets)) 1972 num_buckets = 1 << highbit(num_buckets); 1973 1974 hash->rshift = highbit(elemsz); 1975 hash->num_buckets = num_buckets; 1976 hash->buckets = kmem_zalloc(num_buckets * sizeof (smb_bucket_t), 1977 KM_SLEEP); 1978 for (i = 0; i < num_buckets; i++) 1979 smb_llist_constructor(&hash->buckets[i].b_list, elemsz, 1980 link_offset); 1981 return (hash); 1982 } 1983 1984 void 1985 smb_hash_destroy(smb_hash_t *hash) 1986 { 1987 int i; 1988 1989 for (i = 0; i < hash->num_buckets; i++) 1990 smb_llist_destructor(&hash->buckets[i].b_list); 1991 1992 kmem_free(hash->buckets, hash->num_buckets * sizeof (smb_bucket_t)); 1993 kmem_free(hash, sizeof (*hash)); 1994 } 1995