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