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