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