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 }