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