1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21c13be35aSGordon Ross 
22da6c28aaSamw /*
23c5866007SKeyur Desai  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24811599a4SMatt Barden  * Copyright 2018 Nexenta Systems, Inc. All rights reserved.
25*b62fa64bSToomas Soome  * Copyright 2022-2023 RackTop Systems, Inc.
269a1586dbSAndy Fiddaman  * Copyright 2023 Oxide Computer Company
27da6c28aaSamw  */
28da6c28aaSamw 
293a6c5f83SAlan Wright #include <sys/param.h>
303a6c5f83SAlan Wright #include <sys/types.h>
31da6c28aaSamw #include <sys/tzfile.h>
32da6c28aaSamw #include <sys/atomic.h>
33da6c28aaSamw #include <sys/time.h>
34148c5f43SAlan Wright #include <sys/spl.h>
35148c5f43SAlan Wright #include <sys/random.h>
36bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
37da6c28aaSamw #include <smbsrv/smb_fsops.h>
38da6c28aaSamw #include <smbsrv/smbinfo.h>
39da6c28aaSamw #include <smbsrv/smb_xdr.h>
40da6c28aaSamw #include <smbsrv/smb_vops.h>
41da6c28aaSamw #include <smbsrv/smb_idmap.h>
42da6c28aaSamw 
43da6c28aaSamw #include <sys/sid.h>
44da6c28aaSamw #include <sys/priv_names.h>
45811599a4SMatt Barden #include <sys/bitmap.h>
46da6c28aaSamw 
478622ec45SGordon Ross static kmem_cache_t	*smb_dtor_cache = NULL;
489fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
49148c5f43SAlan Wright static boolean_t smb_avl_hold(smb_avl_t *);
50148c5f43SAlan Wright static void smb_avl_rele(smb_avl_t *);
51148c5f43SAlan Wright 
52da6c28aaSamw time_t tzh_leapcnt = 0;
53da6c28aaSamw 
54da6c28aaSamw struct tm
55da6c28aaSamw *smb_gmtime_r(time_t *clock, struct tm *result);
56da6c28aaSamw 
57da6c28aaSamw time_t
58da6c28aaSamw smb_timegm(struct tm *tm);
59da6c28aaSamw 
60da6c28aaSamw struct	tm {
61da6c28aaSamw 	int	tm_sec;
62da6c28aaSamw 	int	tm_min;
63da6c28aaSamw 	int	tm_hour;
64da6c28aaSamw 	int	tm_mday;
65da6c28aaSamw 	int	tm_mon;
66da6c28aaSamw 	int	tm_year;
67da6c28aaSamw 	int	tm_wday;
68da6c28aaSamw 	int	tm_yday;
69da6c28aaSamw 	int	tm_isdst;
70da6c28aaSamw };
71da6c28aaSamw 
728622ec45SGordon Ross static const int days_in_month[] = {
73da6c28aaSamw 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
74da6c28aaSamw };
75da6c28aaSamw 
7607a6ae61SGordon Ross /*
7707a6ae61SGordon Ross  * Given a UTF-8 string (our internal form everywhere)
7807a6ae61SGordon Ross  * return either the Unicode (UTF-16) length in bytes,
7907a6ae61SGordon Ross  * or the OEM length in bytes.  Which we return is
8007a6ae61SGordon Ross  * determined by whether the client supports Unicode.
8107a6ae61SGordon Ross  * This length does NOT include the null.
8207a6ae61SGordon Ross  */
83da6c28aaSamw int
smb_ascii_or_unicode_strlen(struct smb_request * sr,char * str)84da6c28aaSamw smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str)
85da6c28aaSamw {
86a90cf9f2SGordon Ross 	if (sr->session->dialect >= SMB_VERS_2_BASE ||
87a90cf9f2SGordon Ross 	    (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
88bbf6f00cSJordan Brown 		return (smb_wcequiv_strlen(str));
8907a6ae61SGordon Ross 	return (smb_sbequiv_strlen(str));
90da6c28aaSamw }
91da6c28aaSamw 
9207a6ae61SGordon Ross /*
9307a6ae61SGordon Ross  * Given a UTF-8 string (our internal form everywhere)
9407a6ae61SGordon Ross  * return either the Unicode (UTF-16) length in bytes,
9507a6ae61SGordon Ross  * or the OEM length in bytes.  Which we return is
9607a6ae61SGordon Ross  * determined by whether the client supports Unicode.
9707a6ae61SGordon Ross  * This length DOES include the null.
9807a6ae61SGordon Ross  */
99da6c28aaSamw int
smb_ascii_or_unicode_strlen_null(struct smb_request * sr,char * str)100da6c28aaSamw smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str)
101da6c28aaSamw {
102a90cf9f2SGordon Ross 	if (sr->session->dialect >= SMB_VERS_2_BASE ||
103a90cf9f2SGordon Ross 	    (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
104bbf6f00cSJordan Brown 		return (smb_wcequiv_strlen(str) + 2);
10507a6ae61SGordon Ross 	return (smb_sbequiv_strlen(str) + 1);
106da6c28aaSamw }
107da6c28aaSamw 
108da6c28aaSamw int
smb_ascii_or_unicode_null_len(struct smb_request * sr)109da6c28aaSamw smb_ascii_or_unicode_null_len(struct smb_request *sr)
110da6c28aaSamw {
111a90cf9f2SGordon Ross 	if (sr->session->dialect >= SMB_VERS_2_BASE ||
112a90cf9f2SGordon Ross 	    (sr->smb_flg2 & SMB_FLAGS2_UNICODE) != 0)
113da6c28aaSamw 		return (2);
114da6c28aaSamw 	return (1);
115da6c28aaSamw }
116da6c28aaSamw 
1173a6c5f83SAlan Wright /*
1183a6c5f83SAlan Wright  *
119c13be35aSGordon Ross  * Convert old-style (DOS, LanMan) wildcard strings to NT style.
120c13be35aSGordon Ross  * This should ONLY happen to patterns that come from old clients,
121c13be35aSGordon Ross  * meaning dialect LANMAN2_1 etc. (dialect < NT_LM_0_12).
1223a6c5f83SAlan Wright  *
1233a6c5f83SAlan Wright  *	? is converted to >
1243a6c5f83SAlan Wright  *	* is converted to < if it is followed by .
125c13be35aSGordon Ross  *	. is converted to " if it is followed by ? or * or end of pattern
1263a6c5f83SAlan Wright  *
127c13be35aSGordon Ross  * Note: modifies pattern in place.
1283a6c5f83SAlan Wright  */
129fe1c642dSBill Krier void
smb_convert_wildcards(char * pattern)130fe1c642dSBill Krier smb_convert_wildcards(char *pattern)
1313a6c5f83SAlan Wright {
1323a6c5f83SAlan Wright 	char	*p;
1333a6c5f83SAlan Wright 
134c13be35aSGordon Ross 	for (p = pattern; *p != '\0'; p++) {
1353a6c5f83SAlan Wright 		switch (*p) {
136c13be35aSGordon Ross 		case '?':
137c13be35aSGordon Ross 			*p = '>';
138da6c28aaSamw 			break;
139c13be35aSGordon Ross 		case '*':
140c13be35aSGordon Ross 			if (p[1] == '.')
141c13be35aSGordon Ross 				*p = '<';
142da6c28aaSamw 			break;
143c13be35aSGordon Ross 		case '.':
144c13be35aSGordon Ross 			if (p[1] == '?' || p[1] == '*' || p[1] == '\0')
145c13be35aSGordon Ross 				*p = '\"';
1463a6c5f83SAlan Wright 			break;
1473a6c5f83SAlan Wright 		}
1483a6c5f83SAlan Wright 	}
149da6c28aaSamw }
150da6c28aaSamw 
151da6c28aaSamw /*
152da6c28aaSamw  * smb_sattr_check
153da6c28aaSamw  *
1543db3f65cSamw  * Check file attributes against a search attribute (sattr) mask.
1553db3f65cSamw  *
1563db3f65cSamw  * Normal files, which includes READONLY and ARCHIVE, always pass
1573db3f65cSamw  * this check.  If the DIRECTORY, HIDDEN or SYSTEM special attributes
1583db3f65cSamw  * are set then they must appear in the search mask.  The special
1593db3f65cSamw  * attributes are inclusive, i.e. all special attributes that appear
1603db3f65cSamw  * in sattr must also appear in the file attributes for the check to
1613db3f65cSamw  * pass.
162da6c28aaSamw  *
1633db3f65cSamw  * The following examples show how this works:
1643db3f65cSamw  *
1653db3f65cSamw  *		fileA:	READONLY
166da6c28aaSamw  *		fileB:	0 (no attributes = normal file)
1673db3f65cSamw  *		fileC:	READONLY, ARCHIVE
1683db3f65cSamw  *		fileD:	HIDDEN
1693db3f65cSamw  *		fileE:	READONLY, HIDDEN, SYSTEM
1703db3f65cSamw  *		dirA:	DIRECTORY
171da6c28aaSamw  *
1723db3f65cSamw  * search attribute: 0
173da6c28aaSamw  *		Returns: fileA, fileB and fileC.
1743db3f65cSamw  * search attribute: HIDDEN
175da6c28aaSamw  *		Returns: fileA, fileB, fileC and fileD.
1763db3f65cSamw  * search attribute: SYSTEM
177da6c28aaSamw  *		Returns: fileA, fileB and fileC.
1783db3f65cSamw  * search attribute: DIRECTORY
179da6c28aaSamw  *		Returns: fileA, fileB, fileC and dirA.
1803db3f65cSamw  * search attribute: HIDDEN and SYSTEM
181da6c28aaSamw  *		Returns: fileA, fileB, fileC, fileD and fileE.
182da6c28aaSamw  *
1833db3f65cSamw  * Returns true if the file and sattr match; otherwise, returns false.
184da6c28aaSamw  */
1853db3f65cSamw boolean_t
smb_sattr_check(uint16_t dosattr,uint16_t sattr)1862c2961f8Sjose borrego smb_sattr_check(uint16_t dosattr, uint16_t sattr)
187da6c28aaSamw {
1887f667e74Sjose borrego 	if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) &&
1893db3f65cSamw 	    !(sattr & FILE_ATTRIBUTE_DIRECTORY))
1903db3f65cSamw 		return (B_FALSE);
191da6c28aaSamw 
1927f667e74Sjose borrego 	if ((dosattr & FILE_ATTRIBUTE_HIDDEN) &&
1933db3f65cSamw 	    !(sattr & FILE_ATTRIBUTE_HIDDEN))
1943db3f65cSamw 		return (B_FALSE);
195da6c28aaSamw 
1967f667e74Sjose borrego 	if ((dosattr & FILE_ATTRIBUTE_SYSTEM) &&
1973db3f65cSamw 	    !(sattr & FILE_ATTRIBUTE_SYSTEM))
1983db3f65cSamw 		return (B_FALSE);
199da6c28aaSamw 
2003db3f65cSamw 	return (B_TRUE);
201da6c28aaSamw }
202da6c28aaSamw 
203a90cf9f2SGordon Ross time_t
smb_get_boottime(void)204a90cf9f2SGordon Ross smb_get_boottime(void)
205da6c28aaSamw {
2069a1586dbSAndy Fiddaman 	return (curzone->zone_boot_time);
207da6c28aaSamw }
208da6c28aaSamw 
209da6c28aaSamw /*
210da6c28aaSamw  * smb_idpool_increment
211da6c28aaSamw  *
212da6c28aaSamw  * This function increments the ID pool by doubling the current size. This
213da6c28aaSamw  * function assumes the caller entered the mutex of the pool.
214da6c28aaSamw  */
215da6c28aaSamw static int
smb_idpool_increment(smb_idpool_t * pool)216da6c28aaSamw smb_idpool_increment(
217da6c28aaSamw     smb_idpool_t	*pool)
218da6c28aaSamw {
219da6c28aaSamw 	uint8_t		*new_pool;
220da6c28aaSamw 	uint32_t	new_size;
221da6c28aaSamw 
222da6c28aaSamw 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
223da6c28aaSamw 
224da6c28aaSamw 	new_size = pool->id_size * 2;
225da6c28aaSamw 	if (new_size <= SMB_IDPOOL_MAX_SIZE) {
226da6c28aaSamw 		new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP);
227da6c28aaSamw 		if (new_pool) {
228da6c28aaSamw 			bzero(new_pool, new_size / 8);
229da6c28aaSamw 			bcopy(pool->id_pool, new_pool, pool->id_size / 8);
230da6c28aaSamw 			kmem_free(pool->id_pool, pool->id_size / 8);
231da6c28aaSamw 			pool->id_pool = new_pool;
232da6c28aaSamw 			pool->id_free_counter += new_size - pool->id_size;
233da6c28aaSamw 			pool->id_max_free_counter += new_size - pool->id_size;
234da6c28aaSamw 			pool->id_size = new_size;
235da6c28aaSamw 			pool->id_idx_msk = (new_size / 8) - 1;
236da6c28aaSamw 			if (new_size >= SMB_IDPOOL_MAX_SIZE) {
237da6c28aaSamw 				/* id -1 made unavailable */
238da6c28aaSamw 				pool->id_pool[pool->id_idx_msk] = 0x80;
239da6c28aaSamw 				pool->id_free_counter--;
240da6c28aaSamw 				pool->id_max_free_counter--;
241da6c28aaSamw 			}
242da6c28aaSamw 			return (0);
243da6c28aaSamw 		}
244da6c28aaSamw 	}
245da6c28aaSamw 	return (-1);
246da6c28aaSamw }
247da6c28aaSamw 
248da6c28aaSamw /*
249da6c28aaSamw  * smb_idpool_constructor
250da6c28aaSamw  *
251da6c28aaSamw  * This function initializes the pool structure provided.
252da6c28aaSamw  */
253da6c28aaSamw int
smb_idpool_constructor(smb_idpool_t * pool)254da6c28aaSamw smb_idpool_constructor(
255da6c28aaSamw     smb_idpool_t	*pool)
256da6c28aaSamw {
257da6c28aaSamw 
258da6c28aaSamw 	ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC);
259da6c28aaSamw 
260da6c28aaSamw 	pool->id_size = SMB_IDPOOL_MIN_SIZE;
261da6c28aaSamw 	pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1;
262da6c28aaSamw 	pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
263da6c28aaSamw 	pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
264da6c28aaSamw 	pool->id_bit = 0x02;
265da6c28aaSamw 	pool->id_bit_idx = 1;
266da6c28aaSamw 	pool->id_idx = 0;
267da6c28aaSamw 	pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8),
268da6c28aaSamw 	    KM_SLEEP);
269da6c28aaSamw 	bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8));
270da6c28aaSamw 	/* -1 id made unavailable */
271da6c28aaSamw 	pool->id_pool[0] = 0x01;		/* id 0 made unavailable */
272da6c28aaSamw 	mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL);
273da6c28aaSamw 	pool->id_magic = SMB_IDPOOL_MAGIC;
274da6c28aaSamw 	return (0);
275da6c28aaSamw }
276da6c28aaSamw 
277da6c28aaSamw /*
278da6c28aaSamw  * smb_idpool_destructor
279da6c28aaSamw  *
280da6c28aaSamw  * This function tears down and frees the resources associated with the
281da6c28aaSamw  * pool provided.
282da6c28aaSamw  */
283da6c28aaSamw void
smb_idpool_destructor(smb_idpool_t * pool)284da6c28aaSamw smb_idpool_destructor(
285da6c28aaSamw     smb_idpool_t	*pool)
286da6c28aaSamw {
287da6c28aaSamw 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
288da6c28aaSamw 	ASSERT(pool->id_free_counter == pool->id_max_free_counter);
289da6c28aaSamw 	pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC;
290da6c28aaSamw 	mutex_destroy(&pool->id_mutex);
291da6c28aaSamw 	kmem_free(pool->id_pool, (size_t)(pool->id_size / 8));
292da6c28aaSamw }
293da6c28aaSamw 
294da6c28aaSamw /*
295da6c28aaSamw  * smb_idpool_alloc
296da6c28aaSamw  *
297da6c28aaSamw  * This function allocates an ID from the pool provided.
298da6c28aaSamw  */
299da6c28aaSamw int
smb_idpool_alloc(smb_idpool_t * pool,uint16_t * id)300da6c28aaSamw smb_idpool_alloc(
301da6c28aaSamw     smb_idpool_t	*pool,
302da6c28aaSamw     uint16_t		*id)
303da6c28aaSamw {
304da6c28aaSamw 	uint32_t	i;
305da6c28aaSamw 	uint8_t		bit;
306da6c28aaSamw 	uint8_t		bit_idx;
307da6c28aaSamw 	uint8_t		byte;
308da6c28aaSamw 
309da6c28aaSamw 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
310da6c28aaSamw 
311da6c28aaSamw 	mutex_enter(&pool->id_mutex);
312da6c28aaSamw 	if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) {
313da6c28aaSamw 		mutex_exit(&pool->id_mutex);
314da6c28aaSamw 		return (-1);
315da6c28aaSamw 	}
316da6c28aaSamw 
317da6c28aaSamw 	i = pool->id_size;
318da6c28aaSamw 	while (i) {
319da6c28aaSamw 		bit = pool->id_bit;
320da6c28aaSamw 		bit_idx = pool->id_bit_idx;
321da6c28aaSamw 		byte = pool->id_pool[pool->id_idx];
322da6c28aaSamw 		while (bit) {
323da6c28aaSamw 			if (byte & bit) {
324da6c28aaSamw 				bit = bit << 1;
325da6c28aaSamw 				bit_idx++;
326da6c28aaSamw 				continue;
327da6c28aaSamw 			}
328da6c28aaSamw 			pool->id_pool[pool->id_idx] |= bit;
329da6c28aaSamw 			*id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
330da6c28aaSamw 			pool->id_free_counter--;
331811599a4SMatt Barden 			/*
332811599a4SMatt Barden 			 * Leave position at next bit to allocate,
333811599a4SMatt Barden 			 * so we don't keep re-using the last in an
334811599a4SMatt Barden 			 * alloc/free/alloc/free sequence.  Doing
335811599a4SMatt Barden 			 * that can confuse some SMB clients.
336811599a4SMatt Barden 			 */
337811599a4SMatt Barden 			if (bit & 0x80) {
338811599a4SMatt Barden 				pool->id_bit = 1;
339811599a4SMatt Barden 				pool->id_bit_idx = 0;
340811599a4SMatt Barden 				pool->id_idx++;
341811599a4SMatt Barden 				pool->id_idx &= pool->id_idx_msk;
342811599a4SMatt Barden 			} else {
343811599a4SMatt Barden 				pool->id_bit = (bit << 1);
344811599a4SMatt Barden 				pool->id_bit_idx = bit_idx + 1;
345811599a4SMatt Barden 				/* keep id_idx */
346811599a4SMatt Barden 			}
347da6c28aaSamw 			mutex_exit(&pool->id_mutex);
348da6c28aaSamw 			return (0);
349da6c28aaSamw 		}
350da6c28aaSamw 		pool->id_bit = 1;
351da6c28aaSamw 		pool->id_bit_idx = 0;
352da6c28aaSamw 		pool->id_idx++;
353da6c28aaSamw 		pool->id_idx &= pool->id_idx_msk;
354da6c28aaSamw 		--i;
355da6c28aaSamw 	}
356da6c28aaSamw 	/*
357da6c28aaSamw 	 * This section of code shouldn't be reached. If there are IDs
358da6c28aaSamw 	 * available and none could be found there's a problem.
359da6c28aaSamw 	 */
360da6c28aaSamw 	ASSERT(0);
361da6c28aaSamw 	mutex_exit(&pool->id_mutex);
362da6c28aaSamw 	return (-1);
363da6c28aaSamw }
364da6c28aaSamw 
365da6c28aaSamw /*
366da6c28aaSamw  * smb_idpool_free
367da6c28aaSamw  *
368da6c28aaSamw  * This function frees the ID provided.
369da6c28aaSamw  */
370da6c28aaSamw void
smb_idpool_free(smb_idpool_t * pool,uint16_t id)371da6c28aaSamw smb_idpool_free(
372da6c28aaSamw     smb_idpool_t	*pool,
373da6c28aaSamw     uint16_t		id)
374da6c28aaSamw {
375da6c28aaSamw 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
376da6c28aaSamw 	ASSERT(id != 0);
377da6c28aaSamw 	ASSERT(id != 0xFFFF);
378da6c28aaSamw 
379da6c28aaSamw 	mutex_enter(&pool->id_mutex);
380da6c28aaSamw 	if (pool->id_pool[id >> 3] & (1 << (id & 7))) {
381da6c28aaSamw 		pool->id_pool[id >> 3] &= ~(1 << (id & 7));
382da6c28aaSamw 		pool->id_free_counter++;
383da6c28aaSamw 		ASSERT(pool->id_free_counter <= pool->id_max_free_counter);
384da6c28aaSamw 		mutex_exit(&pool->id_mutex);
385da6c28aaSamw 		return;
386da6c28aaSamw 	}
387da6c28aaSamw 	/* Freeing a free ID. */
388da6c28aaSamw 	ASSERT(0);
389da6c28aaSamw 	mutex_exit(&pool->id_mutex);
390da6c28aaSamw }
391da6c28aaSamw 
3922cf6b79fSGordon Ross /*
3932cf6b79fSGordon Ross  * smb_lavl_constructor
3942cf6b79fSGordon Ross  *
3952cf6b79fSGordon Ross  * This function initializes a locked avl.
3962cf6b79fSGordon Ross  */
3972cf6b79fSGordon Ross void
smb_lavl_constructor(smb_lavl_t * la,int (* compar)(const void *,const void *),size_t size,size_t offset)3982cf6b79fSGordon Ross smb_lavl_constructor(
3992cf6b79fSGordon Ross     smb_lavl_t	*la,
4002cf6b79fSGordon Ross     int (*compar) (const void *, const void *),
4012cf6b79fSGordon Ross     size_t	size,
4022cf6b79fSGordon Ross     size_t	offset)
4032cf6b79fSGordon Ross {
4042cf6b79fSGordon Ross 	rw_init(&la->la_lock, NULL, RW_DEFAULT, NULL);
4052cf6b79fSGordon Ross 	mutex_init(&la->la_mutex, NULL, MUTEX_DEFAULT, NULL);
4062cf6b79fSGordon Ross 	avl_create(&la->la_tree, compar, size, offset);
4072cf6b79fSGordon Ross 	list_create(&la->la_deleteq, sizeof (smb_dtor_t),
4082cf6b79fSGordon Ross 	    offsetof(smb_dtor_t, dt_lnd));
4092cf6b79fSGordon Ross 	la->la_wrop = 0;
4102cf6b79fSGordon Ross 	la->la_deleteq_count = 0;
4112cf6b79fSGordon Ross 	la->la_flushing = B_FALSE;
4122cf6b79fSGordon Ross }
4132cf6b79fSGordon Ross 
4142cf6b79fSGordon Ross /*
4152cf6b79fSGordon Ross  * Flush the delete queue and destroy a locked avl.
4162cf6b79fSGordon Ross  */
4172cf6b79fSGordon Ross void
smb_lavl_destructor(smb_lavl_t * la)4182cf6b79fSGordon Ross smb_lavl_destructor(
4192cf6b79fSGordon Ross     smb_lavl_t	*la)
4202cf6b79fSGordon Ross {
4212cf6b79fSGordon Ross 	smb_lavl_flush(la);
4222cf6b79fSGordon Ross 
4232cf6b79fSGordon Ross 	ASSERT(la->la_deleteq_count == 0);
4242cf6b79fSGordon Ross 	ASSERT0(avl_numnodes(&la->la_tree));
4252cf6b79fSGordon Ross 
4262cf6b79fSGordon Ross 	rw_destroy(&la->la_lock);
4272cf6b79fSGordon Ross 	avl_destroy(&la->la_tree);
4282cf6b79fSGordon Ross 	list_destroy(&la->la_deleteq);
4292cf6b79fSGordon Ross 	mutex_destroy(&la->la_mutex);
4302cf6b79fSGordon Ross }
4312cf6b79fSGordon Ross 
4322cf6b79fSGordon Ross /*
4332cf6b79fSGordon Ross  * smb_lavl_enter
4342cf6b79fSGordon Ross  * Not a macro so dtrace smbsrv:* can see it.
4352cf6b79fSGordon Ross  */
4362cf6b79fSGordon Ross void
smb_lavl_enter(smb_lavl_t * la,krw_t mode)4372cf6b79fSGordon Ross smb_lavl_enter(smb_lavl_t *la, krw_t mode)
4382cf6b79fSGordon Ross {
4392cf6b79fSGordon Ross 	rw_enter(&la->la_lock, mode);
4402cf6b79fSGordon Ross }
4412cf6b79fSGordon Ross 
4422cf6b79fSGordon Ross /*
4432cf6b79fSGordon Ross  * Post an object to the delete queue.  The delete queue will be processed
4442cf6b79fSGordon Ross  * during smb_lavl_exit or lavl destruction.  Objects are often posted for
4452cf6b79fSGordon Ross  * deletion during avl iteration (while the lavl is locked) but that is
4462cf6b79fSGordon Ross  * not required, and an object can be posted at any time.
4472cf6b79fSGordon Ross  */
4482cf6b79fSGordon Ross void
smb_lavl_post(smb_lavl_t * la,void * object,smb_dtorproc_t dtorproc)4492cf6b79fSGordon Ross smb_lavl_post(smb_lavl_t *la, void *object, smb_dtorproc_t dtorproc)
4502cf6b79fSGordon Ross {
4512cf6b79fSGordon Ross 	smb_dtor_t	*dtor;
4522cf6b79fSGordon Ross 
4532cf6b79fSGordon Ross 	ASSERT((object != NULL) && (dtorproc != NULL));
4542cf6b79fSGordon Ross 
4552cf6b79fSGordon Ross 	dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP);
4562cf6b79fSGordon Ross 	bzero(dtor, sizeof (smb_dtor_t));
4572cf6b79fSGordon Ross 	dtor->dt_magic = SMB_DTOR_MAGIC;
4582cf6b79fSGordon Ross 	dtor->dt_object = object;
4592cf6b79fSGordon Ross 	dtor->dt_proc = dtorproc;
4602cf6b79fSGordon Ross 
4612cf6b79fSGordon Ross 	mutex_enter(&la->la_mutex);
4622cf6b79fSGordon Ross 	list_insert_tail(&la->la_deleteq, dtor);
4632cf6b79fSGordon Ross 	++la->la_deleteq_count;
4642cf6b79fSGordon Ross 	mutex_exit(&la->la_mutex);
4652cf6b79fSGordon Ross }
4662cf6b79fSGordon Ross 
4672cf6b79fSGordon Ross /*
4682cf6b79fSGordon Ross  * Exit the lavl lock and process the delete queue.
4692cf6b79fSGordon Ross  */
4702cf6b79fSGordon Ross void
smb_lavl_exit(smb_lavl_t * la)4712cf6b79fSGordon Ross smb_lavl_exit(smb_lavl_t *la)
4722cf6b79fSGordon Ross {
4732cf6b79fSGordon Ross 	rw_exit(&la->la_lock);
4742cf6b79fSGordon Ross 	smb_lavl_flush(la);
4752cf6b79fSGordon Ross }
4762cf6b79fSGordon Ross 
4772cf6b79fSGordon Ross /*
4782cf6b79fSGordon Ross  * Flush the lavl delete queue.  The mutex is dropped across the destructor
4792cf6b79fSGordon Ross  * call in case this leads to additional objects being posted to the delete
4802cf6b79fSGordon Ross  * queue.
4812cf6b79fSGordon Ross  */
4822cf6b79fSGordon Ross void
smb_lavl_flush(smb_lavl_t * la)4832cf6b79fSGordon Ross smb_lavl_flush(smb_lavl_t *la)
4842cf6b79fSGordon Ross {
4852cf6b79fSGordon Ross 	smb_dtor_t    *dtor;
4862cf6b79fSGordon Ross 
4872cf6b79fSGordon Ross 	mutex_enter(&la->la_mutex);
4882cf6b79fSGordon Ross 	if (la->la_flushing) {
4892cf6b79fSGordon Ross 		mutex_exit(&la->la_mutex);
4902cf6b79fSGordon Ross 		return;
4912cf6b79fSGordon Ross 	}
4922cf6b79fSGordon Ross 	la->la_flushing = B_TRUE;
4932cf6b79fSGordon Ross 
4942cf6b79fSGordon Ross 	dtor = list_head(&la->la_deleteq);
4952cf6b79fSGordon Ross 	while (dtor != NULL) {
4962cf6b79fSGordon Ross 		SMB_DTOR_VALID(dtor);
4972cf6b79fSGordon Ross 		ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL));
4982cf6b79fSGordon Ross 		list_remove(&la->la_deleteq, dtor);
4992cf6b79fSGordon Ross 		--la->la_deleteq_count;
5002cf6b79fSGordon Ross 		mutex_exit(&la->la_mutex);
5012cf6b79fSGordon Ross 
5022cf6b79fSGordon Ross 		dtor->dt_proc(dtor->dt_object);
5032cf6b79fSGordon Ross 
5042cf6b79fSGordon Ross 		dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC;
5052cf6b79fSGordon Ross 		kmem_cache_free(smb_dtor_cache, dtor);
5062cf6b79fSGordon Ross 		mutex_enter(&la->la_mutex);
5072cf6b79fSGordon Ross 		dtor = list_head(&la->la_deleteq);
5082cf6b79fSGordon Ross 	}
5092cf6b79fSGordon Ross 	la->la_flushing = B_FALSE;
5102cf6b79fSGordon Ross 
5112cf6b79fSGordon Ross 	mutex_exit(&la->la_mutex);
5122cf6b79fSGordon Ross }
5132cf6b79fSGordon Ross 
5142cf6b79fSGordon Ross /*
5152cf6b79fSGordon Ross  * smb_lavl_upgrade
5162cf6b79fSGordon Ross  *
5172cf6b79fSGordon Ross  * This function tries to upgrade the lock of the locked avl. It assumes the
5182cf6b79fSGordon Ross  * locked has already been entered in RW_READER mode. It first tries using the
5192cf6b79fSGordon Ross  * Solaris function rw_tryupgrade(). If that call fails the lock is released
5202cf6b79fSGordon Ross  * and reentered in RW_WRITER mode. In that last case a window is opened during
5212cf6b79fSGordon Ross  * which the contents of the avl may have changed. The return code indicates
5222cf6b79fSGordon Ross  * whether or not the avl was modified when the lock was exited.
5232cf6b79fSGordon Ross  */
smb_lavl_upgrade(smb_lavl_t * la)5242cf6b79fSGordon Ross int smb_lavl_upgrade(
5252cf6b79fSGordon Ross     smb_lavl_t *la)
5262cf6b79fSGordon Ross {
5272cf6b79fSGordon Ross 	uint64_t	wrop;
5282cf6b79fSGordon Ross 
5292cf6b79fSGordon Ross 	if (rw_tryupgrade(&la->la_lock) != 0) {
5302cf6b79fSGordon Ross 		return (0);
5312cf6b79fSGordon Ross 	}
5322cf6b79fSGordon Ross 	wrop = la->la_wrop;
5332cf6b79fSGordon Ross 	rw_exit(&la->la_lock);
5342cf6b79fSGordon Ross 	rw_enter(&la->la_lock, RW_WRITER);
5352cf6b79fSGordon Ross 	return (wrop != la->la_wrop);
5362cf6b79fSGordon Ross }
5372cf6b79fSGordon Ross 
5382cf6b79fSGordon Ross /*
5392cf6b79fSGordon Ross  * smb_lavl_insert
5402cf6b79fSGordon Ross  *
5412cf6b79fSGordon Ross  * This function inserts the object passed into the tree
5422cf6b79fSGordon Ross  * at the position determined by the AVL comparator.
5432cf6b79fSGordon Ross  */
5442cf6b79fSGordon Ross void
smb_lavl_insert(smb_lavl_t * la,void * obj)5452cf6b79fSGordon Ross smb_lavl_insert(
5462cf6b79fSGordon Ross     smb_lavl_t	*la,
5472cf6b79fSGordon Ross     void	*obj)
5482cf6b79fSGordon Ross {
5492cf6b79fSGordon Ross 	avl_add(&la->la_tree, obj);
5502cf6b79fSGordon Ross 	++la->la_wrop;
5512cf6b79fSGordon Ross }
5522cf6b79fSGordon Ross 
5532cf6b79fSGordon Ross /*
5542cf6b79fSGordon Ross  * smb_lavl_remove
5552cf6b79fSGordon Ross  *
5562cf6b79fSGordon Ross  * This function removes the object passed from the lavl. This function
5572cf6b79fSGordon Ross  * assumes the lock of the lavl has already been entered.
5582cf6b79fSGordon Ross  */
5592cf6b79fSGordon Ross void
smb_lavl_remove(smb_lavl_t * la,void * obj)5602cf6b79fSGordon Ross smb_lavl_remove(
5612cf6b79fSGordon Ross     smb_lavl_t	*la,
5622cf6b79fSGordon Ross     void	*obj)
5632cf6b79fSGordon Ross {
5642cf6b79fSGordon Ross 	avl_remove(&la->la_tree, obj);
5652cf6b79fSGordon Ross 	++la->la_wrop;
5662cf6b79fSGordon Ross }
5672cf6b79fSGordon Ross 
5682cf6b79fSGordon Ross /*
5692cf6b79fSGordon Ross  * smb_lavl_get_count
5702cf6b79fSGordon Ross  *
5712cf6b79fSGordon Ross  * This function returns the number of elements in the specified avl.
5722cf6b79fSGordon Ross  */
5732cf6b79fSGordon Ross uint32_t
smb_lavl_get_count(smb_lavl_t * la)5742cf6b79fSGordon Ross smb_lavl_get_count(
5752cf6b79fSGordon Ross     smb_lavl_t *la)
5762cf6b79fSGordon Ross {
5772cf6b79fSGordon Ross 	return ((uint32_t)avl_numnodes(&la->la_tree));
5782cf6b79fSGordon Ross }
5792cf6b79fSGordon Ross 
5809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
5819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Initialize the llist delete queue object cache.
5829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
5839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
smb_llist_init(void)5849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_init(void)
5859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
5868622ec45SGordon Ross 	if (smb_dtor_cache != NULL)
5879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return;
5889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
5899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_dtor_cache = kmem_cache_create("smb_dtor_cache",
5909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    sizeof (smb_dtor_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
5919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
5929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
5939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
5949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Destroy the llist delete queue object cache.
5959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
5969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
smb_llist_fini(void)5979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_fini(void)
5989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
5998622ec45SGordon Ross 	if (smb_dtor_cache != NULL) {
6008622ec45SGordon Ross 		kmem_cache_destroy(smb_dtor_cache);
6018622ec45SGordon Ross 		smb_dtor_cache = NULL;
6028622ec45SGordon Ross 	}
6039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
6049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
605da6c28aaSamw /*
606da6c28aaSamw  * smb_llist_constructor
607da6c28aaSamw  *
608da6c28aaSamw  * This function initializes a locked list.
609da6c28aaSamw  */
610da6c28aaSamw void
smb_llist_constructor(smb_llist_t * ll,size_t size,size_t offset)611da6c28aaSamw smb_llist_constructor(
612da6c28aaSamw     smb_llist_t	*ll,
613da6c28aaSamw     size_t	size,
614da6c28aaSamw     size_t	offset)
615da6c28aaSamw {
616da6c28aaSamw 	rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL);
6179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_init(&ll->ll_mutex, NULL, MUTEX_DEFAULT, NULL);
618da6c28aaSamw 	list_create(&ll->ll_list, size, offset);
6199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	list_create(&ll->ll_deleteq, sizeof (smb_dtor_t),
6209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    offsetof(smb_dtor_t, dt_lnd));
621da6c28aaSamw 	ll->ll_count = 0;
622da6c28aaSamw 	ll->ll_wrop = 0;
6239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ll->ll_deleteq_count = 0;
624cb174861Sjoyce mcintosh 	ll->ll_flushing = B_FALSE;
625da6c28aaSamw }
626da6c28aaSamw 
627da6c28aaSamw /*
6289fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Flush the delete queue and destroy a locked list.
629da6c28aaSamw  */
630da6c28aaSamw void
smb_llist_destructor(smb_llist_t * ll)631da6c28aaSamw smb_llist_destructor(
632da6c28aaSamw     smb_llist_t	*ll)
633da6c28aaSamw {
6349fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_flush(ll);
6359fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
636da6c28aaSamw 	ASSERT(ll->ll_count == 0);
6379fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT(ll->ll_deleteq_count == 0);
638da6c28aaSamw 
639da6c28aaSamw 	rw_destroy(&ll->ll_lock);
640da6c28aaSamw 	list_destroy(&ll->ll_list);
6419fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	list_destroy(&ll->ll_deleteq);
6429fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_destroy(&ll->ll_mutex);
6439fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
6449fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
645811599a4SMatt Barden /*
646811599a4SMatt Barden  * smb_llist_enter
647811599a4SMatt Barden  * Not a macro so dtrace smbsrv:* can see it.
648811599a4SMatt Barden  */
649811599a4SMatt Barden void
smb_llist_enter(smb_llist_t * ll,krw_t mode)650811599a4SMatt Barden smb_llist_enter(smb_llist_t *ll, krw_t mode)
651811599a4SMatt Barden {
652811599a4SMatt Barden 	rw_enter(&ll->ll_lock, mode);
653811599a4SMatt Barden }
654811599a4SMatt Barden 
6559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
6569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Post an object to the delete queue.  The delete queue will be processed
6579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * during list exit or list destruction.  Objects are often posted for
6589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * deletion during list iteration (while the list is locked) but that is
6599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * not required, and an object can be posted at any time.
6609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
6619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
smb_llist_post(smb_llist_t * ll,void * object,smb_dtorproc_t dtorproc)6629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc)
6639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
6649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_dtor_t	*dtor;
6659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
6669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	ASSERT((object != NULL) && (dtorproc != NULL));
6679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
6689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP);
6699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	bzero(dtor, sizeof (smb_dtor_t));
6709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	dtor->dt_magic = SMB_DTOR_MAGIC;
6719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	dtor->dt_object = object;
6729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	dtor->dt_proc = dtorproc;
6739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
6749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&ll->ll_mutex);
6759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	list_insert_tail(&ll->ll_deleteq, dtor);
6769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	++ll->ll_deleteq_count;
6779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&ll->ll_mutex);
6789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
6799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
6809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
6819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Exit the list lock and process the delete queue.
6829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
6839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
smb_llist_exit(smb_llist_t * ll)6849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_exit(smb_llist_t *ll)
6859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
6869fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	rw_exit(&ll->ll_lock);
6879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_flush(ll);
6889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
6899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
6909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
6919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Flush the list delete queue.  The mutex is dropped across the destructor
6929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * call in case this leads to additional objects being posted to the delete
6939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * queue.
6949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
695c5866007SKeyur Desai void
smb_llist_flush(smb_llist_t * ll)6969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_llist_flush(smb_llist_t *ll)
6979fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
6989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_dtor_t    *dtor;
6999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_enter(&ll->ll_mutex);
701cb174861Sjoyce mcintosh 	if (ll->ll_flushing) {
702cb174861Sjoyce mcintosh 		mutex_exit(&ll->ll_mutex);
703cb174861Sjoyce mcintosh 		return;
704cb174861Sjoyce mcintosh 	}
705cb174861Sjoyce mcintosh 	ll->ll_flushing = B_TRUE;
7069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	dtor = list_head(&ll->ll_deleteq);
7089fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	while (dtor != NULL) {
7099fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		SMB_DTOR_VALID(dtor);
7109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL));
7119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		list_remove(&ll->ll_deleteq, dtor);
7129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		--ll->ll_deleteq_count;
7139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		mutex_exit(&ll->ll_mutex);
7149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		dtor->dt_proc(dtor->dt_object);
7169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC;
7189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		kmem_cache_free(smb_dtor_cache, dtor);
7199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		mutex_enter(&ll->ll_mutex);
7209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		dtor = list_head(&ll->ll_deleteq);
7219fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
722cb174861Sjoyce mcintosh 	ll->ll_flushing = B_FALSE;
7239fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7249fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_exit(&ll->ll_mutex);
725da6c28aaSamw }
726da6c28aaSamw 
727da6c28aaSamw /*
728da6c28aaSamw  * smb_llist_upgrade
729da6c28aaSamw  *
730da6c28aaSamw  * This function tries to upgrade the lock of the locked list. It assumes the
731da6c28aaSamw  * locked has already been entered in RW_READER mode. It first tries using the
732da6c28aaSamw  * Solaris function rw_tryupgrade(). If that call fails the lock is released
733da6c28aaSamw  * and reentered in RW_WRITER mode. In that last case a window is opened during
734da6c28aaSamw  * which the contents of the list may have changed. The return code indicates
735da6c28aaSamw  * whether or not the list was modified when the lock was exited.
736da6c28aaSamw  */
smb_llist_upgrade(smb_llist_t * ll)737da6c28aaSamw int smb_llist_upgrade(
738da6c28aaSamw     smb_llist_t *ll)
739da6c28aaSamw {
740da6c28aaSamw 	uint64_t	wrop;
741da6c28aaSamw 
742da6c28aaSamw 	if (rw_tryupgrade(&ll->ll_lock) != 0) {
743da6c28aaSamw 		return (0);
744da6c28aaSamw 	}
745da6c28aaSamw 	wrop = ll->ll_wrop;
746da6c28aaSamw 	rw_exit(&ll->ll_lock);
747da6c28aaSamw 	rw_enter(&ll->ll_lock, RW_WRITER);
748da6c28aaSamw 	return (wrop != ll->ll_wrop);
749da6c28aaSamw }
750da6c28aaSamw 
751da6c28aaSamw /*
752da6c28aaSamw  * smb_llist_insert_head
753da6c28aaSamw  *
754da6c28aaSamw  * This function inserts the object passed a the beginning of the list. This
755da6c28aaSamw  * function assumes the lock of the list has already been entered.
756da6c28aaSamw  */
757da6c28aaSamw void
smb_llist_insert_head(smb_llist_t * ll,void * obj)758da6c28aaSamw smb_llist_insert_head(
759da6c28aaSamw     smb_llist_t	*ll,
760da6c28aaSamw     void	*obj)
761da6c28aaSamw {
762da6c28aaSamw 	list_insert_head(&ll->ll_list, obj);
763da6c28aaSamw 	++ll->ll_wrop;
764da6c28aaSamw 	++ll->ll_count;
765da6c28aaSamw }
766da6c28aaSamw 
767da6c28aaSamw /*
768da6c28aaSamw  * smb_llist_insert_tail
769da6c28aaSamw  *
770da6c28aaSamw  * This function appends to the object passed to the list. This function assumes
771da6c28aaSamw  * the lock of the list has already been entered.
772da6c28aaSamw  *
773da6c28aaSamw  */
774da6c28aaSamw void
smb_llist_insert_tail(smb_llist_t * ll,void * obj)775da6c28aaSamw smb_llist_insert_tail(
776da6c28aaSamw     smb_llist_t	*ll,
777da6c28aaSamw     void	*obj)
778da6c28aaSamw {
779da6c28aaSamw 	list_insert_tail(&ll->ll_list, obj);
780da6c28aaSamw 	++ll->ll_wrop;
781da6c28aaSamw 	++ll->ll_count;
782da6c28aaSamw }
783da6c28aaSamw 
784da6c28aaSamw /*
785da6c28aaSamw  * smb_llist_remove
786da6c28aaSamw  *
787da6c28aaSamw  * This function removes the object passed from the list. This function assumes
788da6c28aaSamw  * the lock of the list has already been entered.
789da6c28aaSamw  */
790da6c28aaSamw void
smb_llist_remove(smb_llist_t * ll,void * obj)791da6c28aaSamw smb_llist_remove(
792da6c28aaSamw     smb_llist_t	*ll,
793da6c28aaSamw     void	*obj)
794da6c28aaSamw {
795da6c28aaSamw 	list_remove(&ll->ll_list, obj);
796da6c28aaSamw 	++ll->ll_wrop;
797da6c28aaSamw 	--ll->ll_count;
798da6c28aaSamw }
799da6c28aaSamw 
800da6c28aaSamw /*
801da6c28aaSamw  * smb_llist_get_count
802da6c28aaSamw  *
803da6c28aaSamw  * This function returns the number of elements in the specified list.
804da6c28aaSamw  */
805da6c28aaSamw uint32_t
smb_llist_get_count(smb_llist_t * ll)806da6c28aaSamw smb_llist_get_count(
807da6c28aaSamw     smb_llist_t *ll)
808da6c28aaSamw {
809da6c28aaSamw 	return (ll->ll_count);
810da6c28aaSamw }
811da6c28aaSamw 
812da6c28aaSamw /*
813da6c28aaSamw  * smb_slist_constructor
814da6c28aaSamw  *
815da6c28aaSamw  * Synchronized list constructor.
816da6c28aaSamw  */
817da6c28aaSamw void
smb_slist_constructor(smb_slist_t * sl,size_t size,size_t offset)818da6c28aaSamw smb_slist_constructor(
819da6c28aaSamw     smb_slist_t	*sl,
820da6c28aaSamw     size_t	size,
821da6c28aaSamw     size_t	offset)
822da6c28aaSamw {
823da6c28aaSamw 	mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL);
824da6c28aaSamw 	cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL);
825da6c28aaSamw 	list_create(&sl->sl_list, size, offset);
826da6c28aaSamw 	sl->sl_count = 0;
827da6c28aaSamw 	sl->sl_waiting = B_FALSE;
828da6c28aaSamw }
829da6c28aaSamw 
830da6c28aaSamw /*
831da6c28aaSamw  * smb_slist_destructor
832da6c28aaSamw  *
833da6c28aaSamw  * Synchronized list destructor.
834da6c28aaSamw  */
835da6c28aaSamw void
smb_slist_destructor(smb_slist_t * sl)836da6c28aaSamw smb_slist_destructor(
837da6c28aaSamw     smb_slist_t	*sl)
838da6c28aaSamw {
839148c5f43SAlan Wright 	VERIFY(sl->sl_count == 0);
840da6c28aaSamw 
841da6c28aaSamw 	mutex_destroy(&sl->sl_mutex);
842da6c28aaSamw 	cv_destroy(&sl->sl_cv);
843da6c28aaSamw 	list_destroy(&sl->sl_list);
844da6c28aaSamw }
845da6c28aaSamw 
846811599a4SMatt Barden /*
847811599a4SMatt Barden  * smb_slist_enter
848811599a4SMatt Barden  * Not a macro so dtrace smbsrv:* can see it.
849811599a4SMatt Barden  */
850811599a4SMatt Barden void
smb_slist_enter(smb_slist_t * sl)851811599a4SMatt Barden smb_slist_enter(smb_slist_t *sl)
852811599a4SMatt Barden {
853811599a4SMatt Barden 	mutex_enter(&(sl)->sl_mutex);
854811599a4SMatt Barden }
855811599a4SMatt Barden 
856da6c28aaSamw /*
857da6c28aaSamw  * smb_slist_insert_head
858da6c28aaSamw  *
859da6c28aaSamw  * This function inserts the object passed a the beginning of the list.
860da6c28aaSamw  */
861da6c28aaSamw void
smb_slist_insert_head(smb_slist_t * sl,void * obj)862da6c28aaSamw smb_slist_insert_head(
863da6c28aaSamw     smb_slist_t	*sl,
864da6c28aaSamw     void	*obj)
865da6c28aaSamw {
866da6c28aaSamw 	mutex_enter(&sl->sl_mutex);
867da6c28aaSamw 	list_insert_head(&sl->sl_list, obj);
868da6c28aaSamw 	++sl->sl_count;
869da6c28aaSamw 	mutex_exit(&sl->sl_mutex);
870da6c28aaSamw }
871da6c28aaSamw 
872da6c28aaSamw /*
873da6c28aaSamw  * smb_slist_insert_tail
874da6c28aaSamw  *
875da6c28aaSamw  * This function appends the object passed to the list.
876da6c28aaSamw  */
877da6c28aaSamw void
smb_slist_insert_tail(smb_slist_t * sl,void * obj)878da6c28aaSamw smb_slist_insert_tail(
879da6c28aaSamw     smb_slist_t	*sl,
880da6c28aaSamw     void	*obj)
881da6c28aaSamw {
882da6c28aaSamw 	mutex_enter(&sl->sl_mutex);
883da6c28aaSamw 	list_insert_tail(&sl->sl_list, obj);
884da6c28aaSamw 	++sl->sl_count;
885da6c28aaSamw 	mutex_exit(&sl->sl_mutex);
886da6c28aaSamw }
887da6c28aaSamw 
888da6c28aaSamw /*
889da6c28aaSamw  * smb_llist_remove
890da6c28aaSamw  *
891da6c28aaSamw  * This function removes the object passed by the caller from the list.
892da6c28aaSamw  */
893da6c28aaSamw void
smb_slist_remove(smb_slist_t * sl,void * obj)894da6c28aaSamw smb_slist_remove(
895da6c28aaSamw     smb_slist_t	*sl,
896da6c28aaSamw     void	*obj)
897da6c28aaSamw {
898da6c28aaSamw 	mutex_enter(&sl->sl_mutex);
899da6c28aaSamw 	list_remove(&sl->sl_list, obj);
900da6c28aaSamw 	if ((--sl->sl_count == 0) && (sl->sl_waiting)) {
901da6c28aaSamw 		sl->sl_waiting = B_FALSE;
902da6c28aaSamw 		cv_broadcast(&sl->sl_cv);
903da6c28aaSamw 	}
904da6c28aaSamw 	mutex_exit(&sl->sl_mutex);
905da6c28aaSamw }
906da6c28aaSamw 
907da6c28aaSamw /*
908da6c28aaSamw  * smb_slist_move_tail
909da6c28aaSamw  *
910da6c28aaSamw  * This function transfers all the contents of the synchronized list to the
911da6c28aaSamw  * list_t provided. It returns the number of objects transferred.
912da6c28aaSamw  */
913da6c28aaSamw uint32_t
smb_slist_move_tail(list_t * lst,smb_slist_t * sl)914da6c28aaSamw smb_slist_move_tail(
915da6c28aaSamw     list_t	*lst,
916da6c28aaSamw     smb_slist_t	*sl)
917da6c28aaSamw {
918da6c28aaSamw 	uint32_t	rv;
919da6c28aaSamw 
920da6c28aaSamw 	mutex_enter(&sl->sl_mutex);
921da6c28aaSamw 	rv = sl->sl_count;
922da6c28aaSamw 	if (sl->sl_count) {
923da6c28aaSamw 		list_move_tail(lst, &sl->sl_list);
924da6c28aaSamw 		sl->sl_count = 0;
925da6c28aaSamw 		if (sl->sl_waiting) {
926da6c28aaSamw 			sl->sl_waiting = B_FALSE;
927da6c28aaSamw 			cv_broadcast(&sl->sl_cv);
928da6c28aaSamw 		}
929da6c28aaSamw 	}
930da6c28aaSamw 	mutex_exit(&sl->sl_mutex);
931da6c28aaSamw 	return (rv);
932da6c28aaSamw }
933da6c28aaSamw 
934da6c28aaSamw /*
935da6c28aaSamw  * smb_slist_obj_move
936da6c28aaSamw  *
937da6c28aaSamw  * This function moves an object from one list to the end of the other list. It
938da6c28aaSamw  * assumes the mutex of each list has been entered.
939da6c28aaSamw  */
940da6c28aaSamw void
smb_slist_obj_move(smb_slist_t * dst,smb_slist_t * src,void * obj)941da6c28aaSamw smb_slist_obj_move(
942da6c28aaSamw     smb_slist_t	*dst,
943da6c28aaSamw     smb_slist_t	*src,
944da6c28aaSamw     void	*obj)
945da6c28aaSamw {
946da6c28aaSamw 	ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset);
947da6c28aaSamw 	ASSERT(dst->sl_list.list_size == src->sl_list.list_size);
948da6c28aaSamw 
949da6c28aaSamw 	list_remove(&src->sl_list, obj);
950da6c28aaSamw 	list_insert_tail(&dst->sl_list, obj);
951da6c28aaSamw 	dst->sl_count++;
952da6c28aaSamw 	src->sl_count--;
953da6c28aaSamw 	if ((src->sl_count == 0) && (src->sl_waiting)) {
954da6c28aaSamw 		src->sl_waiting = B_FALSE;
955da6c28aaSamw 		cv_broadcast(&src->sl_cv);
956da6c28aaSamw 	}
957da6c28aaSamw }
958da6c28aaSamw 
959da6c28aaSamw /*
960da6c28aaSamw  * smb_slist_wait_for_empty
961da6c28aaSamw  *
962da6c28aaSamw  * This function waits for a list to be emptied.
963da6c28aaSamw  */
964da6c28aaSamw void
smb_slist_wait_for_empty(smb_slist_t * sl)965da6c28aaSamw smb_slist_wait_for_empty(
966da6c28aaSamw     smb_slist_t	*sl)
967da6c28aaSamw {
968da6c28aaSamw 	mutex_enter(&sl->sl_mutex);
969da6c28aaSamw 	while (sl->sl_count) {
970da6c28aaSamw 		sl->sl_waiting = B_TRUE;
971da6c28aaSamw 		cv_wait(&sl->sl_cv, &sl->sl_mutex);
972da6c28aaSamw 	}
973da6c28aaSamw 	mutex_exit(&sl->sl_mutex);
974da6c28aaSamw }
975da6c28aaSamw 
976da6c28aaSamw /*
977da6c28aaSamw  * smb_slist_exit
978da6c28aaSamw  *
979da6c28aaSamw  * This function exits the muetx of the list and signal the condition variable
980da6c28aaSamw  * if the list is empty.
981da6c28aaSamw  */
982da6c28aaSamw void
smb_slist_exit(smb_slist_t * sl)983da6c28aaSamw smb_slist_exit(smb_slist_t *sl)
984da6c28aaSamw {
985da6c28aaSamw 	if ((sl->sl_count == 0) && (sl->sl_waiting)) {
986da6c28aaSamw 		sl->sl_waiting = B_FALSE;
987da6c28aaSamw 		cv_broadcast(&sl->sl_cv);
988da6c28aaSamw 	}
989da6c28aaSamw 	mutex_exit(&sl->sl_mutex);
990da6c28aaSamw }
991da6c28aaSamw 
992b819cea2SGordon Ross /* smb_thread_... moved to smb_thread.c */
993da6c28aaSamw 
994da6c28aaSamw /*
995da6c28aaSamw  * smb_rwx_init
996da6c28aaSamw  */
997da6c28aaSamw void
smb_rwx_init(smb_rwx_t * rwx)998da6c28aaSamw smb_rwx_init(
999da6c28aaSamw     smb_rwx_t	*rwx)
1000da6c28aaSamw {
1001da6c28aaSamw 	bzero(rwx, sizeof (smb_rwx_t));
1002da6c28aaSamw 	cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL);
1003da6c28aaSamw 	mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
1004da6c28aaSamw 	rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
1005da6c28aaSamw }
1006da6c28aaSamw 
1007da6c28aaSamw /*
1008da6c28aaSamw  * smb_rwx_destroy
1009da6c28aaSamw  */
1010da6c28aaSamw void
smb_rwx_destroy(smb_rwx_t * rwx)1011da6c28aaSamw smb_rwx_destroy(
1012da6c28aaSamw     smb_rwx_t	*rwx)
1013da6c28aaSamw {
1014da6c28aaSamw 	mutex_destroy(&rwx->rwx_mutex);
1015da6c28aaSamw 	cv_destroy(&rwx->rwx_cv);
1016da6c28aaSamw 	rw_destroy(&rwx->rwx_lock);
1017da6c28aaSamw }
1018da6c28aaSamw 
1019da6c28aaSamw /*
1020811599a4SMatt Barden  * smb_rwx_rwenter
1021da6c28aaSamw  */
1022da6c28aaSamw void
smb_rwx_rwenter(smb_rwx_t * rwx,krw_t mode)1023811599a4SMatt Barden smb_rwx_rwenter(smb_rwx_t *rwx, krw_t mode)
1024da6c28aaSamw {
1025811599a4SMatt Barden 	rw_enter(&rwx->rwx_lock, mode);
1026da6c28aaSamw }
1027da6c28aaSamw 
1028da6c28aaSamw /*
1029811599a4SMatt Barden  * smb_rwx_rwexit
1030da6c28aaSamw  */
1031811599a4SMatt Barden void
smb_rwx_rwexit(smb_rwx_t * rwx)1032811599a4SMatt Barden smb_rwx_rwexit(
1033da6c28aaSamw     smb_rwx_t	*rwx)
1034da6c28aaSamw {
1035811599a4SMatt Barden 	rw_exit(&rwx->rwx_lock);
1036da6c28aaSamw }
1037da6c28aaSamw 
1038da6c28aaSamw 
1039da6c28aaSamw /*
1040811599a4SMatt Barden  * smb_rwx_cvwait
1041da6c28aaSamw  *
1042811599a4SMatt Barden  * Wait on rwx->rw_cv, dropping the rw lock and retake after wakeup.
1043811599a4SMatt Barden  * Assumes the smb_rwx lock was entered in RW_READER or RW_WRITER
1044da6c28aaSamw  * mode. It will:
1045da6c28aaSamw  *
1046da6c28aaSamw  *	1) release the lock and save its current mode.
1047811599a4SMatt Barden  *	2) wait until the condition variable is signaled.
1048da6c28aaSamw  *	3) re-acquire the lock in the mode saved in (1).
1049811599a4SMatt Barden  *
1050811599a4SMatt Barden  * Lock order: rwlock, mutex
1051da6c28aaSamw  */
1052da6c28aaSamw int
smb_rwx_cvwait(smb_rwx_t * rwx,clock_t timeout)1053811599a4SMatt Barden smb_rwx_cvwait(
1054da6c28aaSamw     smb_rwx_t	*rwx,
1055da6c28aaSamw     clock_t	timeout)
1056da6c28aaSamw {
1057da6c28aaSamw 	krw_t	mode;
1058b819cea2SGordon Ross 	int	rc = 1;
1059da6c28aaSamw 
1060da6c28aaSamw 	if (rw_write_held(&rwx->rwx_lock)) {
1061da6c28aaSamw 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
1062da6c28aaSamw 		mode = RW_WRITER;
1063da6c28aaSamw 	} else {
1064da6c28aaSamw 		ASSERT(rw_read_held(&rwx->rwx_lock));
1065da6c28aaSamw 		mode = RW_READER;
1066da6c28aaSamw 	}
1067da6c28aaSamw 
1068da6c28aaSamw 	mutex_enter(&rwx->rwx_mutex);
1069811599a4SMatt Barden 	rw_exit(&rwx->rwx_lock);
1070811599a4SMatt Barden 
1071811599a4SMatt Barden 	rwx->rwx_waiting = B_TRUE;
1072811599a4SMatt Barden 	if (timeout == -1) {
1073811599a4SMatt Barden 		cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
1074811599a4SMatt Barden 	} else {
1075811599a4SMatt Barden 		rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
1076811599a4SMatt Barden 		    timeout, TR_CLOCK_TICK);
1077da6c28aaSamw 	}
1078da6c28aaSamw 	mutex_exit(&rwx->rwx_mutex);
1079da6c28aaSamw 
1080da6c28aaSamw 	rw_enter(&rwx->rwx_lock, mode);
1081da6c28aaSamw 	return (rc);
1082da6c28aaSamw }
1083da6c28aaSamw 
1084811599a4SMatt Barden /*
1085811599a4SMatt Barden  * smb_rwx_cvbcast
1086811599a4SMatt Barden  *
1087811599a4SMatt Barden  * Wake up threads waiting on rx_cv
1088811599a4SMatt Barden  * The rw lock may or may not be held.
1089811599a4SMatt Barden  * The mutex MUST NOT be held.
1090811599a4SMatt Barden  */
1091811599a4SMatt Barden void
smb_rwx_cvbcast(smb_rwx_t * rwx)1092811599a4SMatt Barden smb_rwx_cvbcast(smb_rwx_t *rwx)
1093811599a4SMatt Barden {
1094811599a4SMatt Barden 	mutex_enter(&rwx->rwx_mutex);
1095811599a4SMatt Barden 	if (rwx->rwx_waiting) {
1096811599a4SMatt Barden 		rwx->rwx_waiting = B_FALSE;
1097811599a4SMatt Barden 		cv_broadcast(&rwx->rwx_cv);
1098811599a4SMatt Barden 	}
1099811599a4SMatt Barden 	mutex_exit(&rwx->rwx_mutex);
1100811599a4SMatt Barden }
1101811599a4SMatt Barden 
1102b819cea2SGordon Ross /* smb_idmap_... moved to smb_idmap.c */
1103da6c28aaSamw 
1104da6c28aaSamw uint64_t
smb_time_unix_to_nt(timestruc_t * unix_time)1105e3f2c991SKeyur Desai smb_time_unix_to_nt(timestruc_t *unix_time)
1106da6c28aaSamw {
1107da6c28aaSamw 	uint64_t nt_time;
1108da6c28aaSamw 
1109e3f2c991SKeyur Desai 	if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
1110e3f2c991SKeyur Desai 		return (0);
1111e3f2c991SKeyur Desai 
1112da6c28aaSamw 	nt_time = unix_time->tv_sec;
1113da6c28aaSamw 	nt_time *= 10000000;  /* seconds to 100ns */
1114da6c28aaSamw 	nt_time += unix_time->tv_nsec / 100;
1115da6c28aaSamw 	return (nt_time + NT_TIME_BIAS);
1116da6c28aaSamw }
1117da6c28aaSamw 
1118*b62fa64bSToomas Soome const timestruc_t smb_nttime_m1 = { -1, -1 }; /* minus 1 */
1119*b62fa64bSToomas Soome const timestruc_t smb_nttime_m2 = { -1, -2 }; /* minus 2 */
1120*b62fa64bSToomas Soome 
1121e3f2c991SKeyur Desai void
smb_time_nt_to_unix(uint64_t nt_time,timestruc_t * unix_time)1122e3f2c991SKeyur Desai smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
1123da6c28aaSamw {
1124*b62fa64bSToomas Soome 	static const timestruc_t tzero = { 0, 0 };
1125da6c28aaSamw 	uint32_t seconds;
1126da6c28aaSamw 
1127e3f2c991SKeyur Desai 	ASSERT(unix_time);
1128e3f2c991SKeyur Desai 
1129*b62fa64bSToomas Soome 	/*
1130*b62fa64bSToomas Soome 	 * NT time values (0, -1, -2) get special treatment in SMB.
1131*b62fa64bSToomas Soome 	 * See notes above smb_node_setattr() for details.
1132*b62fa64bSToomas Soome 	 */
1133*b62fa64bSToomas Soome 	if (nt_time == 0) {
1134*b62fa64bSToomas Soome 		*unix_time = tzero;
1135*b62fa64bSToomas Soome 		return;
1136*b62fa64bSToomas Soome 	}
1137*b62fa64bSToomas Soome 	if ((int64_t)nt_time == -1) {
1138*b62fa64bSToomas Soome 		*unix_time = smb_nttime_m1;
1139*b62fa64bSToomas Soome 		return;
1140*b62fa64bSToomas Soome 	}
1141*b62fa64bSToomas Soome 	if ((int64_t)nt_time == -2) {
1142*b62fa64bSToomas Soome 		*unix_time = smb_nttime_m2;
1143e3f2c991SKeyur Desai 		return;
1144e3f2c991SKeyur Desai 	}
1145e3f2c991SKeyur Desai 
1146b6f078edSGordon Ross 	/*
1147b6f078edSGordon Ross 	 * Can't represent times less than or equal NT_TIME_BIAS,
1148b6f078edSGordon Ross 	 * so convert them to the oldest date we can store.
1149b6f078edSGordon Ross 	 * Note that time zero is "special" being converted
1150b6f078edSGordon Ross 	 * both directions as 0:0 (unix-to-nt, nt-to-unix).
1151b6f078edSGordon Ross 	 */
1152b6f078edSGordon Ross 	if (nt_time <= NT_TIME_BIAS) {
1153b6f078edSGordon Ross 		unix_time->tv_sec = 0;
1154b6f078edSGordon Ross 		unix_time->tv_nsec = 100;
1155b6f078edSGordon Ross 		return;
1156b6f078edSGordon Ross 	}
1157b6f078edSGordon Ross 
1158da6c28aaSamw 	nt_time -= NT_TIME_BIAS;
1159da6c28aaSamw 	seconds = nt_time / 10000000;
1160e3f2c991SKeyur Desai 	unix_time->tv_sec = seconds;
1161e3f2c991SKeyur Desai 	unix_time->tv_nsec = (nt_time  % 10000000) * 100;
1162e3f2c991SKeyur Desai }
1163e3f2c991SKeyur Desai 
1164e3f2c991SKeyur Desai /*
1165e3f2c991SKeyur Desai  * smb_time_gmt_to_local, smb_time_local_to_gmt
1166e3f2c991SKeyur Desai  *
1167e3f2c991SKeyur Desai  * Apply the gmt offset to convert between local time and gmt
1168e3f2c991SKeyur Desai  */
1169e3f2c991SKeyur Desai int32_t
smb_time_gmt_to_local(smb_request_t * sr,int32_t gmt)1170e3f2c991SKeyur Desai smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt)
1171e3f2c991SKeyur Desai {
1172e3f2c991SKeyur Desai 	if ((gmt == 0) || (gmt == -1))
1173e3f2c991SKeyur Desai 		return (0);
1174e3f2c991SKeyur Desai 
1175e3f2c991SKeyur Desai 	return (gmt - sr->sr_gmtoff);
1176da6c28aaSamw }
1177da6c28aaSamw 
1178e3f2c991SKeyur Desai int32_t
smb_time_local_to_gmt(smb_request_t * sr,int32_t local)1179e3f2c991SKeyur Desai smb_time_local_to_gmt(smb_request_t *sr, int32_t local)
1180e3f2c991SKeyur Desai {
1181e3f2c991SKeyur Desai 	if ((local == 0) || (local == -1))
1182e3f2c991SKeyur Desai 		return (0);
1183e3f2c991SKeyur Desai 
1184e3f2c991SKeyur Desai 	return (local + sr->sr_gmtoff);
1185e3f2c991SKeyur Desai }
1186e3f2c991SKeyur Desai 
1187e3f2c991SKeyur Desai 
1188c8ec8eeaSjose borrego /*
1189e3f2c991SKeyur Desai  * smb_time_dos_to_unix
1190c8ec8eeaSjose borrego  *
1191c8ec8eeaSjose borrego  * Convert SMB_DATE & SMB_TIME values to a unix timestamp.
1192c8ec8eeaSjose borrego  *
1193c8ec8eeaSjose borrego  * A date/time field of 0 means that that server file system
1194c8ec8eeaSjose borrego  * assigned value need not be changed. The behaviour when the
1195c8ec8eeaSjose borrego  * date/time field is set to -1 is not documented but is
1196c8ec8eeaSjose borrego  * generally treated like 0.
1197c8ec8eeaSjose borrego  * If date or time is 0 or -1 the unix time is returned as 0
1198c8ec8eeaSjose borrego  * so that the caller can identify and handle this special case.
1199c8ec8eeaSjose borrego  */
1200c8ec8eeaSjose borrego int32_t
smb_time_dos_to_unix(int16_t date,int16_t time)1201e3f2c991SKeyur Desai smb_time_dos_to_unix(int16_t date, int16_t time)
1202da6c28aaSamw {
1203da6c28aaSamw 	struct tm	atm;
1204da6c28aaSamw 
1205c8ec8eeaSjose borrego 	if (((date == 0) || (time == 0)) ||
1206c8ec8eeaSjose borrego 	    ((date == -1) || (time == -1))) {
1207c8ec8eeaSjose borrego 		return (0);
1208c8ec8eeaSjose borrego 	}
1209c8ec8eeaSjose borrego 
1210da6c28aaSamw 	atm.tm_year = ((date >>  9) & 0x3F) + 80;
1211da6c28aaSamw 	atm.tm_mon  = ((date >>  5) & 0x0F) - 1;
1212da6c28aaSamw 	atm.tm_mday = ((date >>  0) & 0x1F);
1213da6c28aaSamw 	atm.tm_hour = ((time >> 11) & 0x1F);
1214da6c28aaSamw 	atm.tm_min  = ((time >>  5) & 0x3F);
1215da6c28aaSamw 	atm.tm_sec  = ((time >>  0) & 0x1F) << 1;
1216da6c28aaSamw 
1217da6c28aaSamw 	return (smb_timegm(&atm));
1218da6c28aaSamw }
1219da6c28aaSamw 
1220e3f2c991SKeyur Desai void
smb_time_unix_to_dos(int32_t ux_time,int16_t * date_p,int16_t * time_p)1221e3f2c991SKeyur Desai smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p)
1222da6c28aaSamw {
1223da6c28aaSamw 	struct tm	atm;
1224da6c28aaSamw 	int		i;
1225da6c28aaSamw 	time_t		tmp_time;
1226da6c28aaSamw 
1227e3f2c991SKeyur Desai 	if (ux_time == 0) {
1228e3f2c991SKeyur Desai 		*date_p = 0;
1229e3f2c991SKeyur Desai 		*time_p = 0;
1230e3f2c991SKeyur Desai 		return;
1231e3f2c991SKeyur Desai 	}
1232e3f2c991SKeyur Desai 
1233da6c28aaSamw 	tmp_time = (time_t)ux_time;
1234da6c28aaSamw 	(void) smb_gmtime_r(&tmp_time, &atm);
1235da6c28aaSamw 
1236da6c28aaSamw 	if (date_p) {
1237da6c28aaSamw 		i = 0;
1238da6c28aaSamw 		i += atm.tm_year - 80;
1239da6c28aaSamw 		i <<= 4;
1240da6c28aaSamw 		i += atm.tm_mon + 1;
1241da6c28aaSamw 		i <<= 5;
1242da6c28aaSamw 		i += atm.tm_mday;
1243da6c28aaSamw 
1244da6c28aaSamw 		*date_p = (short)i;
1245da6c28aaSamw 	}
1246da6c28aaSamw 	if (time_p) {
1247da6c28aaSamw 		i = 0;
1248da6c28aaSamw 		i += atm.tm_hour;
1249da6c28aaSamw 		i <<= 6;
1250da6c28aaSamw 		i += atm.tm_min;
1251da6c28aaSamw 		i <<= 5;
1252da6c28aaSamw 		i += atm.tm_sec >> 1;
1253da6c28aaSamw 
1254da6c28aaSamw 		*time_p = (short)i;
1255da6c28aaSamw 	}
1256da6c28aaSamw }
1257da6c28aaSamw 
1258da6c28aaSamw 
1259da6c28aaSamw /*
1260da6c28aaSamw  * smb_gmtime_r
1261da6c28aaSamw  *
1262da6c28aaSamw  * Thread-safe version of smb_gmtime. Returns a null pointer if either
1263da6c28aaSamw  * input parameter is a null pointer. Otherwise returns a pointer
1264da6c28aaSamw  * to result.
1265da6c28aaSamw  *
1266da6c28aaSamw  * Day of the week calculation: the Epoch was a thursday.
1267da6c28aaSamw  *
1268da6c28aaSamw  * There are no timezone corrections so tm_isdst and tm_gmtoff are
1269da6c28aaSamw  * always zero, and the zone is always WET.
1270da6c28aaSamw  */
1271da6c28aaSamw struct tm *
smb_gmtime_r(time_t * clock,struct tm * result)1272da6c28aaSamw smb_gmtime_r(time_t *clock, struct tm *result)
1273da6c28aaSamw {
1274da6c28aaSamw 	time_t tsec;
1275da6c28aaSamw 	int year;
1276da6c28aaSamw 	int month;
1277da6c28aaSamw 	int sec_per_month;
1278da6c28aaSamw 
1279da6c28aaSamw 	if (clock == 0 || result == 0)
1280da6c28aaSamw 		return (0);
1281da6c28aaSamw 
1282da6c28aaSamw 	bzero(result, sizeof (struct tm));
1283da6c28aaSamw 	tsec = *clock;
1284da6c28aaSamw 	tsec -= tzh_leapcnt;
1285da6c28aaSamw 
1286da6c28aaSamw 	result->tm_wday = tsec / SECSPERDAY;
1287da6c28aaSamw 	result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK;
1288da6c28aaSamw 
1289da6c28aaSamw 	year = EPOCH_YEAR;
1290da6c28aaSamw 	while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) :
1291da6c28aaSamw 	    (SECSPERDAY * DAYSPERNYEAR))) {
1292da6c28aaSamw 		if (isleap(year))
1293da6c28aaSamw 			tsec -= SECSPERDAY * DAYSPERLYEAR;
1294da6c28aaSamw 		else
1295da6c28aaSamw 			tsec -= SECSPERDAY * DAYSPERNYEAR;
1296da6c28aaSamw 
1297da6c28aaSamw 		++year;
1298da6c28aaSamw 	}
1299da6c28aaSamw 
1300da6c28aaSamw 	result->tm_year = year - TM_YEAR_BASE;
1301da6c28aaSamw 	result->tm_yday = tsec / SECSPERDAY;
1302da6c28aaSamw 
1303da6c28aaSamw 	for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) {
1304da6c28aaSamw 		sec_per_month = days_in_month[month] * SECSPERDAY;
1305da6c28aaSamw 
1306da6c28aaSamw 		if (month == TM_FEBRUARY && isleap(year))
1307da6c28aaSamw 			sec_per_month += SECSPERDAY;
1308da6c28aaSamw 
1309da6c28aaSamw 		if (tsec < sec_per_month)
1310da6c28aaSamw 			break;
1311da6c28aaSamw 
1312da6c28aaSamw 		tsec -= sec_per_month;
1313da6c28aaSamw 	}
1314da6c28aaSamw 
1315da6c28aaSamw 	result->tm_mon = month;
1316da6c28aaSamw 	result->tm_mday = (tsec / SECSPERDAY) + 1;
1317da6c28aaSamw 	tsec %= SECSPERDAY;
1318da6c28aaSamw 	result->tm_sec = tsec % 60;
1319da6c28aaSamw 	tsec /= 60;
1320da6c28aaSamw 	result->tm_min = tsec % 60;
1321da6c28aaSamw 	tsec /= 60;
1322da6c28aaSamw 	result->tm_hour = (int)tsec;
1323da6c28aaSamw 
1324da6c28aaSamw 	return (result);
1325da6c28aaSamw }
1326da6c28aaSamw 
1327da6c28aaSamw 
1328da6c28aaSamw /*
1329da6c28aaSamw  * smb_timegm
1330da6c28aaSamw  *
1331da6c28aaSamw  * Converts the broken-down time in tm to a time value, i.e. the number
1332da6c28aaSamw  * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is
1333da6c28aaSamw  * not a POSIX or ANSI function. Per the man page, the input values of
1334da6c28aaSamw  * tm_wday and tm_yday are ignored and, as the input data is assumed to
1335da6c28aaSamw  * represent GMT, we force tm_isdst and tm_gmtoff to 0.
1336da6c28aaSamw  *
1337da6c28aaSamw  * Before returning the clock time, we use smb_gmtime_r to set up tm_wday
1338da6c28aaSamw  * and tm_yday, and bring the other fields within normal range. I don't
1339da6c28aaSamw  * think this is really how it should be done but it's convenient for
1340da6c28aaSamw  * now.
1341da6c28aaSamw  */
1342da6c28aaSamw time_t
smb_timegm(struct tm * tm)1343da6c28aaSamw smb_timegm(struct tm *tm)
1344da6c28aaSamw {
1345da6c28aaSamw 	time_t tsec;
1346da6c28aaSamw 	int dd;
1347da6c28aaSamw 	int mm;
1348da6c28aaSamw 	int yy;
1349da6c28aaSamw 	int year;
1350da6c28aaSamw 
1351da6c28aaSamw 	if (tm == 0)
1352da6c28aaSamw 		return (-1);
1353da6c28aaSamw 
1354da6c28aaSamw 	year = tm->tm_year + TM_YEAR_BASE;
1355da6c28aaSamw 	tsec = tzh_leapcnt;
1356da6c28aaSamw 
1357da6c28aaSamw 	for (yy = EPOCH_YEAR; yy < year; ++yy) {
1358da6c28aaSamw 		if (isleap(yy))
1359da6c28aaSamw 			tsec += SECSPERDAY * DAYSPERLYEAR;
1360da6c28aaSamw 		else
1361da6c28aaSamw 			tsec += SECSPERDAY * DAYSPERNYEAR;
1362da6c28aaSamw 	}
1363da6c28aaSamw 
1364da6c28aaSamw 	for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) {
1365da6c28aaSamw 		dd = days_in_month[mm] * SECSPERDAY;
1366da6c28aaSamw 
1367da6c28aaSamw 		if (mm == TM_FEBRUARY && isleap(year))
1368da6c28aaSamw 			dd += SECSPERDAY;
1369da6c28aaSamw 
1370da6c28aaSamw 		tsec += dd;
1371da6c28aaSamw 	}
1372da6c28aaSamw 
1373da6c28aaSamw 	tsec += (tm->tm_mday - 1) * SECSPERDAY;
1374da6c28aaSamw 	tsec += tm->tm_sec;
1375da6c28aaSamw 	tsec += tm->tm_min * SECSPERMIN;
1376da6c28aaSamw 	tsec += tm->tm_hour * SECSPERHOUR;
1377da6c28aaSamw 
1378da6c28aaSamw 	tm->tm_isdst = 0;
1379da6c28aaSamw 	(void) smb_gmtime_r(&tsec, tm);
1380da6c28aaSamw 	return (tsec);
1381da6c28aaSamw }
1382da6c28aaSamw 
1383da6c28aaSamw /*
1384148c5f43SAlan Wright  * smb_pad_align
1385da6c28aaSamw  *
1386148c5f43SAlan Wright  * Returns the number of bytes required to pad an offset to the
1387148c5f43SAlan Wright  * specified alignment.
1388da6c28aaSamw  */
1389148c5f43SAlan Wright uint32_t
smb_pad_align(uint32_t offset,uint32_t align)1390148c5f43SAlan Wright smb_pad_align(uint32_t offset, uint32_t align)
1391da6c28aaSamw {
1392148c5f43SAlan Wright 	uint32_t pad = offset % align;
1393da6c28aaSamw 
1394148c5f43SAlan Wright 	if (pad != 0)
1395148c5f43SAlan Wright 		pad = align - pad;
1396da6c28aaSamw 
1397148c5f43SAlan Wright 	return (pad);
1398da6c28aaSamw }
1399da6c28aaSamw 
1400da6c28aaSamw /*
1401148c5f43SAlan Wright  * smb_panic
1402da6c28aaSamw  *
1403148c5f43SAlan Wright  * Logs the file name, function name and line number passed in and panics the
1404148c5f43SAlan Wright  * system.
1405da6c28aaSamw  */
1406148c5f43SAlan Wright void
smb_panic(char * file,const char * func,int line)1407148c5f43SAlan Wright smb_panic(char *file, const char *func, int line)
1408da6c28aaSamw {
1409148c5f43SAlan Wright 	cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line);
1410148c5f43SAlan Wright }
1411148c5f43SAlan Wright 
1412148c5f43SAlan Wright /*
1413148c5f43SAlan Wright  * Creates an AVL tree and initializes the given smb_avl_t
1414148c5f43SAlan Wright  * structure using the passed args
1415148c5f43SAlan Wright  */
1416148c5f43SAlan Wright void
smb_avl_create(smb_avl_t * avl,size_t size,size_t offset,const smb_avl_nops_t * ops)14178622ec45SGordon Ross smb_avl_create(smb_avl_t *avl, size_t size, size_t offset,
14182cf6b79fSGordon Ross     const smb_avl_nops_t *ops)
1419148c5f43SAlan Wright {
1420148c5f43SAlan Wright 	ASSERT(avl);
1421148c5f43SAlan Wright 	ASSERT(ops);
1422da6c28aaSamw 
1423148c5f43SAlan Wright 	rw_init(&avl->avl_lock, NULL, RW_DEFAULT, NULL);
1424148c5f43SAlan Wright 	mutex_init(&avl->avl_mutex, NULL, MUTEX_DEFAULT, NULL);
1425da6c28aaSamw 
1426148c5f43SAlan Wright 	avl->avl_nops = ops;
1427148c5f43SAlan Wright 	avl->avl_state = SMB_AVL_STATE_READY;
1428148c5f43SAlan Wright 	avl->avl_refcnt = 0;
1429148c5f43SAlan Wright 	(void) random_get_pseudo_bytes((uint8_t *)&avl->avl_sequence,
1430148c5f43SAlan Wright 	    sizeof (uint32_t));
1431da6c28aaSamw 
1432148c5f43SAlan Wright 	avl_create(&avl->avl_tree, ops->avln_cmp, size, offset);
1433da6c28aaSamw }
1434da6c28aaSamw 
1435da6c28aaSamw /*
1436148c5f43SAlan Wright  * Destroys the specified AVL tree.
1437148c5f43SAlan Wright  * It waits for all the in-flight operations to finish
1438148c5f43SAlan Wright  * before destroying the AVL.
1439da6c28aaSamw  */
1440148c5f43SAlan Wright void
smb_avl_destroy(smb_avl_t * avl)1441148c5f43SAlan Wright smb_avl_destroy(smb_avl_t *avl)
1442da6c28aaSamw {
1443148c5f43SAlan Wright 	void *cookie = NULL;
1444148c5f43SAlan Wright 	void *node;
1445da6c28aaSamw 
1446148c5f43SAlan Wright 	ASSERT(avl);
14479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1448148c5f43SAlan Wright 	mutex_enter(&avl->avl_mutex);
1449148c5f43SAlan Wright 	if (avl->avl_state != SMB_AVL_STATE_READY) {
1450148c5f43SAlan Wright 		mutex_exit(&avl->avl_mutex);
1451148c5f43SAlan Wright 		return;
1452148c5f43SAlan Wright 	}
1453da6c28aaSamw 
1454148c5f43SAlan Wright 	avl->avl_state = SMB_AVL_STATE_DESTROYING;
1455da6c28aaSamw 
1456148c5f43SAlan Wright 	while (avl->avl_refcnt > 0)
1457148c5f43SAlan Wright 		(void) cv_wait(&avl->avl_cv, &avl->avl_mutex);
1458148c5f43SAlan Wright 	mutex_exit(&avl->avl_mutex);
14599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1460148c5f43SAlan Wright 	rw_enter(&avl->avl_lock, RW_WRITER);
1461148c5f43SAlan Wright 	while ((node = avl_destroy_nodes(&avl->avl_tree, &cookie)) != NULL)
1462148c5f43SAlan Wright 		avl->avl_nops->avln_destroy(node);
1463da6c28aaSamw 
1464148c5f43SAlan Wright 	avl_destroy(&avl->avl_tree);
1465148c5f43SAlan Wright 	rw_exit(&avl->avl_lock);
1466da6c28aaSamw 
1467148c5f43SAlan Wright 	rw_destroy(&avl->avl_lock);
1468148c5f43SAlan Wright 
1469148c5f43SAlan Wright 	mutex_destroy(&avl->avl_mutex);
1470148c5f43SAlan Wright 	bzero(avl, sizeof (smb_avl_t));
1471148c5f43SAlan Wright }
1472da6c28aaSamw 
1473148c5f43SAlan Wright /*
1474148c5f43SAlan Wright  * Adds the given item to the AVL if it's
1475148c5f43SAlan Wright  * not already there.
1476148c5f43SAlan Wright  *
1477148c5f43SAlan Wright  * Returns:
1478148c5f43SAlan Wright  *
1479811599a4SMatt Barden  *	ENOTACTIVE	AVL is not in READY state
1480811599a4SMatt Barden  *	EEXIST		The item is already in AVL
1481148c5f43SAlan Wright  */
1482148c5f43SAlan Wright int
smb_avl_add(smb_avl_t * avl,void * item)1483148c5f43SAlan Wright smb_avl_add(smb_avl_t *avl, void *item)
1484148c5f43SAlan Wright {
1485148c5f43SAlan Wright 	avl_index_t where;
1486da6c28aaSamw 
1487148c5f43SAlan Wright 	ASSERT(avl);
1488148c5f43SAlan Wright 	ASSERT(item);
1489da6c28aaSamw 
1490148c5f43SAlan Wright 	if (!smb_avl_hold(avl))
1491148c5f43SAlan Wright 		return (ENOTACTIVE);
1492da6c28aaSamw 
1493148c5f43SAlan Wright 	rw_enter(&avl->avl_lock, RW_WRITER);
1494148c5f43SAlan Wright 	if (avl_find(&avl->avl_tree, item, &where) != NULL) {
1495148c5f43SAlan Wright 		rw_exit(&avl->avl_lock);
1496148c5f43SAlan Wright 		smb_avl_rele(avl);
1497148c5f43SAlan Wright 		return (EEXIST);
1498da6c28aaSamw 	}
1499da6c28aaSamw 
1500148c5f43SAlan Wright 	avl_insert(&avl->avl_tree, item, where);
1501148c5f43SAlan Wright 	avl->avl_sequence++;
1502148c5f43SAlan Wright 	rw_exit(&avl->avl_lock);
15039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1504148c5f43SAlan Wright 	smb_avl_rele(avl);
1505148c5f43SAlan Wright 	return (0);
1506da6c28aaSamw }
1507da6c28aaSamw 
1508da6c28aaSamw /*
1509148c5f43SAlan Wright  * Removes the given item from the AVL.
1510148c5f43SAlan Wright  * If no reference is left on the item
1511148c5f43SAlan Wright  * it will also be destroyed by calling the
1512148c5f43SAlan Wright  * registered destroy operation.
1513da6c28aaSamw  */
1514da6c28aaSamw void
smb_avl_remove(smb_avl_t * avl,void * item)1515148c5f43SAlan Wright smb_avl_remove(smb_avl_t *avl, void *item)
1516da6c28aaSamw {
1517148c5f43SAlan Wright 	avl_index_t where;
1518148c5f43SAlan Wright 	void *rm_item;
1519148c5f43SAlan Wright 
1520148c5f43SAlan Wright 	ASSERT(avl);
1521148c5f43SAlan Wright 	ASSERT(item);
1522148c5f43SAlan Wright 
1523148c5f43SAlan Wright 	if (!smb_avl_hold(avl))
1524148c5f43SAlan Wright 		return;
1525148c5f43SAlan Wright 
1526148c5f43SAlan Wright 	rw_enter(&avl->avl_lock, RW_WRITER);
1527148c5f43SAlan Wright 	if ((rm_item = avl_find(&avl->avl_tree, item, &where)) == NULL) {
1528148c5f43SAlan Wright 		rw_exit(&avl->avl_lock);
1529148c5f43SAlan Wright 		smb_avl_rele(avl);
1530148c5f43SAlan Wright 		return;
1531148c5f43SAlan Wright 	}
1532148c5f43SAlan Wright 
1533148c5f43SAlan Wright 	avl_remove(&avl->avl_tree, rm_item);
1534148c5f43SAlan Wright 	if (avl->avl_nops->avln_rele(rm_item))
1535148c5f43SAlan Wright 		avl->avl_nops->avln_destroy(rm_item);
1536148c5f43SAlan Wright 	avl->avl_sequence++;
1537148c5f43SAlan Wright 	rw_exit(&avl->avl_lock);
1538148c5f43SAlan Wright 
1539148c5f43SAlan Wright 	smb_avl_rele(avl);
1540da6c28aaSamw }
1541da6c28aaSamw 
1542da6c28aaSamw /*
1543148c5f43SAlan Wright  * Looks up the AVL for the given item.
1544148c5f43SAlan Wright  * If the item is found a hold on the object
1545148c5f43SAlan Wright  * is taken before the pointer to it is
1546148c5f43SAlan Wright  * returned to the caller. The caller MUST
1547148c5f43SAlan Wright  * always call smb_avl_release() after it's done
1548148c5f43SAlan Wright  * using the returned object to release the hold
1549148c5f43SAlan Wright  * taken on the object.
1550da6c28aaSamw  */
1551148c5f43SAlan Wright void *
smb_avl_lookup(smb_avl_t * avl,void * item)1552148c5f43SAlan Wright smb_avl_lookup(smb_avl_t *avl, void *item)
1553da6c28aaSamw {
1554148c5f43SAlan Wright 	void *node = NULL;
1555da6c28aaSamw 
1556148c5f43SAlan Wright 	ASSERT(avl);
1557148c5f43SAlan Wright 	ASSERT(item);
1558da6c28aaSamw 
1559148c5f43SAlan Wright 	if (!smb_avl_hold(avl))
1560148c5f43SAlan Wright 		return (NULL);
1561da6c28aaSamw 
1562148c5f43SAlan Wright 	rw_enter(&avl->avl_lock, RW_READER);
1563148c5f43SAlan Wright 	node = avl_find(&avl->avl_tree, item, NULL);
1564148c5f43SAlan Wright 	if (node != NULL)
1565148c5f43SAlan Wright 		avl->avl_nops->avln_hold(node);
1566148c5f43SAlan Wright 	rw_exit(&avl->avl_lock);
1567da6c28aaSamw 
1568148c5f43SAlan Wright 	if (node == NULL)
1569148c5f43SAlan Wright 		smb_avl_rele(avl);
1570da6c28aaSamw 
1571148c5f43SAlan Wright 	return (node);
1572148c5f43SAlan Wright }
1573148c5f43SAlan Wright 
1574148c5f43SAlan Wright /*
1575148c5f43SAlan Wright  * The hold on the given object is released.
1576148c5f43SAlan Wright  * This function MUST always be called after
1577148c5f43SAlan Wright  * smb_avl_lookup() and smb_avl_iterate() for
1578148c5f43SAlan Wright  * the returned object.
1579148c5f43SAlan Wright  *
1580148c5f43SAlan Wright  * If AVL is in DESTROYING state, the destroying
1581148c5f43SAlan Wright  * thread will be notified.
1582148c5f43SAlan Wright  */
1583148c5f43SAlan Wright void
smb_avl_release(smb_avl_t * avl,void * item)1584148c5f43SAlan Wright smb_avl_release(smb_avl_t *avl, void *item)
1585148c5f43SAlan Wright {
1586148c5f43SAlan Wright 	ASSERT(avl);
1587148c5f43SAlan Wright 	ASSERT(item);
1588da6c28aaSamw 
1589148c5f43SAlan Wright 	if (avl->avl_nops->avln_rele(item))
1590148c5f43SAlan Wright 		avl->avl_nops->avln_destroy(item);
1591da6c28aaSamw 
1592148c5f43SAlan Wright 	smb_avl_rele(avl);
1593da6c28aaSamw }
1594da6c28aaSamw 
1595b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
1596148c5f43SAlan Wright  * Initializes the given cursor for the AVL.
1597148c5f43SAlan Wright  * The cursor will be used to iterate through the AVL
1598148c5f43SAlan Wright  */
1599148c5f43SAlan Wright void
smb_avl_iterinit(smb_avl_t * avl,smb_avl_cursor_t * cursor)1600148c5f43SAlan Wright smb_avl_iterinit(smb_avl_t *avl, smb_avl_cursor_t *cursor)
1601148c5f43SAlan Wright {
1602148c5f43SAlan Wright 	ASSERT(avl);
1603148c5f43SAlan Wright 	ASSERT(cursor);
1604148c5f43SAlan Wright 
1605148c5f43SAlan Wright 	cursor->avlc_next = NULL;
1606148c5f43SAlan Wright 	cursor->avlc_sequence = avl->avl_sequence;
1607148c5f43SAlan Wright }
1608148c5f43SAlan Wright 
1609148c5f43SAlan Wright /*
1610148c5f43SAlan Wright  * Iterates through the AVL using the given cursor.
1611148c5f43SAlan Wright  * It always starts at the beginning and then returns
1612148c5f43SAlan Wright  * a pointer to the next object on each subsequent call.
1613b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
1614148c5f43SAlan Wright  * If a new object is added to or removed from the AVL
1615148c5f43SAlan Wright  * between two calls to this function, the iteration
1616148c5f43SAlan Wright  * will terminate prematurely.
1617b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
1618148c5f43SAlan Wright  * The caller MUST always call smb_avl_release() after it's
1619148c5f43SAlan Wright  * done using the returned object to release the hold taken
1620148c5f43SAlan Wright  * on the object.
1621b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1622148c5f43SAlan Wright void *
smb_avl_iterate(smb_avl_t * avl,smb_avl_cursor_t * cursor)1623148c5f43SAlan Wright smb_avl_iterate(smb_avl_t *avl, smb_avl_cursor_t *cursor)
1624b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1625148c5f43SAlan Wright 	void *node;
1626b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1627148c5f43SAlan Wright 	ASSERT(avl);
1628148c5f43SAlan Wright 	ASSERT(cursor);
1629b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1630148c5f43SAlan Wright 	if (!smb_avl_hold(avl))
1631b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
1632b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1633148c5f43SAlan Wright 	rw_enter(&avl->avl_lock, RW_READER);
1634148c5f43SAlan Wright 	if (cursor->avlc_sequence != avl->avl_sequence) {
1635148c5f43SAlan Wright 		rw_exit(&avl->avl_lock);
1636148c5f43SAlan Wright 		smb_avl_rele(avl);
1637148c5f43SAlan Wright 		return (NULL);
1638b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1639b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1640148c5f43SAlan Wright 	if (cursor->avlc_next == NULL)
1641148c5f43SAlan Wright 		node = avl_first(&avl->avl_tree);
1642148c5f43SAlan Wright 	else
1643148c5f43SAlan Wright 		node = AVL_NEXT(&avl->avl_tree, cursor->avlc_next);
1644148c5f43SAlan Wright 
1645148c5f43SAlan Wright 	if (node != NULL)
1646148c5f43SAlan Wright 		avl->avl_nops->avln_hold(node);
1647148c5f43SAlan Wright 
1648148c5f43SAlan Wright 	cursor->avlc_next = node;
1649148c5f43SAlan Wright 	rw_exit(&avl->avl_lock);
1650148c5f43SAlan Wright 
1651148c5f43SAlan Wright 	if (node == NULL)
1652148c5f43SAlan Wright 		smb_avl_rele(avl);
1653148c5f43SAlan Wright 
1654148c5f43SAlan Wright 	return (node);
1655148c5f43SAlan Wright }
1656148c5f43SAlan Wright 
1657148c5f43SAlan Wright /*
1658148c5f43SAlan Wright  * Increments the AVL reference count in order to
1659148c5f43SAlan Wright  * prevent the avl from being destroyed while it's
1660148c5f43SAlan Wright  * being accessed.
1661148c5f43SAlan Wright  */
1662148c5f43SAlan Wright static boolean_t
smb_avl_hold(smb_avl_t * avl)1663148c5f43SAlan Wright smb_avl_hold(smb_avl_t *avl)
1664148c5f43SAlan Wright {
1665148c5f43SAlan Wright 	mutex_enter(&avl->avl_mutex);
1666148c5f43SAlan Wright 	if (avl->avl_state != SMB_AVL_STATE_READY) {
1667148c5f43SAlan Wright 		mutex_exit(&avl->avl_mutex);
1668148c5f43SAlan Wright 		return (B_FALSE);
1669b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1670148c5f43SAlan Wright 	avl->avl_refcnt++;
1671148c5f43SAlan Wright 	mutex_exit(&avl->avl_mutex);
1672b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1673148c5f43SAlan Wright 	return (B_TRUE);
1674b89a8333Snatalie li - Sun Microsystems - Irvine United States }
16752c2961f8Sjose borrego 
16769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
1677148c5f43SAlan Wright  * Decrements the AVL reference count to release the
1678148c5f43SAlan Wright  * hold. If another thread is trying to destroy the
1679148c5f43SAlan Wright  * AVL and is waiting for the reference count to become
1680148c5f43SAlan Wright  * 0, it is signaled to wake up.
16819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
1682148c5f43SAlan Wright static void
smb_avl_rele(smb_avl_t * avl)1683148c5f43SAlan Wright smb_avl_rele(smb_avl_t *avl)
16849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
1685148c5f43SAlan Wright 	mutex_enter(&avl->avl_mutex);
1686148c5f43SAlan Wright 	ASSERT(avl->avl_refcnt > 0);
1687148c5f43SAlan Wright 	avl->avl_refcnt--;
1688148c5f43SAlan Wright 	if (avl->avl_state == SMB_AVL_STATE_DESTROYING)
1689148c5f43SAlan Wright 		cv_broadcast(&avl->avl_cv);
1690148c5f43SAlan Wright 	mutex_exit(&avl->avl_mutex);
1691148c5f43SAlan Wright }
16929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1693148c5f43SAlan Wright /*
1694148c5f43SAlan Wright  * smb_latency_init
1695148c5f43SAlan Wright  */
1696148c5f43SAlan Wright void
smb_latency_init(smb_latency_t * lat)1697148c5f43SAlan Wright smb_latency_init(smb_latency_t *lat)
1698148c5f43SAlan Wright {
1699148c5f43SAlan Wright 	bzero(lat, sizeof (*lat));
1700148c5f43SAlan Wright 	mutex_init(&lat->ly_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7));
1701148c5f43SAlan Wright }
17029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1703148c5f43SAlan Wright /*
1704148c5f43SAlan Wright  * smb_latency_destroy
1705148c5f43SAlan Wright  */
1706148c5f43SAlan Wright void
smb_latency_destroy(smb_latency_t * lat)1707148c5f43SAlan Wright smb_latency_destroy(smb_latency_t *lat)
1708148c5f43SAlan Wright {
1709148c5f43SAlan Wright 	mutex_destroy(&lat->ly_mutex);
17109fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
17119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
17122c2961f8Sjose borrego /*
1713148c5f43SAlan Wright  * smb_latency_add_sample
17142c2961f8Sjose borrego  *
1715148c5f43SAlan Wright  * Uses the new sample to calculate the new mean and standard deviation. The
1716148c5f43SAlan Wright  * sample must be a scaled value.
17172c2961f8Sjose borrego  */
17182c2961f8Sjose borrego void
smb_latency_add_sample(smb_latency_t * lat,hrtime_t sample)1719148c5f43SAlan Wright smb_latency_add_sample(smb_latency_t *lat, hrtime_t sample)
1720148c5f43SAlan Wright {
1721148c5f43SAlan Wright 	hrtime_t	a_mean;
1722148c5f43SAlan Wright 	hrtime_t	d_mean;
1723148c5f43SAlan Wright 
1724148c5f43SAlan Wright 	mutex_enter(&lat->ly_mutex);
1725148c5f43SAlan Wright 	lat->ly_a_nreq++;
1726148c5f43SAlan Wright 	lat->ly_a_sum += sample;
1727148c5f43SAlan Wright 	if (lat->ly_a_nreq != 0) {
1728148c5f43SAlan Wright 		a_mean = lat->ly_a_sum / lat->ly_a_nreq;
1729148c5f43SAlan Wright 		lat->ly_a_stddev =
1730148c5f43SAlan Wright 		    (sample - a_mean) * (sample - lat->ly_a_mean);
1731148c5f43SAlan Wright 		lat->ly_a_mean = a_mean;
1732148c5f43SAlan Wright 	}
1733148c5f43SAlan Wright 	lat->ly_d_nreq++;
1734148c5f43SAlan Wright 	lat->ly_d_sum += sample;
1735148c5f43SAlan Wright 	if (lat->ly_d_nreq != 0) {
1736148c5f43SAlan Wright 		d_mean = lat->ly_d_sum / lat->ly_d_nreq;
1737148c5f43SAlan Wright 		lat->ly_d_stddev =
1738148c5f43SAlan Wright 		    (sample - d_mean) * (sample - lat->ly_d_mean);
1739148c5f43SAlan Wright 		lat->ly_d_mean = d_mean;
1740148c5f43SAlan Wright 	}
1741148c5f43SAlan Wright 	mutex_exit(&lat->ly_mutex);
1742148c5f43SAlan Wright }
1743148c5f43SAlan Wright 
1744148c5f43SAlan Wright /*
1745148c5f43SAlan Wright  * smb_srqueue_init
1746148c5f43SAlan Wright  */
1747148c5f43SAlan Wright void
smb_srqueue_init(smb_srqueue_t * srq)1748148c5f43SAlan Wright smb_srqueue_init(smb_srqueue_t *srq)
17492c2961f8Sjose borrego {
1750148c5f43SAlan Wright 	bzero(srq, sizeof (*srq));
1751148c5f43SAlan Wright 	mutex_init(&srq->srq_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7));
1752148c5f43SAlan Wright 	srq->srq_wlastupdate = srq->srq_rlastupdate = gethrtime_unscaled();
1753148c5f43SAlan Wright }
1754148c5f43SAlan Wright 
1755148c5f43SAlan Wright /*
1756148c5f43SAlan Wright  * smb_srqueue_destroy
1757148c5f43SAlan Wright  */
1758148c5f43SAlan Wright void
smb_srqueue_destroy(smb_srqueue_t * srq)1759148c5f43SAlan Wright smb_srqueue_destroy(smb_srqueue_t *srq)
1760148c5f43SAlan Wright {
1761148c5f43SAlan Wright 	mutex_destroy(&srq->srq_mutex);
1762148c5f43SAlan Wright }
1763148c5f43SAlan Wright 
1764148c5f43SAlan Wright /*
1765148c5f43SAlan Wright  * smb_srqueue_waitq_enter
1766148c5f43SAlan Wright  */
1767148c5f43SAlan Wright void
smb_srqueue_waitq_enter(smb_srqueue_t * srq)1768148c5f43SAlan Wright smb_srqueue_waitq_enter(smb_srqueue_t *srq)
1769148c5f43SAlan Wright {
1770148c5f43SAlan Wright 	hrtime_t	new;
1771148c5f43SAlan Wright 	hrtime_t	delta;
1772148c5f43SAlan Wright 	uint32_t	wcnt;
1773148c5f43SAlan Wright 
1774148c5f43SAlan Wright 	mutex_enter(&srq->srq_mutex);
1775148c5f43SAlan Wright 	new = gethrtime_unscaled();
1776148c5f43SAlan Wright 	delta = new - srq->srq_wlastupdate;
1777148c5f43SAlan Wright 	srq->srq_wlastupdate = new;
1778148c5f43SAlan Wright 	wcnt = srq->srq_wcnt++;
1779148c5f43SAlan Wright 	if (wcnt != 0) {
1780148c5f43SAlan Wright 		srq->srq_wlentime += delta * wcnt;
1781148c5f43SAlan Wright 		srq->srq_wtime += delta;
1782148c5f43SAlan Wright 	}
1783148c5f43SAlan Wright 	mutex_exit(&srq->srq_mutex);
1784148c5f43SAlan Wright }
1785148c5f43SAlan Wright 
1786148c5f43SAlan Wright /*
1787148c5f43SAlan Wright  * smb_srqueue_runq_exit
1788148c5f43SAlan Wright  */
1789148c5f43SAlan Wright void
smb_srqueue_runq_exit(smb_srqueue_t * srq)1790148c5f43SAlan Wright smb_srqueue_runq_exit(smb_srqueue_t *srq)
1791148c5f43SAlan Wright {
1792148c5f43SAlan Wright 	hrtime_t	new;
1793148c5f43SAlan Wright 	hrtime_t	delta;
1794148c5f43SAlan Wright 	uint32_t	rcnt;
1795148c5f43SAlan Wright 
1796148c5f43SAlan Wright 	mutex_enter(&srq->srq_mutex);
1797148c5f43SAlan Wright 	new = gethrtime_unscaled();
1798148c5f43SAlan Wright 	delta = new - srq->srq_rlastupdate;
1799148c5f43SAlan Wright 	srq->srq_rlastupdate = new;
1800148c5f43SAlan Wright 	rcnt = srq->srq_rcnt--;
1801148c5f43SAlan Wright 	ASSERT(rcnt > 0);
1802148c5f43SAlan Wright 	srq->srq_rlentime += delta * rcnt;
1803148c5f43SAlan Wright 	srq->srq_rtime += delta;
1804148c5f43SAlan Wright 	mutex_exit(&srq->srq_mutex);
1805148c5f43SAlan Wright }
1806148c5f43SAlan Wright 
1807148c5f43SAlan Wright /*
1808148c5f43SAlan Wright  * smb_srqueue_waitq_to_runq
1809148c5f43SAlan Wright  */
1810148c5f43SAlan Wright void
smb_srqueue_waitq_to_runq(smb_srqueue_t * srq)1811148c5f43SAlan Wright smb_srqueue_waitq_to_runq(smb_srqueue_t *srq)
1812148c5f43SAlan Wright {
1813148c5f43SAlan Wright 	hrtime_t	new;
1814148c5f43SAlan Wright 	hrtime_t	delta;
1815148c5f43SAlan Wright 	uint32_t	wcnt;
1816148c5f43SAlan Wright 	uint32_t	rcnt;
1817148c5f43SAlan Wright 
1818148c5f43SAlan Wright 	mutex_enter(&srq->srq_mutex);
1819148c5f43SAlan Wright 	new = gethrtime_unscaled();
1820148c5f43SAlan Wright 	delta = new - srq->srq_wlastupdate;
1821148c5f43SAlan Wright 	srq->srq_wlastupdate = new;
1822148c5f43SAlan Wright 	wcnt = srq->srq_wcnt--;
1823148c5f43SAlan Wright 	ASSERT(wcnt > 0);
1824148c5f43SAlan Wright 	srq->srq_wlentime += delta * wcnt;
1825148c5f43SAlan Wright 	srq->srq_wtime += delta;
1826148c5f43SAlan Wright 	delta = new - srq->srq_rlastupdate;
1827148c5f43SAlan Wright 	srq->srq_rlastupdate = new;
1828148c5f43SAlan Wright 	rcnt = srq->srq_rcnt++;
1829148c5f43SAlan Wright 	if (rcnt != 0) {
1830148c5f43SAlan Wright 		srq->srq_rlentime += delta * rcnt;
1831148c5f43SAlan Wright 		srq->srq_rtime += delta;
1832148c5f43SAlan Wright 	}
1833148c5f43SAlan Wright 	mutex_exit(&srq->srq_mutex);
1834148c5f43SAlan Wright }
1835148c5f43SAlan Wright 
1836148c5f43SAlan Wright /*
1837148c5f43SAlan Wright  * smb_srqueue_update
1838148c5f43SAlan Wright  *
1839148c5f43SAlan Wright  * Takes a snapshot of the smb_sr_stat_t structure passed in.
1840148c5f43SAlan Wright  */
1841148c5f43SAlan Wright void
smb_srqueue_update(smb_srqueue_t * srq,smb_kstat_utilization_t * kd)1842148c5f43SAlan Wright smb_srqueue_update(smb_srqueue_t *srq, smb_kstat_utilization_t *kd)
1843148c5f43SAlan Wright {
1844148c5f43SAlan Wright 	hrtime_t	delta;
1845148c5f43SAlan Wright 	hrtime_t	snaptime;
1846148c5f43SAlan Wright 
1847148c5f43SAlan Wright 	mutex_enter(&srq->srq_mutex);
1848148c5f43SAlan Wright 	snaptime = gethrtime_unscaled();
1849148c5f43SAlan Wright 	delta = snaptime - srq->srq_wlastupdate;
1850148c5f43SAlan Wright 	srq->srq_wlastupdate = snaptime;
1851148c5f43SAlan Wright 	if (srq->srq_wcnt != 0) {
1852148c5f43SAlan Wright 		srq->srq_wlentime += delta * srq->srq_wcnt;
1853148c5f43SAlan Wright 		srq->srq_wtime += delta;
1854148c5f43SAlan Wright 	}
1855148c5f43SAlan Wright 	delta = snaptime - srq->srq_rlastupdate;
1856148c5f43SAlan Wright 	srq->srq_rlastupdate = snaptime;
1857148c5f43SAlan Wright 	if (srq->srq_rcnt != 0) {
1858148c5f43SAlan Wright 		srq->srq_rlentime += delta * srq->srq_rcnt;
1859148c5f43SAlan Wright 		srq->srq_rtime += delta;
1860148c5f43SAlan Wright 	}
1861148c5f43SAlan Wright 	kd->ku_rlentime = srq->srq_rlentime;
1862148c5f43SAlan Wright 	kd->ku_rtime = srq->srq_rtime;
1863148c5f43SAlan Wright 	kd->ku_wlentime = srq->srq_wlentime;
1864148c5f43SAlan Wright 	kd->ku_wtime = srq->srq_wtime;
1865148c5f43SAlan Wright 	mutex_exit(&srq->srq_mutex);
1866148c5f43SAlan Wright 	scalehrtime(&kd->ku_rlentime);
1867148c5f43SAlan Wright 	scalehrtime(&kd->ku_rtime);
1868148c5f43SAlan Wright 	scalehrtime(&kd->ku_wlentime);
1869148c5f43SAlan Wright 	scalehrtime(&kd->ku_wtime);
18702c2961f8Sjose borrego }
1871cb174861Sjoyce mcintosh 
1872cb174861Sjoyce mcintosh void
smb_threshold_init(smb_cmd_threshold_t * ct,char * cmd,uint_t threshold,uint_t timeout)1873856399cfSGordon Ross smb_threshold_init(smb_cmd_threshold_t *ct, char *cmd,
1874856399cfSGordon Ross     uint_t threshold, uint_t timeout)
1875cb174861Sjoyce mcintosh {
1876cb174861Sjoyce mcintosh 	bzero(ct, sizeof (smb_cmd_threshold_t));
1877cb174861Sjoyce mcintosh 	mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL);
1878856399cfSGordon Ross 	cv_init(&ct->ct_cond, NULL, CV_DEFAULT, NULL);
1879856399cfSGordon Ross 
1880cb174861Sjoyce mcintosh 	ct->ct_cmd = cmd;
1881cb174861Sjoyce mcintosh 	ct->ct_threshold = threshold;
1882856399cfSGordon Ross 	ct->ct_timeout = timeout;
1883cb174861Sjoyce mcintosh }
1884cb174861Sjoyce mcintosh 
1885cb174861Sjoyce mcintosh void
smb_threshold_fini(smb_cmd_threshold_t * ct)1886cb174861Sjoyce mcintosh smb_threshold_fini(smb_cmd_threshold_t *ct)
1887cb174861Sjoyce mcintosh {
1888856399cfSGordon Ross 	cv_destroy(&ct->ct_cond);
1889cb174861Sjoyce mcintosh 	mutex_destroy(&ct->ct_mutex);
1890cb174861Sjoyce mcintosh }
1891cb174861Sjoyce mcintosh 
1892cb174861Sjoyce mcintosh /*
1893856399cfSGordon Ross  * This threshold mechanism is used to limit the number of simultaneous
1894856399cfSGordon Ross  * named pipe connections, concurrent authentication conversations, etc.
1895856399cfSGordon Ross  * Requests that would take us over the threshold wait until either the
1896856399cfSGordon Ross  * resources are available (return zero) or timeout (return error).
1897cb174861Sjoyce mcintosh  */
1898cb174861Sjoyce mcintosh int
smb_threshold_enter(smb_cmd_threshold_t * ct)1899cb174861Sjoyce mcintosh smb_threshold_enter(smb_cmd_threshold_t *ct)
1900cb174861Sjoyce mcintosh {
1901856399cfSGordon Ross 	clock_t	time, rem;
1902cb174861Sjoyce mcintosh 
1903856399cfSGordon Ross 	time = MSEC_TO_TICK(ct->ct_timeout) + ddi_get_lbolt();
1904cb174861Sjoyce mcintosh 	mutex_enter(&ct->ct_mutex);
1905cb174861Sjoyce mcintosh 
1906856399cfSGordon Ross 	while (ct->ct_threshold != 0 &&
1907856399cfSGordon Ross 	    ct->ct_threshold <= ct->ct_active_cnt) {
1908856399cfSGordon Ross 		ct->ct_blocked_cnt++;
1909856399cfSGordon Ross 		rem = cv_timedwait(&ct->ct_cond, &ct->ct_mutex, time);
1910856399cfSGordon Ross 		ct->ct_blocked_cnt--;
1911856399cfSGordon Ross 		if (rem < 0) {
1912cb174861Sjoyce mcintosh 			mutex_exit(&ct->ct_mutex);
1913856399cfSGordon Ross 			return (ETIME);
1914cb174861Sjoyce mcintosh 		}
1915cb174861Sjoyce mcintosh 	}
1916856399cfSGordon Ross 	if (ct->ct_threshold == 0) {
1917856399cfSGordon Ross 		mutex_exit(&ct->ct_mutex);
1918856399cfSGordon Ross 		return (ECANCELED);
1919856399cfSGordon Ross 	}
1920856399cfSGordon Ross 
1921856399cfSGordon Ross 	ASSERT3U(ct->ct_active_cnt, <, ct->ct_threshold);
1922856399cfSGordon Ross 	ct->ct_active_cnt++;
1923cb174861Sjoyce mcintosh 
1924cb174861Sjoyce mcintosh 	mutex_exit(&ct->ct_mutex);
1925cb174861Sjoyce mcintosh 	return (0);
1926cb174861Sjoyce mcintosh }
1927cb174861Sjoyce mcintosh 
1928cb174861Sjoyce mcintosh void
smb_threshold_exit(smb_cmd_threshold_t * ct)1929856399cfSGordon Ross smb_threshold_exit(smb_cmd_threshold_t *ct)
1930856399cfSGordon Ross {
1931856399cfSGordon Ross 	mutex_enter(&ct->ct_mutex);
1932856399cfSGordon Ross 	ASSERT3U(ct->ct_active_cnt, >, 0);
1933856399cfSGordon Ross 	ct->ct_active_cnt--;
1934856399cfSGordon Ross 	if (ct->ct_blocked_cnt)
1935856399cfSGordon Ross 		cv_signal(&ct->ct_cond);
1936856399cfSGordon Ross 	mutex_exit(&ct->ct_mutex);
1937856399cfSGordon Ross }
1938856399cfSGordon Ross 
1939856399cfSGordon Ross void
smb_threshold_wake_all(smb_cmd_threshold_t * ct)1940856399cfSGordon Ross smb_threshold_wake_all(smb_cmd_threshold_t *ct)
1941cb174861Sjoyce mcintosh {
1942cb174861Sjoyce mcintosh 	mutex_enter(&ct->ct_mutex);
1943856399cfSGordon Ross 	ct->ct_threshold = 0;
1944856399cfSGordon Ross 	cv_broadcast(&ct->ct_cond);
1945cb174861Sjoyce mcintosh 	mutex_exit(&ct->ct_mutex);
1946cb174861Sjoyce mcintosh }
1947811599a4SMatt Barden 
1948811599a4SMatt Barden /* taken from mod_hash_byptr */
1949811599a4SMatt Barden uint_t
smb_hash_uint64(smb_hash_t * hash,uint64_t val)1950811599a4SMatt Barden smb_hash_uint64(smb_hash_t *hash, uint64_t val)
1951811599a4SMatt Barden {
1952811599a4SMatt Barden 	uint64_t k = val >> hash->rshift;
1953811599a4SMatt Barden 	uint_t idx = ((uint_t)k) & (hash->num_buckets - 1);
1954811599a4SMatt Barden 
1955811599a4SMatt Barden 	return (idx);
1956811599a4SMatt Barden }
1957811599a4SMatt Barden 
1958811599a4SMatt Barden boolean_t
smb_is_pow2(size_t n)1959811599a4SMatt Barden smb_is_pow2(size_t n)
1960811599a4SMatt Barden {
1961811599a4SMatt Barden 	return ((n & (n - 1)) == 0);
1962811599a4SMatt Barden }
1963811599a4SMatt Barden 
1964811599a4SMatt Barden smb_hash_t *
smb_hash_create(size_t elemsz,size_t link_offset,uint32_t num_buckets)1965811599a4SMatt Barden smb_hash_create(size_t elemsz, size_t link_offset,
1966811599a4SMatt Barden     uint32_t num_buckets)
1967811599a4SMatt Barden {
1968811599a4SMatt Barden 	smb_hash_t *hash = kmem_alloc(sizeof (*hash), KM_SLEEP);
1969811599a4SMatt Barden 	int i;
1970811599a4SMatt Barden 
1971811599a4SMatt Barden 	if (!smb_is_pow2(num_buckets))
1972811599a4SMatt Barden 		num_buckets = 1 << highbit(num_buckets);
1973811599a4SMatt Barden 
1974811599a4SMatt Barden 	hash->rshift = highbit(elemsz);
1975811599a4SMatt Barden 	hash->num_buckets = num_buckets;
1976811599a4SMatt Barden 	hash->buckets = kmem_zalloc(num_buckets * sizeof (smb_bucket_t),
1977811599a4SMatt Barden 	    KM_SLEEP);
1978811599a4SMatt Barden 	for (i = 0; i < num_buckets; i++)
1979811599a4SMatt Barden 		smb_llist_constructor(&hash->buckets[i].b_list, elemsz,
1980811599a4SMatt Barden 		    link_offset);
1981811599a4SMatt Barden 	return (hash);
1982811599a4SMatt Barden }
1983811599a4SMatt Barden 
1984811599a4SMatt Barden void
smb_hash_destroy(smb_hash_t * hash)1985811599a4SMatt Barden smb_hash_destroy(smb_hash_t *hash)
1986811599a4SMatt Barden {
1987811599a4SMatt Barden 	int i;
1988811599a4SMatt Barden 
1989811599a4SMatt Barden 	for (i = 0; i < hash->num_buckets; i++)
1990811599a4SMatt Barden 		smb_llist_destructor(&hash->buckets[i].b_list);
1991811599a4SMatt Barden 
1992811599a4SMatt Barden 	kmem_free(hash->buckets, hash->num_buckets * sizeof (smb_bucket_t));
1993811599a4SMatt Barden 	kmem_free(hash, sizeof (*hash));
1994811599a4SMatt Barden }
1995