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 2012 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/kidmap.h> 32 #include <sys/time.h> 33 #include <sys/spl.h> 34 #include <sys/cpuvar.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 46 static kmem_cache_t *smb_dtor_cache; 47 static boolean_t smb_llist_initialized = B_FALSE; 48 49 static boolean_t smb_thread_continue_timedwait_locked(smb_thread_t *, int); 50 51 static boolean_t smb_avl_hold(smb_avl_t *); 52 static void smb_avl_rele(smb_avl_t *); 53 54 time_t tzh_leapcnt = 0; 55 56 struct tm 57 *smb_gmtime_r(time_t *clock, struct tm *result); 58 59 time_t 60 smb_timegm(struct tm *tm); 61 62 struct tm { 63 int tm_sec; 64 int tm_min; 65 int tm_hour; 66 int tm_mday; 67 int tm_mon; 68 int tm_year; 69 int tm_wday; 70 int tm_yday; 71 int tm_isdst; 72 }; 73 74 static int days_in_month[] = { 75 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 76 }; 77 78 int 79 smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str) 80 { 81 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 82 return (smb_wcequiv_strlen(str)); 83 return (strlen(str)); 84 } 85 86 int 87 smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str) 88 { 89 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 90 return (smb_wcequiv_strlen(str) + 2); 91 return (strlen(str) + 1); 92 } 93 94 int 95 smb_ascii_or_unicode_null_len(struct smb_request *sr) 96 { 97 if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) 98 return (2); 99 return (1); 100 } 101 102 /* 103 * 104 * Convert old-style (DOS, LanMan) wildcard strings to NT style. 105 * This should ONLY happen to patterns that come from old clients, 106 * meaning dialect LANMAN2_1 etc. (dialect < NT_LM_0_12). 107 * 108 * ? is converted to > 109 * * is converted to < if it is followed by . 110 * . is converted to " if it is followed by ? or * or end of pattern 111 * 112 * Note: modifies pattern in place. 113 */ 114 void 115 smb_convert_wildcards(char *pattern) 116 { 117 char *p; 118 119 for (p = pattern; *p != '\0'; p++) { 120 switch (*p) { 121 case '?': 122 *p = '>'; 123 break; 124 case '*': 125 if (p[1] == '.') 126 *p = '<'; 127 break; 128 case '.': 129 if (p[1] == '?' || p[1] == '*' || p[1] == '\0') 130 *p = '\"'; 131 break; 132 } 133 } 134 } 135 136 /* 137 * smb_sattr_check 138 * 139 * Check file attributes against a search attribute (sattr) mask. 140 * 141 * Normal files, which includes READONLY and ARCHIVE, always pass 142 * this check. If the DIRECTORY, HIDDEN or SYSTEM special attributes 143 * are set then they must appear in the search mask. The special 144 * attributes are inclusive, i.e. all special attributes that appear 145 * in sattr must also appear in the file attributes for the check to 146 * pass. 147 * 148 * The following examples show how this works: 149 * 150 * fileA: READONLY 151 * fileB: 0 (no attributes = normal file) 152 * fileC: READONLY, ARCHIVE 153 * fileD: HIDDEN 154 * fileE: READONLY, HIDDEN, SYSTEM 155 * dirA: DIRECTORY 156 * 157 * search attribute: 0 158 * Returns: fileA, fileB and fileC. 159 * search attribute: HIDDEN 160 * Returns: fileA, fileB, fileC and fileD. 161 * search attribute: SYSTEM 162 * Returns: fileA, fileB and fileC. 163 * search attribute: DIRECTORY 164 * Returns: fileA, fileB, fileC and dirA. 165 * search attribute: HIDDEN and SYSTEM 166 * Returns: fileA, fileB, fileC, fileD and fileE. 167 * 168 * Returns true if the file and sattr match; otherwise, returns false. 169 */ 170 boolean_t 171 smb_sattr_check(uint16_t dosattr, uint16_t sattr) 172 { 173 if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) && 174 !(sattr & FILE_ATTRIBUTE_DIRECTORY)) 175 return (B_FALSE); 176 177 if ((dosattr & FILE_ATTRIBUTE_HIDDEN) && 178 !(sattr & FILE_ATTRIBUTE_HIDDEN)) 179 return (B_FALSE); 180 181 if ((dosattr & FILE_ATTRIBUTE_SYSTEM) && 182 !(sattr & FILE_ATTRIBUTE_SYSTEM)) 183 return (B_FALSE); 184 185 return (B_TRUE); 186 } 187 188 int 189 microtime(timestruc_t *tvp) 190 { 191 tvp->tv_sec = gethrestime_sec(); 192 tvp->tv_nsec = 0; 193 return (0); 194 } 195 196 int32_t 197 clock_get_milli_uptime() 198 { 199 return (TICK_TO_MSEC(ddi_get_lbolt())); 200 } 201 202 int /*ARGSUSED*/ 203 smb_noop(void *p, size_t size, int foo) 204 { 205 return (0); 206 } 207 208 /* 209 * smb_idpool_increment 210 * 211 * This function increments the ID pool by doubling the current size. This 212 * function assumes the caller entered the mutex of the pool. 213 */ 214 static int 215 smb_idpool_increment( 216 smb_idpool_t *pool) 217 { 218 uint8_t *new_pool; 219 uint32_t new_size; 220 221 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 222 223 new_size = pool->id_size * 2; 224 if (new_size <= SMB_IDPOOL_MAX_SIZE) { 225 new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP); 226 if (new_pool) { 227 bzero(new_pool, new_size / 8); 228 bcopy(pool->id_pool, new_pool, pool->id_size / 8); 229 kmem_free(pool->id_pool, pool->id_size / 8); 230 pool->id_pool = new_pool; 231 pool->id_free_counter += new_size - pool->id_size; 232 pool->id_max_free_counter += new_size - pool->id_size; 233 pool->id_size = new_size; 234 pool->id_idx_msk = (new_size / 8) - 1; 235 if (new_size >= SMB_IDPOOL_MAX_SIZE) { 236 /* id -1 made unavailable */ 237 pool->id_pool[pool->id_idx_msk] = 0x80; 238 pool->id_free_counter--; 239 pool->id_max_free_counter--; 240 } 241 return (0); 242 } 243 } 244 return (-1); 245 } 246 247 /* 248 * smb_idpool_constructor 249 * 250 * This function initializes the pool structure provided. 251 */ 252 int 253 smb_idpool_constructor( 254 smb_idpool_t *pool) 255 { 256 257 ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC); 258 259 pool->id_size = SMB_IDPOOL_MIN_SIZE; 260 pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1; 261 pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1; 262 pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1; 263 pool->id_bit = 0x02; 264 pool->id_bit_idx = 1; 265 pool->id_idx = 0; 266 pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8), 267 KM_SLEEP); 268 bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8)); 269 /* -1 id made unavailable */ 270 pool->id_pool[0] = 0x01; /* id 0 made unavailable */ 271 mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL); 272 pool->id_magic = SMB_IDPOOL_MAGIC; 273 return (0); 274 } 275 276 /* 277 * smb_idpool_destructor 278 * 279 * This function tears down and frees the resources associated with the 280 * pool provided. 281 */ 282 void 283 smb_idpool_destructor( 284 smb_idpool_t *pool) 285 { 286 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 287 ASSERT(pool->id_free_counter == pool->id_max_free_counter); 288 pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC; 289 mutex_destroy(&pool->id_mutex); 290 kmem_free(pool->id_pool, (size_t)(pool->id_size / 8)); 291 } 292 293 /* 294 * smb_idpool_alloc 295 * 296 * This function allocates an ID from the pool provided. 297 */ 298 int 299 smb_idpool_alloc( 300 smb_idpool_t *pool, 301 uint16_t *id) 302 { 303 uint32_t i; 304 uint8_t bit; 305 uint8_t bit_idx; 306 uint8_t byte; 307 308 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 309 310 mutex_enter(&pool->id_mutex); 311 if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) { 312 mutex_exit(&pool->id_mutex); 313 return (-1); 314 } 315 316 i = pool->id_size; 317 while (i) { 318 bit = pool->id_bit; 319 bit_idx = pool->id_bit_idx; 320 byte = pool->id_pool[pool->id_idx]; 321 while (bit) { 322 if (byte & bit) { 323 bit = bit << 1; 324 bit_idx++; 325 continue; 326 } 327 pool->id_pool[pool->id_idx] |= bit; 328 *id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx); 329 pool->id_free_counter--; 330 pool->id_bit = bit; 331 pool->id_bit_idx = bit_idx; 332 mutex_exit(&pool->id_mutex); 333 return (0); 334 } 335 pool->id_bit = 1; 336 pool->id_bit_idx = 0; 337 pool->id_idx++; 338 pool->id_idx &= pool->id_idx_msk; 339 --i; 340 } 341 /* 342 * This section of code shouldn't be reached. If there are IDs 343 * available and none could be found there's a problem. 344 */ 345 ASSERT(0); 346 mutex_exit(&pool->id_mutex); 347 return (-1); 348 } 349 350 /* 351 * smb_idpool_free 352 * 353 * This function frees the ID provided. 354 */ 355 void 356 smb_idpool_free( 357 smb_idpool_t *pool, 358 uint16_t id) 359 { 360 ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC); 361 ASSERT(id != 0); 362 ASSERT(id != 0xFFFF); 363 364 mutex_enter(&pool->id_mutex); 365 if (pool->id_pool[id >> 3] & (1 << (id & 7))) { 366 pool->id_pool[id >> 3] &= ~(1 << (id & 7)); 367 pool->id_free_counter++; 368 ASSERT(pool->id_free_counter <= pool->id_max_free_counter); 369 mutex_exit(&pool->id_mutex); 370 return; 371 } 372 /* Freeing a free ID. */ 373 ASSERT(0); 374 mutex_exit(&pool->id_mutex); 375 } 376 377 /* 378 * Initialize the llist delete queue object cache. 379 */ 380 void 381 smb_llist_init(void) 382 { 383 if (smb_llist_initialized) 384 return; 385 386 smb_dtor_cache = kmem_cache_create("smb_dtor_cache", 387 sizeof (smb_dtor_t), 8, NULL, NULL, NULL, NULL, NULL, 0); 388 389 smb_llist_initialized = B_TRUE; 390 } 391 392 /* 393 * Destroy the llist delete queue object cache. 394 */ 395 void 396 smb_llist_fini(void) 397 { 398 if (!smb_llist_initialized) 399 return; 400 401 kmem_cache_destroy(smb_dtor_cache); 402 smb_llist_initialized = B_FALSE; 403 } 404 405 /* 406 * smb_llist_constructor 407 * 408 * This function initializes a locked list. 409 */ 410 void 411 smb_llist_constructor( 412 smb_llist_t *ll, 413 size_t size, 414 size_t offset) 415 { 416 rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL); 417 mutex_init(&ll->ll_mutex, NULL, MUTEX_DEFAULT, NULL); 418 list_create(&ll->ll_list, size, offset); 419 list_create(&ll->ll_deleteq, sizeof (smb_dtor_t), 420 offsetof(smb_dtor_t, dt_lnd)); 421 ll->ll_count = 0; 422 ll->ll_wrop = 0; 423 ll->ll_deleteq_count = 0; 424 ll->ll_flushing = B_FALSE; 425 } 426 427 /* 428 * Flush the delete queue and destroy a locked list. 429 */ 430 void 431 smb_llist_destructor( 432 smb_llist_t *ll) 433 { 434 smb_llist_flush(ll); 435 436 ASSERT(ll->ll_count == 0); 437 ASSERT(ll->ll_deleteq_count == 0); 438 439 rw_destroy(&ll->ll_lock); 440 list_destroy(&ll->ll_list); 441 list_destroy(&ll->ll_deleteq); 442 mutex_destroy(&ll->ll_mutex); 443 } 444 445 /* 446 * Post an object to the delete queue. The delete queue will be processed 447 * during list exit or list destruction. Objects are often posted for 448 * deletion during list iteration (while the list is locked) but that is 449 * not required, and an object can be posted at any time. 450 */ 451 void 452 smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc) 453 { 454 smb_dtor_t *dtor; 455 456 ASSERT((object != NULL) && (dtorproc != NULL)); 457 458 dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP); 459 bzero(dtor, sizeof (smb_dtor_t)); 460 dtor->dt_magic = SMB_DTOR_MAGIC; 461 dtor->dt_object = object; 462 dtor->dt_proc = dtorproc; 463 464 mutex_enter(&ll->ll_mutex); 465 list_insert_tail(&ll->ll_deleteq, dtor); 466 ++ll->ll_deleteq_count; 467 mutex_exit(&ll->ll_mutex); 468 } 469 470 /* 471 * Exit the list lock and process the delete queue. 472 */ 473 void 474 smb_llist_exit(smb_llist_t *ll) 475 { 476 rw_exit(&ll->ll_lock); 477 smb_llist_flush(ll); 478 } 479 480 /* 481 * Flush the list delete queue. The mutex is dropped across the destructor 482 * call in case this leads to additional objects being posted to the delete 483 * queue. 484 */ 485 void 486 smb_llist_flush(smb_llist_t *ll) 487 { 488 smb_dtor_t *dtor; 489 490 mutex_enter(&ll->ll_mutex); 491 if (ll->ll_flushing) { 492 mutex_exit(&ll->ll_mutex); 493 return; 494 } 495 ll->ll_flushing = B_TRUE; 496 497 dtor = list_head(&ll->ll_deleteq); 498 while (dtor != NULL) { 499 SMB_DTOR_VALID(dtor); 500 ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL)); 501 list_remove(&ll->ll_deleteq, dtor); 502 --ll->ll_deleteq_count; 503 mutex_exit(&ll->ll_mutex); 504 505 dtor->dt_proc(dtor->dt_object); 506 507 dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC; 508 kmem_cache_free(smb_dtor_cache, dtor); 509 mutex_enter(&ll->ll_mutex); 510 dtor = list_head(&ll->ll_deleteq); 511 } 512 ll->ll_flushing = B_FALSE; 513 514 mutex_exit(&ll->ll_mutex); 515 } 516 517 /* 518 * smb_llist_upgrade 519 * 520 * This function tries to upgrade the lock of the locked list. It assumes the 521 * locked has already been entered in RW_READER mode. It first tries using the 522 * Solaris function rw_tryupgrade(). If that call fails the lock is released 523 * and reentered in RW_WRITER mode. In that last case a window is opened during 524 * which the contents of the list may have changed. The return code indicates 525 * whether or not the list was modified when the lock was exited. 526 */ 527 int smb_llist_upgrade( 528 smb_llist_t *ll) 529 { 530 uint64_t wrop; 531 532 if (rw_tryupgrade(&ll->ll_lock) != 0) { 533 return (0); 534 } 535 wrop = ll->ll_wrop; 536 rw_exit(&ll->ll_lock); 537 rw_enter(&ll->ll_lock, RW_WRITER); 538 return (wrop != ll->ll_wrop); 539 } 540 541 /* 542 * smb_llist_insert_head 543 * 544 * This function inserts the object passed a the beginning of the list. This 545 * function assumes the lock of the list has already been entered. 546 */ 547 void 548 smb_llist_insert_head( 549 smb_llist_t *ll, 550 void *obj) 551 { 552 list_insert_head(&ll->ll_list, obj); 553 ++ll->ll_wrop; 554 ++ll->ll_count; 555 } 556 557 /* 558 * smb_llist_insert_tail 559 * 560 * This function appends to the object passed to the list. This function assumes 561 * the lock of the list has already been entered. 562 * 563 */ 564 void 565 smb_llist_insert_tail( 566 smb_llist_t *ll, 567 void *obj) 568 { 569 list_insert_tail(&ll->ll_list, obj); 570 ++ll->ll_wrop; 571 ++ll->ll_count; 572 } 573 574 /* 575 * smb_llist_remove 576 * 577 * This function removes the object passed from the list. This function assumes 578 * the lock of the list has already been entered. 579 */ 580 void 581 smb_llist_remove( 582 smb_llist_t *ll, 583 void *obj) 584 { 585 list_remove(&ll->ll_list, obj); 586 ++ll->ll_wrop; 587 --ll->ll_count; 588 } 589 590 /* 591 * smb_llist_get_count 592 * 593 * This function returns the number of elements in the specified list. 594 */ 595 uint32_t 596 smb_llist_get_count( 597 smb_llist_t *ll) 598 { 599 return (ll->ll_count); 600 } 601 602 /* 603 * smb_slist_constructor 604 * 605 * Synchronized list constructor. 606 */ 607 void 608 smb_slist_constructor( 609 smb_slist_t *sl, 610 size_t size, 611 size_t offset) 612 { 613 mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL); 614 cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL); 615 list_create(&sl->sl_list, size, offset); 616 sl->sl_count = 0; 617 sl->sl_waiting = B_FALSE; 618 } 619 620 /* 621 * smb_slist_destructor 622 * 623 * Synchronized list destructor. 624 */ 625 void 626 smb_slist_destructor( 627 smb_slist_t *sl) 628 { 629 VERIFY(sl->sl_count == 0); 630 631 mutex_destroy(&sl->sl_mutex); 632 cv_destroy(&sl->sl_cv); 633 list_destroy(&sl->sl_list); 634 } 635 636 /* 637 * smb_slist_insert_head 638 * 639 * This function inserts the object passed a the beginning of the list. 640 */ 641 void 642 smb_slist_insert_head( 643 smb_slist_t *sl, 644 void *obj) 645 { 646 mutex_enter(&sl->sl_mutex); 647 list_insert_head(&sl->sl_list, obj); 648 ++sl->sl_count; 649 mutex_exit(&sl->sl_mutex); 650 } 651 652 /* 653 * smb_slist_insert_tail 654 * 655 * This function appends the object passed to the list. 656 */ 657 void 658 smb_slist_insert_tail( 659 smb_slist_t *sl, 660 void *obj) 661 { 662 mutex_enter(&sl->sl_mutex); 663 list_insert_tail(&sl->sl_list, obj); 664 ++sl->sl_count; 665 mutex_exit(&sl->sl_mutex); 666 } 667 668 /* 669 * smb_llist_remove 670 * 671 * This function removes the object passed by the caller from the list. 672 */ 673 void 674 smb_slist_remove( 675 smb_slist_t *sl, 676 void *obj) 677 { 678 mutex_enter(&sl->sl_mutex); 679 list_remove(&sl->sl_list, obj); 680 if ((--sl->sl_count == 0) && (sl->sl_waiting)) { 681 sl->sl_waiting = B_FALSE; 682 cv_broadcast(&sl->sl_cv); 683 } 684 mutex_exit(&sl->sl_mutex); 685 } 686 687 /* 688 * smb_slist_move_tail 689 * 690 * This function transfers all the contents of the synchronized list to the 691 * list_t provided. It returns the number of objects transferred. 692 */ 693 uint32_t 694 smb_slist_move_tail( 695 list_t *lst, 696 smb_slist_t *sl) 697 { 698 uint32_t rv; 699 700 mutex_enter(&sl->sl_mutex); 701 rv = sl->sl_count; 702 if (sl->sl_count) { 703 list_move_tail(lst, &sl->sl_list); 704 sl->sl_count = 0; 705 if (sl->sl_waiting) { 706 sl->sl_waiting = B_FALSE; 707 cv_broadcast(&sl->sl_cv); 708 } 709 } 710 mutex_exit(&sl->sl_mutex); 711 return (rv); 712 } 713 714 /* 715 * smb_slist_obj_move 716 * 717 * This function moves an object from one list to the end of the other list. It 718 * assumes the mutex of each list has been entered. 719 */ 720 void 721 smb_slist_obj_move( 722 smb_slist_t *dst, 723 smb_slist_t *src, 724 void *obj) 725 { 726 ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset); 727 ASSERT(dst->sl_list.list_size == src->sl_list.list_size); 728 729 list_remove(&src->sl_list, obj); 730 list_insert_tail(&dst->sl_list, obj); 731 dst->sl_count++; 732 src->sl_count--; 733 if ((src->sl_count == 0) && (src->sl_waiting)) { 734 src->sl_waiting = B_FALSE; 735 cv_broadcast(&src->sl_cv); 736 } 737 } 738 739 /* 740 * smb_slist_wait_for_empty 741 * 742 * This function waits for a list to be emptied. 743 */ 744 void 745 smb_slist_wait_for_empty( 746 smb_slist_t *sl) 747 { 748 mutex_enter(&sl->sl_mutex); 749 while (sl->sl_count) { 750 sl->sl_waiting = B_TRUE; 751 cv_wait(&sl->sl_cv, &sl->sl_mutex); 752 } 753 mutex_exit(&sl->sl_mutex); 754 } 755 756 /* 757 * smb_slist_exit 758 * 759 * This function exits the muetx of the list and signal the condition variable 760 * if the list is empty. 761 */ 762 void 763 smb_slist_exit(smb_slist_t *sl) 764 { 765 if ((sl->sl_count == 0) && (sl->sl_waiting)) { 766 sl->sl_waiting = B_FALSE; 767 cv_broadcast(&sl->sl_cv); 768 } 769 mutex_exit(&sl->sl_mutex); 770 } 771 772 /* 773 * smb_thread_entry_point 774 * 775 * Common entry point for all the threads created through smb_thread_start. 776 * The state of the thread is set to "running" at the beginning and moved to 777 * "exiting" just before calling thread_exit(). The condition variable is 778 * also signaled. 779 */ 780 static void 781 smb_thread_entry_point( 782 smb_thread_t *thread) 783 { 784 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 785 mutex_enter(&thread->sth_mtx); 786 ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING); 787 thread->sth_th = curthread; 788 thread->sth_did = thread->sth_th->t_did; 789 790 if (!thread->sth_kill) { 791 thread->sth_state = SMB_THREAD_STATE_RUNNING; 792 cv_signal(&thread->sth_cv); 793 mutex_exit(&thread->sth_mtx); 794 thread->sth_ep(thread, thread->sth_ep_arg); 795 mutex_enter(&thread->sth_mtx); 796 } 797 thread->sth_th = NULL; 798 thread->sth_state = SMB_THREAD_STATE_EXITING; 799 cv_broadcast(&thread->sth_cv); 800 mutex_exit(&thread->sth_mtx); 801 thread_exit(); 802 } 803 804 /* 805 * smb_thread_init 806 */ 807 void 808 smb_thread_init( 809 smb_thread_t *thread, 810 char *name, 811 smb_thread_ep_t ep, 812 void *ep_arg) 813 { 814 ASSERT(thread->sth_magic != SMB_THREAD_MAGIC); 815 816 bzero(thread, sizeof (*thread)); 817 818 (void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name)); 819 thread->sth_ep = ep; 820 thread->sth_ep_arg = ep_arg; 821 thread->sth_state = SMB_THREAD_STATE_EXITED; 822 mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL); 823 cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL); 824 thread->sth_magic = SMB_THREAD_MAGIC; 825 } 826 827 /* 828 * smb_thread_destroy 829 */ 830 void 831 smb_thread_destroy( 832 smb_thread_t *thread) 833 { 834 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 835 ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED); 836 thread->sth_magic = 0; 837 mutex_destroy(&thread->sth_mtx); 838 cv_destroy(&thread->sth_cv); 839 } 840 841 /* 842 * smb_thread_start 843 * 844 * This function starts a thread with the parameters provided. It waits until 845 * the state of the thread has been moved to running. 846 */ 847 /*ARGSUSED*/ 848 int 849 smb_thread_start( 850 smb_thread_t *thread) 851 { 852 int rc = 0; 853 kthread_t *tmpthread; 854 855 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 856 857 mutex_enter(&thread->sth_mtx); 858 switch (thread->sth_state) { 859 case SMB_THREAD_STATE_EXITED: 860 thread->sth_state = SMB_THREAD_STATE_STARTING; 861 mutex_exit(&thread->sth_mtx); 862 tmpthread = thread_create(NULL, 0, smb_thread_entry_point, 863 thread, 0, &p0, TS_RUN, minclsyspri); 864 ASSERT(tmpthread != NULL); 865 mutex_enter(&thread->sth_mtx); 866 while (thread->sth_state == SMB_THREAD_STATE_STARTING) 867 cv_wait(&thread->sth_cv, &thread->sth_mtx); 868 if (thread->sth_state != SMB_THREAD_STATE_RUNNING) 869 rc = -1; 870 break; 871 default: 872 ASSERT(0); 873 rc = -1; 874 break; 875 } 876 mutex_exit(&thread->sth_mtx); 877 return (rc); 878 } 879 880 /* 881 * smb_thread_stop 882 * 883 * This function signals a thread to kill itself and waits until the "exiting" 884 * state has been reached. 885 */ 886 void 887 smb_thread_stop(smb_thread_t *thread) 888 { 889 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 890 891 mutex_enter(&thread->sth_mtx); 892 switch (thread->sth_state) { 893 case SMB_THREAD_STATE_RUNNING: 894 case SMB_THREAD_STATE_STARTING: 895 if (!thread->sth_kill) { 896 thread->sth_kill = B_TRUE; 897 cv_broadcast(&thread->sth_cv); 898 while (thread->sth_state != SMB_THREAD_STATE_EXITING) 899 cv_wait(&thread->sth_cv, &thread->sth_mtx); 900 mutex_exit(&thread->sth_mtx); 901 thread_join(thread->sth_did); 902 mutex_enter(&thread->sth_mtx); 903 thread->sth_state = SMB_THREAD_STATE_EXITED; 904 thread->sth_did = 0; 905 thread->sth_kill = B_FALSE; 906 cv_broadcast(&thread->sth_cv); 907 break; 908 } 909 /*FALLTHRU*/ 910 911 case SMB_THREAD_STATE_EXITING: 912 if (thread->sth_kill) { 913 while (thread->sth_state != SMB_THREAD_STATE_EXITED) 914 cv_wait(&thread->sth_cv, &thread->sth_mtx); 915 } else { 916 thread->sth_state = SMB_THREAD_STATE_EXITED; 917 thread->sth_did = 0; 918 } 919 break; 920 921 case SMB_THREAD_STATE_EXITED: 922 break; 923 924 default: 925 ASSERT(0); 926 break; 927 } 928 mutex_exit(&thread->sth_mtx); 929 } 930 931 /* 932 * smb_thread_signal 933 * 934 * This function signals a thread. 935 */ 936 void 937 smb_thread_signal(smb_thread_t *thread) 938 { 939 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 940 941 mutex_enter(&thread->sth_mtx); 942 switch (thread->sth_state) { 943 case SMB_THREAD_STATE_RUNNING: 944 cv_signal(&thread->sth_cv); 945 break; 946 947 default: 948 break; 949 } 950 mutex_exit(&thread->sth_mtx); 951 } 952 953 boolean_t 954 smb_thread_continue(smb_thread_t *thread) 955 { 956 boolean_t result; 957 958 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 959 960 mutex_enter(&thread->sth_mtx); 961 result = smb_thread_continue_timedwait_locked(thread, 0); 962 mutex_exit(&thread->sth_mtx); 963 964 return (result); 965 } 966 967 boolean_t 968 smb_thread_continue_nowait(smb_thread_t *thread) 969 { 970 boolean_t result; 971 972 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 973 974 mutex_enter(&thread->sth_mtx); 975 /* 976 * Setting ticks=-1 requests a non-blocking check. We will 977 * still block if the thread is in "suspend" state. 978 */ 979 result = smb_thread_continue_timedwait_locked(thread, -1); 980 mutex_exit(&thread->sth_mtx); 981 982 return (result); 983 } 984 985 boolean_t 986 smb_thread_continue_timedwait(smb_thread_t *thread, int seconds) 987 { 988 boolean_t result; 989 990 ASSERT(thread->sth_magic == SMB_THREAD_MAGIC); 991 992 mutex_enter(&thread->sth_mtx); 993 result = smb_thread_continue_timedwait_locked(thread, 994 SEC_TO_TICK(seconds)); 995 mutex_exit(&thread->sth_mtx); 996 997 return (result); 998 } 999 1000 /* 1001 * smb_thread_continue_timedwait_locked 1002 * 1003 * Internal only. Ticks==-1 means don't block, Ticks == 0 means wait 1004 * indefinitely 1005 */ 1006 static boolean_t 1007 smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks) 1008 { 1009 boolean_t result; 1010 1011 /* -1 means don't block */ 1012 if (ticks != -1 && !thread->sth_kill) { 1013 if (ticks == 0) { 1014 cv_wait(&thread->sth_cv, &thread->sth_mtx); 1015 } else { 1016 (void) cv_reltimedwait(&thread->sth_cv, 1017 &thread->sth_mtx, (clock_t)ticks, TR_CLOCK_TICK); 1018 } 1019 } 1020 result = (thread->sth_kill == 0); 1021 1022 return (result); 1023 } 1024 1025 /* 1026 * smb_rwx_init 1027 */ 1028 void 1029 smb_rwx_init( 1030 smb_rwx_t *rwx) 1031 { 1032 bzero(rwx, sizeof (smb_rwx_t)); 1033 cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL); 1034 mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL); 1035 rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL); 1036 } 1037 1038 /* 1039 * smb_rwx_destroy 1040 */ 1041 void 1042 smb_rwx_destroy( 1043 smb_rwx_t *rwx) 1044 { 1045 mutex_destroy(&rwx->rwx_mutex); 1046 cv_destroy(&rwx->rwx_cv); 1047 rw_destroy(&rwx->rwx_lock); 1048 } 1049 1050 /* 1051 * smb_rwx_rwexit 1052 */ 1053 void 1054 smb_rwx_rwexit( 1055 smb_rwx_t *rwx) 1056 { 1057 if (rw_write_held(&rwx->rwx_lock)) { 1058 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1059 mutex_enter(&rwx->rwx_mutex); 1060 if (rwx->rwx_waiting) { 1061 rwx->rwx_waiting = B_FALSE; 1062 cv_broadcast(&rwx->rwx_cv); 1063 } 1064 mutex_exit(&rwx->rwx_mutex); 1065 } 1066 rw_exit(&rwx->rwx_lock); 1067 } 1068 1069 /* 1070 * smb_rwx_rwupgrade 1071 */ 1072 krw_t 1073 smb_rwx_rwupgrade( 1074 smb_rwx_t *rwx) 1075 { 1076 if (rw_write_held(&rwx->rwx_lock)) { 1077 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1078 return (RW_WRITER); 1079 } 1080 if (!rw_tryupgrade(&rwx->rwx_lock)) { 1081 rw_exit(&rwx->rwx_lock); 1082 rw_enter(&rwx->rwx_lock, RW_WRITER); 1083 } 1084 return (RW_READER); 1085 } 1086 1087 /* 1088 * smb_rwx_rwrestore 1089 */ 1090 void 1091 smb_rwx_rwdowngrade( 1092 smb_rwx_t *rwx, 1093 krw_t mode) 1094 { 1095 ASSERT(rw_write_held(&rwx->rwx_lock)); 1096 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1097 1098 if (mode == RW_WRITER) { 1099 return; 1100 } 1101 ASSERT(mode == RW_READER); 1102 mutex_enter(&rwx->rwx_mutex); 1103 if (rwx->rwx_waiting) { 1104 rwx->rwx_waiting = B_FALSE; 1105 cv_broadcast(&rwx->rwx_cv); 1106 } 1107 mutex_exit(&rwx->rwx_mutex); 1108 rw_downgrade(&rwx->rwx_lock); 1109 } 1110 1111 /* 1112 * smb_rwx_wait 1113 * 1114 * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER 1115 * mode. It will: 1116 * 1117 * 1) release the lock and save its current mode. 1118 * 2) wait until the condition variable is signaled. This can happen for 1119 * 2 reasons: When a writer releases the lock or when the time out (if 1120 * provided) expires. 1121 * 3) re-acquire the lock in the mode saved in (1). 1122 */ 1123 int 1124 smb_rwx_rwwait( 1125 smb_rwx_t *rwx, 1126 clock_t timeout) 1127 { 1128 int rc; 1129 krw_t mode; 1130 1131 mutex_enter(&rwx->rwx_mutex); 1132 rwx->rwx_waiting = B_TRUE; 1133 mutex_exit(&rwx->rwx_mutex); 1134 1135 if (rw_write_held(&rwx->rwx_lock)) { 1136 ASSERT(rw_owner(&rwx->rwx_lock) == curthread); 1137 mode = RW_WRITER; 1138 } else { 1139 ASSERT(rw_read_held(&rwx->rwx_lock)); 1140 mode = RW_READER; 1141 } 1142 rw_exit(&rwx->rwx_lock); 1143 1144 mutex_enter(&rwx->rwx_mutex); 1145 if (rwx->rwx_waiting) { 1146 if (timeout == -1) { 1147 rc = 1; 1148 cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex); 1149 } else { 1150 rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex, 1151 timeout, TR_CLOCK_TICK); 1152 } 1153 } 1154 mutex_exit(&rwx->rwx_mutex); 1155 1156 rw_enter(&rwx->rwx_lock, mode); 1157 return (rc); 1158 } 1159 1160 /* 1161 * SMB ID mapping 1162 * 1163 * Solaris ID mapping service (aka Winchester) works with domain SIDs 1164 * and RIDs where domain SIDs are in string format. CIFS service works 1165 * with binary SIDs understandable by CIFS clients. A layer of SMB ID 1166 * mapping functions are implemeted to hide the SID conversion details 1167 * and also hide the handling of array of batch mapping requests. 1168 * 1169 * IMPORTANT NOTE The Winchester API requires a zone. Because CIFS server 1170 * currently only runs in the global zone the global zone is specified. 1171 * This needs to be fixed when the CIFS server supports zones. 1172 */ 1173 1174 static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib); 1175 1176 /* 1177 * smb_idmap_getid 1178 * 1179 * Maps the given Windows SID to a Solaris ID using the 1180 * simple mapping API. 1181 */ 1182 idmap_stat 1183 smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype) 1184 { 1185 smb_idmap_t sim; 1186 char sidstr[SMB_SID_STRSZ]; 1187 1188 smb_sid_tostr(sid, sidstr); 1189 if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0) 1190 return (IDMAP_ERR_SID); 1191 sim.sim_domsid = sidstr; 1192 sim.sim_id = id; 1193 1194 switch (*idtype) { 1195 case SMB_IDMAP_USER: 1196 sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid, 1197 sim.sim_rid, sim.sim_id); 1198 break; 1199 1200 case SMB_IDMAP_GROUP: 1201 sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid, 1202 sim.sim_rid, sim.sim_id); 1203 break; 1204 1205 case SMB_IDMAP_UNKNOWN: 1206 sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid, 1207 sim.sim_rid, sim.sim_id, &sim.sim_idtype); 1208 break; 1209 1210 default: 1211 ASSERT(0); 1212 return (IDMAP_ERR_ARG); 1213 } 1214 1215 *idtype = sim.sim_idtype; 1216 1217 return (sim.sim_stat); 1218 } 1219 1220 /* 1221 * smb_idmap_getsid 1222 * 1223 * Maps the given Solaris ID to a Windows SID using the 1224 * simple mapping API. 1225 */ 1226 idmap_stat 1227 smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid) 1228 { 1229 smb_idmap_t sim; 1230 1231 switch (idtype) { 1232 case SMB_IDMAP_USER: 1233 sim.sim_stat = kidmap_getsidbyuid(global_zone, id, 1234 (const char **)&sim.sim_domsid, &sim.sim_rid); 1235 break; 1236 1237 case SMB_IDMAP_GROUP: 1238 sim.sim_stat = kidmap_getsidbygid(global_zone, id, 1239 (const char **)&sim.sim_domsid, &sim.sim_rid); 1240 break; 1241 1242 case SMB_IDMAP_EVERYONE: 1243 /* Everyone S-1-1-0 */ 1244 sim.sim_domsid = "S-1-1"; 1245 sim.sim_rid = 0; 1246 sim.sim_stat = IDMAP_SUCCESS; 1247 break; 1248 1249 default: 1250 ASSERT(0); 1251 return (IDMAP_ERR_ARG); 1252 } 1253 1254 if (sim.sim_stat != IDMAP_SUCCESS) 1255 return (sim.sim_stat); 1256 1257 if (sim.sim_domsid == NULL) 1258 return (IDMAP_ERR_NOMAPPING); 1259 1260 sim.sim_sid = smb_sid_fromstr(sim.sim_domsid); 1261 if (sim.sim_sid == NULL) 1262 return (IDMAP_ERR_INTERNAL); 1263 1264 *sid = smb_sid_splice(sim.sim_sid, sim.sim_rid); 1265 smb_sid_free(sim.sim_sid); 1266 if (*sid == NULL) 1267 sim.sim_stat = IDMAP_ERR_INTERNAL; 1268 1269 return (sim.sim_stat); 1270 } 1271 1272 /* 1273 * smb_idmap_batch_create 1274 * 1275 * Creates and initializes the context for batch ID mapping. 1276 */ 1277 idmap_stat 1278 smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags) 1279 { 1280 ASSERT(sib); 1281 1282 bzero(sib, sizeof (smb_idmap_batch_t)); 1283 1284 sib->sib_idmaph = kidmap_get_create(global_zone); 1285 1286 sib->sib_flags = flags; 1287 sib->sib_nmap = nmap; 1288 sib->sib_size = nmap * sizeof (smb_idmap_t); 1289 sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP); 1290 1291 return (IDMAP_SUCCESS); 1292 } 1293 1294 /* 1295 * smb_idmap_batch_destroy 1296 * 1297 * Frees the batch ID mapping context. 1298 * If ID mapping is Solaris -> Windows it frees memories 1299 * allocated for binary SIDs. 1300 */ 1301 void 1302 smb_idmap_batch_destroy(smb_idmap_batch_t *sib) 1303 { 1304 char *domsid; 1305 int i; 1306 1307 ASSERT(sib); 1308 ASSERT(sib->sib_maps); 1309 1310 if (sib->sib_idmaph) 1311 kidmap_get_destroy(sib->sib_idmaph); 1312 1313 if (sib->sib_flags & SMB_IDMAP_ID2SID) { 1314 /* 1315 * SIDs are allocated only when mapping 1316 * UID/GID to SIDs 1317 */ 1318 for (i = 0; i < sib->sib_nmap; i++) 1319 smb_sid_free(sib->sib_maps[i].sim_sid); 1320 } else if (sib->sib_flags & SMB_IDMAP_SID2ID) { 1321 /* 1322 * SID prefixes are allocated only when mapping 1323 * SIDs to UID/GID 1324 */ 1325 for (i = 0; i < sib->sib_nmap; i++) { 1326 domsid = sib->sib_maps[i].sim_domsid; 1327 if (domsid) 1328 smb_mem_free(domsid); 1329 } 1330 } 1331 1332 if (sib->sib_size && sib->sib_maps) 1333 kmem_free(sib->sib_maps, sib->sib_size); 1334 } 1335 1336 /* 1337 * smb_idmap_batch_getid 1338 * 1339 * Queue a request to map the given SID to a UID or GID. 1340 * 1341 * sim->sim_id should point to variable that's supposed to 1342 * hold the returned UID/GID. This needs to be setup by caller 1343 * of this function. 1344 * 1345 * If requested ID type is known, it's passed as 'idtype', 1346 * if it's unknown it'll be returned in sim->sim_idtype. 1347 */ 1348 idmap_stat 1349 smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 1350 smb_sid_t *sid, int idtype) 1351 { 1352 char strsid[SMB_SID_STRSZ]; 1353 idmap_stat idm_stat; 1354 1355 ASSERT(idmaph); 1356 ASSERT(sim); 1357 ASSERT(sid); 1358 1359 smb_sid_tostr(sid, strsid); 1360 if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0) 1361 return (IDMAP_ERR_SID); 1362 sim->sim_domsid = smb_mem_strdup(strsid); 1363 1364 switch (idtype) { 1365 case SMB_IDMAP_USER: 1366 idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid, 1367 sim->sim_rid, sim->sim_id, &sim->sim_stat); 1368 break; 1369 1370 case SMB_IDMAP_GROUP: 1371 idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid, 1372 sim->sim_rid, sim->sim_id, &sim->sim_stat); 1373 break; 1374 1375 case SMB_IDMAP_UNKNOWN: 1376 idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid, 1377 sim->sim_rid, sim->sim_id, &sim->sim_idtype, 1378 &sim->sim_stat); 1379 break; 1380 1381 default: 1382 ASSERT(0); 1383 return (IDMAP_ERR_ARG); 1384 } 1385 1386 return (idm_stat); 1387 } 1388 1389 /* 1390 * smb_idmap_batch_getsid 1391 * 1392 * Queue a request to map the given UID/GID to a SID. 1393 * 1394 * sim->sim_domsid and sim->sim_rid will contain the mapping 1395 * result upon successful process of the batched request. 1396 */ 1397 idmap_stat 1398 smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim, 1399 uid_t id, int idtype) 1400 { 1401 idmap_stat idm_stat; 1402 1403 switch (idtype) { 1404 case SMB_IDMAP_USER: 1405 idm_stat = kidmap_batch_getsidbyuid(idmaph, id, 1406 (const char **)&sim->sim_domsid, &sim->sim_rid, 1407 &sim->sim_stat); 1408 break; 1409 1410 case SMB_IDMAP_GROUP: 1411 idm_stat = kidmap_batch_getsidbygid(idmaph, id, 1412 (const char **)&sim->sim_domsid, &sim->sim_rid, 1413 &sim->sim_stat); 1414 break; 1415 1416 case SMB_IDMAP_OWNERAT: 1417 /* Current Owner S-1-5-32-766 */ 1418 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR; 1419 sim->sim_rid = SECURITY_CURRENT_OWNER_RID; 1420 sim->sim_stat = IDMAP_SUCCESS; 1421 idm_stat = IDMAP_SUCCESS; 1422 break; 1423 1424 case SMB_IDMAP_GROUPAT: 1425 /* Current Group S-1-5-32-767 */ 1426 sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR; 1427 sim->sim_rid = SECURITY_CURRENT_GROUP_RID; 1428 sim->sim_stat = IDMAP_SUCCESS; 1429 idm_stat = IDMAP_SUCCESS; 1430 break; 1431 1432 case SMB_IDMAP_EVERYONE: 1433 /* Everyone S-1-1-0 */ 1434 sim->sim_domsid = NT_WORLD_AUTH_SIDSTR; 1435 sim->sim_rid = 0; 1436 sim->sim_stat = IDMAP_SUCCESS; 1437 idm_stat = IDMAP_SUCCESS; 1438 break; 1439 1440 default: 1441 ASSERT(0); 1442 return (IDMAP_ERR_ARG); 1443 } 1444 1445 return (idm_stat); 1446 } 1447 1448 /* 1449 * smb_idmap_batch_binsid 1450 * 1451 * Convert sidrids to binary sids 1452 * 1453 * Returns 0 if successful and non-zero upon failure. 1454 */ 1455 static int 1456 smb_idmap_batch_binsid(smb_idmap_batch_t *sib) 1457 { 1458 smb_sid_t *sid; 1459 smb_idmap_t *sim; 1460 int i; 1461 1462 if (sib->sib_flags & SMB_IDMAP_SID2ID) 1463 /* This operation is not required */ 1464 return (0); 1465 1466 sim = sib->sib_maps; 1467 for (i = 0; i < sib->sib_nmap; sim++, i++) { 1468 ASSERT(sim->sim_domsid); 1469 if (sim->sim_domsid == NULL) 1470 return (1); 1471 1472 if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL) 1473 return (1); 1474 1475 sim->sim_sid = smb_sid_splice(sid, sim->sim_rid); 1476 smb_sid_free(sid); 1477 } 1478 1479 return (0); 1480 } 1481 1482 /* 1483 * smb_idmap_batch_getmappings 1484 * 1485 * trigger ID mapping service to get the mappings for queued 1486 * requests. 1487 * 1488 * Checks the result of all the queued requests. 1489 * If this is a Solaris -> Windows mapping it generates 1490 * binary SIDs from returned (domsid, rid) pairs. 1491 */ 1492 idmap_stat 1493 smb_idmap_batch_getmappings(smb_idmap_batch_t *sib) 1494 { 1495 idmap_stat idm_stat = IDMAP_SUCCESS; 1496 int i; 1497 1498 idm_stat = kidmap_get_mappings(sib->sib_idmaph); 1499 if (idm_stat != IDMAP_SUCCESS) 1500 return (idm_stat); 1501 1502 /* 1503 * Check the status for all the queued requests 1504 */ 1505 for (i = 0; i < sib->sib_nmap; i++) { 1506 if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS) 1507 return (sib->sib_maps[i].sim_stat); 1508 } 1509 1510 if (smb_idmap_batch_binsid(sib) != 0) 1511 idm_stat = IDMAP_ERR_OTHER; 1512 1513 return (idm_stat); 1514 } 1515 1516 uint64_t 1517 smb_time_unix_to_nt(timestruc_t *unix_time) 1518 { 1519 uint64_t nt_time; 1520 1521 if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0)) 1522 return (0); 1523 1524 nt_time = unix_time->tv_sec; 1525 nt_time *= 10000000; /* seconds to 100ns */ 1526 nt_time += unix_time->tv_nsec / 100; 1527 return (nt_time + NT_TIME_BIAS); 1528 } 1529 1530 void 1531 smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time) 1532 { 1533 uint32_t seconds; 1534 1535 ASSERT(unix_time); 1536 1537 if ((nt_time == 0) || (nt_time == -1)) { 1538 unix_time->tv_sec = 0; 1539 unix_time->tv_nsec = 0; 1540 return; 1541 } 1542 1543 nt_time -= NT_TIME_BIAS; 1544 seconds = nt_time / 10000000; 1545 unix_time->tv_sec = seconds; 1546 unix_time->tv_nsec = (nt_time % 10000000) * 100; 1547 } 1548 1549 /* 1550 * smb_time_gmt_to_local, smb_time_local_to_gmt 1551 * 1552 * Apply the gmt offset to convert between local time and gmt 1553 */ 1554 int32_t 1555 smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt) 1556 { 1557 if ((gmt == 0) || (gmt == -1)) 1558 return (0); 1559 1560 return (gmt - sr->sr_gmtoff); 1561 } 1562 1563 int32_t 1564 smb_time_local_to_gmt(smb_request_t *sr, int32_t local) 1565 { 1566 if ((local == 0) || (local == -1)) 1567 return (0); 1568 1569 return (local + sr->sr_gmtoff); 1570 } 1571 1572 1573 /* 1574 * smb_time_dos_to_unix 1575 * 1576 * Convert SMB_DATE & SMB_TIME values to a unix timestamp. 1577 * 1578 * A date/time field of 0 means that that server file system 1579 * assigned value need not be changed. The behaviour when the 1580 * date/time field is set to -1 is not documented but is 1581 * generally treated like 0. 1582 * If date or time is 0 or -1 the unix time is returned as 0 1583 * so that the caller can identify and handle this special case. 1584 */ 1585 int32_t 1586 smb_time_dos_to_unix(int16_t date, int16_t time) 1587 { 1588 struct tm atm; 1589 1590 if (((date == 0) || (time == 0)) || 1591 ((date == -1) || (time == -1))) { 1592 return (0); 1593 } 1594 1595 atm.tm_year = ((date >> 9) & 0x3F) + 80; 1596 atm.tm_mon = ((date >> 5) & 0x0F) - 1; 1597 atm.tm_mday = ((date >> 0) & 0x1F); 1598 atm.tm_hour = ((time >> 11) & 0x1F); 1599 atm.tm_min = ((time >> 5) & 0x3F); 1600 atm.tm_sec = ((time >> 0) & 0x1F) << 1; 1601 1602 return (smb_timegm(&atm)); 1603 } 1604 1605 void 1606 smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p) 1607 { 1608 struct tm atm; 1609 int i; 1610 time_t tmp_time; 1611 1612 if (ux_time == 0) { 1613 *date_p = 0; 1614 *time_p = 0; 1615 return; 1616 } 1617 1618 tmp_time = (time_t)ux_time; 1619 (void) smb_gmtime_r(&tmp_time, &atm); 1620 1621 if (date_p) { 1622 i = 0; 1623 i += atm.tm_year - 80; 1624 i <<= 4; 1625 i += atm.tm_mon + 1; 1626 i <<= 5; 1627 i += atm.tm_mday; 1628 1629 *date_p = (short)i; 1630 } 1631 if (time_p) { 1632 i = 0; 1633 i += atm.tm_hour; 1634 i <<= 6; 1635 i += atm.tm_min; 1636 i <<= 5; 1637 i += atm.tm_sec >> 1; 1638 1639 *time_p = (short)i; 1640 } 1641 } 1642 1643 1644 /* 1645 * smb_gmtime_r 1646 * 1647 * Thread-safe version of smb_gmtime. Returns a null pointer if either 1648 * input parameter is a null pointer. Otherwise returns a pointer 1649 * to result. 1650 * 1651 * Day of the week calculation: the Epoch was a thursday. 1652 * 1653 * There are no timezone corrections so tm_isdst and tm_gmtoff are 1654 * always zero, and the zone is always WET. 1655 */ 1656 struct tm * 1657 smb_gmtime_r(time_t *clock, struct tm *result) 1658 { 1659 time_t tsec; 1660 int year; 1661 int month; 1662 int sec_per_month; 1663 1664 if (clock == 0 || result == 0) 1665 return (0); 1666 1667 bzero(result, sizeof (struct tm)); 1668 tsec = *clock; 1669 tsec -= tzh_leapcnt; 1670 1671 result->tm_wday = tsec / SECSPERDAY; 1672 result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK; 1673 1674 year = EPOCH_YEAR; 1675 while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) : 1676 (SECSPERDAY * DAYSPERNYEAR))) { 1677 if (isleap(year)) 1678 tsec -= SECSPERDAY * DAYSPERLYEAR; 1679 else 1680 tsec -= SECSPERDAY * DAYSPERNYEAR; 1681 1682 ++year; 1683 } 1684 1685 result->tm_year = year - TM_YEAR_BASE; 1686 result->tm_yday = tsec / SECSPERDAY; 1687 1688 for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) { 1689 sec_per_month = days_in_month[month] * SECSPERDAY; 1690 1691 if (month == TM_FEBRUARY && isleap(year)) 1692 sec_per_month += SECSPERDAY; 1693 1694 if (tsec < sec_per_month) 1695 break; 1696 1697 tsec -= sec_per_month; 1698 } 1699 1700 result->tm_mon = month; 1701 result->tm_mday = (tsec / SECSPERDAY) + 1; 1702 tsec %= SECSPERDAY; 1703 result->tm_sec = tsec % 60; 1704 tsec /= 60; 1705 result->tm_min = tsec % 60; 1706 tsec /= 60; 1707 result->tm_hour = (int)tsec; 1708 1709 return (result); 1710 } 1711 1712 1713 /* 1714 * smb_timegm 1715 * 1716 * Converts the broken-down time in tm to a time value, i.e. the number 1717 * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is 1718 * not a POSIX or ANSI function. Per the man page, the input values of 1719 * tm_wday and tm_yday are ignored and, as the input data is assumed to 1720 * represent GMT, we force tm_isdst and tm_gmtoff to 0. 1721 * 1722 * Before returning the clock time, we use smb_gmtime_r to set up tm_wday 1723 * and tm_yday, and bring the other fields within normal range. I don't 1724 * think this is really how it should be done but it's convenient for 1725 * now. 1726 */ 1727 time_t 1728 smb_timegm(struct tm *tm) 1729 { 1730 time_t tsec; 1731 int dd; 1732 int mm; 1733 int yy; 1734 int year; 1735 1736 if (tm == 0) 1737 return (-1); 1738 1739 year = tm->tm_year + TM_YEAR_BASE; 1740 tsec = tzh_leapcnt; 1741 1742 for (yy = EPOCH_YEAR; yy < year; ++yy) { 1743 if (isleap(yy)) 1744 tsec += SECSPERDAY * DAYSPERLYEAR; 1745 else 1746 tsec += SECSPERDAY * DAYSPERNYEAR; 1747 } 1748 1749 for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) { 1750 dd = days_in_month[mm] * SECSPERDAY; 1751 1752 if (mm == TM_FEBRUARY && isleap(year)) 1753 dd += SECSPERDAY; 1754 1755 tsec += dd; 1756 } 1757 1758 tsec += (tm->tm_mday - 1) * SECSPERDAY; 1759 tsec += tm->tm_sec; 1760 tsec += tm->tm_min * SECSPERMIN; 1761 tsec += tm->tm_hour * SECSPERHOUR; 1762 1763 tm->tm_isdst = 0; 1764 (void) smb_gmtime_r(&tsec, tm); 1765 return (tsec); 1766 } 1767 1768 /* 1769 * smb_pad_align 1770 * 1771 * Returns the number of bytes required to pad an offset to the 1772 * specified alignment. 1773 */ 1774 uint32_t 1775 smb_pad_align(uint32_t offset, uint32_t align) 1776 { 1777 uint32_t pad = offset % align; 1778 1779 if (pad != 0) 1780 pad = align - pad; 1781 1782 return (pad); 1783 } 1784 1785 /* 1786 * smb_panic 1787 * 1788 * Logs the file name, function name and line number passed in and panics the 1789 * system. 1790 */ 1791 void 1792 smb_panic(char *file, const char *func, int line) 1793 { 1794 cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line); 1795 } 1796 1797 /* 1798 * Creates an AVL tree and initializes the given smb_avl_t 1799 * structure using the passed args 1800 */ 1801 void 1802 smb_avl_create(smb_avl_t *avl, size_t size, size_t offset, smb_avl_nops_t *ops) 1803 { 1804 ASSERT(avl); 1805 ASSERT(ops); 1806 1807 rw_init(&avl->avl_lock, NULL, RW_DEFAULT, NULL); 1808 mutex_init(&avl->avl_mutex, NULL, MUTEX_DEFAULT, NULL); 1809 1810 avl->avl_nops = ops; 1811 avl->avl_state = SMB_AVL_STATE_READY; 1812 avl->avl_refcnt = 0; 1813 (void) random_get_pseudo_bytes((uint8_t *)&avl->avl_sequence, 1814 sizeof (uint32_t)); 1815 1816 avl_create(&avl->avl_tree, ops->avln_cmp, size, offset); 1817 } 1818 1819 /* 1820 * Destroys the specified AVL tree. 1821 * It waits for all the in-flight operations to finish 1822 * before destroying the AVL. 1823 */ 1824 void 1825 smb_avl_destroy(smb_avl_t *avl) 1826 { 1827 void *cookie = NULL; 1828 void *node; 1829 1830 ASSERT(avl); 1831 1832 mutex_enter(&avl->avl_mutex); 1833 if (avl->avl_state != SMB_AVL_STATE_READY) { 1834 mutex_exit(&avl->avl_mutex); 1835 return; 1836 } 1837 1838 avl->avl_state = SMB_AVL_STATE_DESTROYING; 1839 1840 while (avl->avl_refcnt > 0) 1841 (void) cv_wait(&avl->avl_cv, &avl->avl_mutex); 1842 mutex_exit(&avl->avl_mutex); 1843 1844 rw_enter(&avl->avl_lock, RW_WRITER); 1845 while ((node = avl_destroy_nodes(&avl->avl_tree, &cookie)) != NULL) 1846 avl->avl_nops->avln_destroy(node); 1847 1848 avl_destroy(&avl->avl_tree); 1849 rw_exit(&avl->avl_lock); 1850 1851 rw_destroy(&avl->avl_lock); 1852 1853 mutex_destroy(&avl->avl_mutex); 1854 bzero(avl, sizeof (smb_avl_t)); 1855 } 1856 1857 /* 1858 * Adds the given item to the AVL if it's 1859 * not already there. 1860 * 1861 * Returns: 1862 * 1863 * ENOTACTIVE AVL is not in READY state 1864 * EEXIST The item is already in AVL 1865 */ 1866 int 1867 smb_avl_add(smb_avl_t *avl, void *item) 1868 { 1869 avl_index_t where; 1870 1871 ASSERT(avl); 1872 ASSERT(item); 1873 1874 if (!smb_avl_hold(avl)) 1875 return (ENOTACTIVE); 1876 1877 rw_enter(&avl->avl_lock, RW_WRITER); 1878 if (avl_find(&avl->avl_tree, item, &where) != NULL) { 1879 rw_exit(&avl->avl_lock); 1880 smb_avl_rele(avl); 1881 return (EEXIST); 1882 } 1883 1884 avl_insert(&avl->avl_tree, item, where); 1885 avl->avl_sequence++; 1886 rw_exit(&avl->avl_lock); 1887 1888 smb_avl_rele(avl); 1889 return (0); 1890 } 1891 1892 /* 1893 * Removes the given item from the AVL. 1894 * If no reference is left on the item 1895 * it will also be destroyed by calling the 1896 * registered destroy operation. 1897 */ 1898 void 1899 smb_avl_remove(smb_avl_t *avl, void *item) 1900 { 1901 avl_index_t where; 1902 void *rm_item; 1903 1904 ASSERT(avl); 1905 ASSERT(item); 1906 1907 if (!smb_avl_hold(avl)) 1908 return; 1909 1910 rw_enter(&avl->avl_lock, RW_WRITER); 1911 if ((rm_item = avl_find(&avl->avl_tree, item, &where)) == NULL) { 1912 rw_exit(&avl->avl_lock); 1913 smb_avl_rele(avl); 1914 return; 1915 } 1916 1917 avl_remove(&avl->avl_tree, rm_item); 1918 if (avl->avl_nops->avln_rele(rm_item)) 1919 avl->avl_nops->avln_destroy(rm_item); 1920 avl->avl_sequence++; 1921 rw_exit(&avl->avl_lock); 1922 1923 smb_avl_rele(avl); 1924 } 1925 1926 /* 1927 * Looks up the AVL for the given item. 1928 * If the item is found a hold on the object 1929 * is taken before the pointer to it is 1930 * returned to the caller. The caller MUST 1931 * always call smb_avl_release() after it's done 1932 * using the returned object to release the hold 1933 * taken on the object. 1934 */ 1935 void * 1936 smb_avl_lookup(smb_avl_t *avl, void *item) 1937 { 1938 void *node = NULL; 1939 1940 ASSERT(avl); 1941 ASSERT(item); 1942 1943 if (!smb_avl_hold(avl)) 1944 return (NULL); 1945 1946 rw_enter(&avl->avl_lock, RW_READER); 1947 node = avl_find(&avl->avl_tree, item, NULL); 1948 if (node != NULL) 1949 avl->avl_nops->avln_hold(node); 1950 rw_exit(&avl->avl_lock); 1951 1952 if (node == NULL) 1953 smb_avl_rele(avl); 1954 1955 return (node); 1956 } 1957 1958 /* 1959 * The hold on the given object is released. 1960 * This function MUST always be called after 1961 * smb_avl_lookup() and smb_avl_iterate() for 1962 * the returned object. 1963 * 1964 * If AVL is in DESTROYING state, the destroying 1965 * thread will be notified. 1966 */ 1967 void 1968 smb_avl_release(smb_avl_t *avl, void *item) 1969 { 1970 ASSERT(avl); 1971 ASSERT(item); 1972 1973 if (avl->avl_nops->avln_rele(item)) 1974 avl->avl_nops->avln_destroy(item); 1975 1976 smb_avl_rele(avl); 1977 } 1978 1979 /* 1980 * Initializes the given cursor for the AVL. 1981 * The cursor will be used to iterate through the AVL 1982 */ 1983 void 1984 smb_avl_iterinit(smb_avl_t *avl, smb_avl_cursor_t *cursor) 1985 { 1986 ASSERT(avl); 1987 ASSERT(cursor); 1988 1989 cursor->avlc_next = NULL; 1990 cursor->avlc_sequence = avl->avl_sequence; 1991 } 1992 1993 /* 1994 * Iterates through the AVL using the given cursor. 1995 * It always starts at the beginning and then returns 1996 * a pointer to the next object on each subsequent call. 1997 * 1998 * If a new object is added to or removed from the AVL 1999 * between two calls to this function, the iteration 2000 * will terminate prematurely. 2001 * 2002 * The caller MUST always call smb_avl_release() after it's 2003 * done using the returned object to release the hold taken 2004 * on the object. 2005 */ 2006 void * 2007 smb_avl_iterate(smb_avl_t *avl, smb_avl_cursor_t *cursor) 2008 { 2009 void *node; 2010 2011 ASSERT(avl); 2012 ASSERT(cursor); 2013 2014 if (!smb_avl_hold(avl)) 2015 return (NULL); 2016 2017 rw_enter(&avl->avl_lock, RW_READER); 2018 if (cursor->avlc_sequence != avl->avl_sequence) { 2019 rw_exit(&avl->avl_lock); 2020 smb_avl_rele(avl); 2021 return (NULL); 2022 } 2023 2024 if (cursor->avlc_next == NULL) 2025 node = avl_first(&avl->avl_tree); 2026 else 2027 node = AVL_NEXT(&avl->avl_tree, cursor->avlc_next); 2028 2029 if (node != NULL) 2030 avl->avl_nops->avln_hold(node); 2031 2032 cursor->avlc_next = node; 2033 rw_exit(&avl->avl_lock); 2034 2035 if (node == NULL) 2036 smb_avl_rele(avl); 2037 2038 return (node); 2039 } 2040 2041 /* 2042 * Increments the AVL reference count in order to 2043 * prevent the avl from being destroyed while it's 2044 * being accessed. 2045 */ 2046 static boolean_t 2047 smb_avl_hold(smb_avl_t *avl) 2048 { 2049 mutex_enter(&avl->avl_mutex); 2050 if (avl->avl_state != SMB_AVL_STATE_READY) { 2051 mutex_exit(&avl->avl_mutex); 2052 return (B_FALSE); 2053 } 2054 avl->avl_refcnt++; 2055 mutex_exit(&avl->avl_mutex); 2056 2057 return (B_TRUE); 2058 } 2059 2060 /* 2061 * Decrements the AVL reference count to release the 2062 * hold. If another thread is trying to destroy the 2063 * AVL and is waiting for the reference count to become 2064 * 0, it is signaled to wake up. 2065 */ 2066 static void 2067 smb_avl_rele(smb_avl_t *avl) 2068 { 2069 mutex_enter(&avl->avl_mutex); 2070 ASSERT(avl->avl_refcnt > 0); 2071 avl->avl_refcnt--; 2072 if (avl->avl_state == SMB_AVL_STATE_DESTROYING) 2073 cv_broadcast(&avl->avl_cv); 2074 mutex_exit(&avl->avl_mutex); 2075 } 2076 2077 /* 2078 * smb_latency_init 2079 */ 2080 void 2081 smb_latency_init(smb_latency_t *lat) 2082 { 2083 bzero(lat, sizeof (*lat)); 2084 mutex_init(&lat->ly_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); 2085 } 2086 2087 /* 2088 * smb_latency_destroy 2089 */ 2090 void 2091 smb_latency_destroy(smb_latency_t *lat) 2092 { 2093 mutex_destroy(&lat->ly_mutex); 2094 } 2095 2096 /* 2097 * smb_latency_add_sample 2098 * 2099 * Uses the new sample to calculate the new mean and standard deviation. The 2100 * sample must be a scaled value. 2101 */ 2102 void 2103 smb_latency_add_sample(smb_latency_t *lat, hrtime_t sample) 2104 { 2105 hrtime_t a_mean; 2106 hrtime_t d_mean; 2107 2108 mutex_enter(&lat->ly_mutex); 2109 lat->ly_a_nreq++; 2110 lat->ly_a_sum += sample; 2111 if (lat->ly_a_nreq != 0) { 2112 a_mean = lat->ly_a_sum / lat->ly_a_nreq; 2113 lat->ly_a_stddev = 2114 (sample - a_mean) * (sample - lat->ly_a_mean); 2115 lat->ly_a_mean = a_mean; 2116 } 2117 lat->ly_d_nreq++; 2118 lat->ly_d_sum += sample; 2119 if (lat->ly_d_nreq != 0) { 2120 d_mean = lat->ly_d_sum / lat->ly_d_nreq; 2121 lat->ly_d_stddev = 2122 (sample - d_mean) * (sample - lat->ly_d_mean); 2123 lat->ly_d_mean = d_mean; 2124 } 2125 mutex_exit(&lat->ly_mutex); 2126 } 2127 2128 /* 2129 * smb_srqueue_init 2130 */ 2131 void 2132 smb_srqueue_init(smb_srqueue_t *srq) 2133 { 2134 bzero(srq, sizeof (*srq)); 2135 mutex_init(&srq->srq_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7)); 2136 srq->srq_wlastupdate = srq->srq_rlastupdate = gethrtime_unscaled(); 2137 } 2138 2139 /* 2140 * smb_srqueue_destroy 2141 */ 2142 void 2143 smb_srqueue_destroy(smb_srqueue_t *srq) 2144 { 2145 mutex_destroy(&srq->srq_mutex); 2146 } 2147 2148 /* 2149 * smb_srqueue_waitq_enter 2150 */ 2151 void 2152 smb_srqueue_waitq_enter(smb_srqueue_t *srq) 2153 { 2154 hrtime_t new; 2155 hrtime_t delta; 2156 uint32_t wcnt; 2157 2158 mutex_enter(&srq->srq_mutex); 2159 new = gethrtime_unscaled(); 2160 delta = new - srq->srq_wlastupdate; 2161 srq->srq_wlastupdate = new; 2162 wcnt = srq->srq_wcnt++; 2163 if (wcnt != 0) { 2164 srq->srq_wlentime += delta * wcnt; 2165 srq->srq_wtime += delta; 2166 } 2167 mutex_exit(&srq->srq_mutex); 2168 } 2169 2170 /* 2171 * smb_srqueue_runq_exit 2172 */ 2173 void 2174 smb_srqueue_runq_exit(smb_srqueue_t *srq) 2175 { 2176 hrtime_t new; 2177 hrtime_t delta; 2178 uint32_t rcnt; 2179 2180 mutex_enter(&srq->srq_mutex); 2181 new = gethrtime_unscaled(); 2182 delta = new - srq->srq_rlastupdate; 2183 srq->srq_rlastupdate = new; 2184 rcnt = srq->srq_rcnt--; 2185 ASSERT(rcnt > 0); 2186 srq->srq_rlentime += delta * rcnt; 2187 srq->srq_rtime += delta; 2188 mutex_exit(&srq->srq_mutex); 2189 } 2190 2191 /* 2192 * smb_srqueue_waitq_to_runq 2193 */ 2194 void 2195 smb_srqueue_waitq_to_runq(smb_srqueue_t *srq) 2196 { 2197 hrtime_t new; 2198 hrtime_t delta; 2199 uint32_t wcnt; 2200 uint32_t rcnt; 2201 2202 mutex_enter(&srq->srq_mutex); 2203 new = gethrtime_unscaled(); 2204 delta = new - srq->srq_wlastupdate; 2205 srq->srq_wlastupdate = new; 2206 wcnt = srq->srq_wcnt--; 2207 ASSERT(wcnt > 0); 2208 srq->srq_wlentime += delta * wcnt; 2209 srq->srq_wtime += delta; 2210 delta = new - srq->srq_rlastupdate; 2211 srq->srq_rlastupdate = new; 2212 rcnt = srq->srq_rcnt++; 2213 if (rcnt != 0) { 2214 srq->srq_rlentime += delta * rcnt; 2215 srq->srq_rtime += delta; 2216 } 2217 mutex_exit(&srq->srq_mutex); 2218 } 2219 2220 /* 2221 * smb_srqueue_update 2222 * 2223 * Takes a snapshot of the smb_sr_stat_t structure passed in. 2224 */ 2225 void 2226 smb_srqueue_update(smb_srqueue_t *srq, smb_kstat_utilization_t *kd) 2227 { 2228 hrtime_t delta; 2229 hrtime_t snaptime; 2230 2231 mutex_enter(&srq->srq_mutex); 2232 snaptime = gethrtime_unscaled(); 2233 delta = snaptime - srq->srq_wlastupdate; 2234 srq->srq_wlastupdate = snaptime; 2235 if (srq->srq_wcnt != 0) { 2236 srq->srq_wlentime += delta * srq->srq_wcnt; 2237 srq->srq_wtime += delta; 2238 } 2239 delta = snaptime - srq->srq_rlastupdate; 2240 srq->srq_rlastupdate = snaptime; 2241 if (srq->srq_rcnt != 0) { 2242 srq->srq_rlentime += delta * srq->srq_rcnt; 2243 srq->srq_rtime += delta; 2244 } 2245 kd->ku_rlentime = srq->srq_rlentime; 2246 kd->ku_rtime = srq->srq_rtime; 2247 kd->ku_wlentime = srq->srq_wlentime; 2248 kd->ku_wtime = srq->srq_wtime; 2249 mutex_exit(&srq->srq_mutex); 2250 scalehrtime(&kd->ku_rlentime); 2251 scalehrtime(&kd->ku_rtime); 2252 scalehrtime(&kd->ku_wlentime); 2253 scalehrtime(&kd->ku_wtime); 2254 } 2255 2256 void 2257 smb_threshold_init(smb_cmd_threshold_t *ct, char *cmd, int threshold, 2258 int timeout) 2259 { 2260 bzero(ct, sizeof (smb_cmd_threshold_t)); 2261 mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL); 2262 ct->ct_cmd = cmd; 2263 ct->ct_threshold = threshold; 2264 ct->ct_event = smb_event_create(timeout); 2265 ct->ct_event_id = smb_event_txid(ct->ct_event); 2266 2267 if (smb_threshold_debug) { 2268 cmn_err(CE_NOTE, "smb_threshold_init[%s]: threshold (%d), " 2269 "timeout (%d)", cmd, threshold, timeout); 2270 } 2271 } 2272 2273 /* 2274 * This function must be called prior to SMB_SERVER_STATE_STOPPING state 2275 * so that ct_event can be successfully removed from the event list. 2276 * It should not be called when the server mutex is held or when the 2277 * server is removed from the server list. 2278 */ 2279 void 2280 smb_threshold_fini(smb_cmd_threshold_t *ct) 2281 { 2282 smb_event_destroy(ct->ct_event); 2283 mutex_destroy(&ct->ct_mutex); 2284 bzero(ct, sizeof (smb_cmd_threshold_t)); 2285 } 2286 2287 /* 2288 * This threshold mechanism can be used to limit the number of simultaneous 2289 * requests, which serves to limit the stress that can be applied to the 2290 * service and also allows the service to respond to requests before the 2291 * client times out and reports that the server is not responding, 2292 * 2293 * If the number of requests exceeds the threshold, new requests will be 2294 * stalled until the number drops back to the threshold. Stalled requests 2295 * will be notified as appropriate, in which case 0 will be returned. 2296 * If the timeout expires before the request is notified, a non-zero errno 2297 * value will be returned. 2298 * 2299 * To avoid a flood of messages, the message rate is throttled as well. 2300 */ 2301 int 2302 smb_threshold_enter(smb_cmd_threshold_t *ct) 2303 { 2304 int rc; 2305 2306 mutex_enter(&ct->ct_mutex); 2307 if (ct->ct_active_cnt >= ct->ct_threshold && ct->ct_event != NULL) { 2308 atomic_inc_32(&ct->ct_blocked_cnt); 2309 2310 if (smb_threshold_debug) { 2311 cmn_err(CE_NOTE, "smb_threshold_enter[%s]: blocked " 2312 "(blocked ops: %u, inflight ops: %u)", 2313 ct->ct_cmd, ct->ct_blocked_cnt, ct->ct_active_cnt); 2314 } 2315 2316 mutex_exit(&ct->ct_mutex); 2317 2318 if ((rc = smb_event_wait(ct->ct_event)) != 0) { 2319 if (rc == ECANCELED) 2320 return (rc); 2321 2322 mutex_enter(&ct->ct_mutex); 2323 if (ct->ct_active_cnt >= ct->ct_threshold) { 2324 2325 if ((ct->ct_error_cnt % 2326 SMB_THRESHOLD_REPORT_THROTTLE) == 0) { 2327 cmn_err(CE_NOTE, "%s: server busy: " 2328 "threshold %d exceeded)", 2329 ct->ct_cmd, ct->ct_threshold); 2330 } 2331 2332 atomic_inc_32(&ct->ct_error_cnt); 2333 mutex_exit(&ct->ct_mutex); 2334 return (rc); 2335 } 2336 2337 mutex_exit(&ct->ct_mutex); 2338 2339 } 2340 2341 mutex_enter(&ct->ct_mutex); 2342 atomic_dec_32(&ct->ct_blocked_cnt); 2343 if (smb_threshold_debug) { 2344 cmn_err(CE_NOTE, "smb_threshold_enter[%s]: resumed " 2345 "(blocked ops: %u, inflight ops: %u)", ct->ct_cmd, 2346 ct->ct_blocked_cnt, ct->ct_active_cnt); 2347 } 2348 } 2349 2350 atomic_inc_32(&ct->ct_active_cnt); 2351 mutex_exit(&ct->ct_mutex); 2352 return (0); 2353 } 2354 2355 void 2356 smb_threshold_exit(smb_cmd_threshold_t *ct, smb_server_t *sv) 2357 { 2358 mutex_enter(&ct->ct_mutex); 2359 atomic_dec_32(&ct->ct_active_cnt); 2360 mutex_exit(&ct->ct_mutex); 2361 smb_event_notify(sv, ct->ct_event_id); 2362 } 2363