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