xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kutil.c (revision 12508:edb7861a1533)
111963SAfshin.Ardakani@Sun.COM /*
211963SAfshin.Ardakani@Sun.COM  * CDDL HEADER START
311963SAfshin.Ardakani@Sun.COM  *
411963SAfshin.Ardakani@Sun.COM  * The contents of this file are subject to the terms of the
511963SAfshin.Ardakani@Sun.COM  * Common Development and Distribution License (the "License").
611963SAfshin.Ardakani@Sun.COM  * You may not use this file except in compliance with the License.
711963SAfshin.Ardakani@Sun.COM  *
811963SAfshin.Ardakani@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911963SAfshin.Ardakani@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011963SAfshin.Ardakani@Sun.COM  * See the License for the specific language governing permissions
1111963SAfshin.Ardakani@Sun.COM  * and limitations under the License.
1211963SAfshin.Ardakani@Sun.COM  *
1311963SAfshin.Ardakani@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411963SAfshin.Ardakani@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511963SAfshin.Ardakani@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611963SAfshin.Ardakani@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711963SAfshin.Ardakani@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811963SAfshin.Ardakani@Sun.COM  *
1911963SAfshin.Ardakani@Sun.COM  * CDDL HEADER END
2011963SAfshin.Ardakani@Sun.COM  */
2111963SAfshin.Ardakani@Sun.COM /*
2212065SKeyur.Desai@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2311963SAfshin.Ardakani@Sun.COM  */
2411963SAfshin.Ardakani@Sun.COM 
2511963SAfshin.Ardakani@Sun.COM #include <sys/param.h>
2611963SAfshin.Ardakani@Sun.COM #include <sys/types.h>
2711963SAfshin.Ardakani@Sun.COM #include <sys/tzfile.h>
2811963SAfshin.Ardakani@Sun.COM #include <sys/atomic.h>
2911963SAfshin.Ardakani@Sun.COM #include <sys/kidmap.h>
3011963SAfshin.Ardakani@Sun.COM #include <sys/time.h>
31*12508Samw@Sun.COM #include <sys/spl.h>
3211963SAfshin.Ardakani@Sun.COM #include <sys/cpuvar.h>
33*12508Samw@Sun.COM #include <sys/random.h>
3411963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_kproto.h>
3511963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_fsops.h>
3611963SAfshin.Ardakani@Sun.COM #include <smbsrv/smbinfo.h>
3711963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_xdr.h>
3811963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_vops.h>
3911963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_idmap.h>
4011963SAfshin.Ardakani@Sun.COM 
4111963SAfshin.Ardakani@Sun.COM #include <sys/sid.h>
4211963SAfshin.Ardakani@Sun.COM #include <sys/priv_names.h>
4311963SAfshin.Ardakani@Sun.COM 
4411963SAfshin.Ardakani@Sun.COM static kmem_cache_t	*smb_dtor_cache;
4511963SAfshin.Ardakani@Sun.COM static boolean_t	smb_llist_initialized = B_FALSE;
4611963SAfshin.Ardakani@Sun.COM 
4711963SAfshin.Ardakani@Sun.COM static boolean_t smb_thread_continue_timedwait_locked(smb_thread_t *, int);
4811963SAfshin.Ardakani@Sun.COM 
49*12508Samw@Sun.COM static boolean_t smb_avl_hold(smb_avl_t *);
50*12508Samw@Sun.COM static void smb_avl_rele(smb_avl_t *);
51*12508Samw@Sun.COM 
5211963SAfshin.Ardakani@Sun.COM time_t tzh_leapcnt = 0;
5311963SAfshin.Ardakani@Sun.COM 
5411963SAfshin.Ardakani@Sun.COM struct tm
5511963SAfshin.Ardakani@Sun.COM *smb_gmtime_r(time_t *clock, struct tm *result);
5611963SAfshin.Ardakani@Sun.COM 
5711963SAfshin.Ardakani@Sun.COM time_t
5811963SAfshin.Ardakani@Sun.COM smb_timegm(struct tm *tm);
5911963SAfshin.Ardakani@Sun.COM 
6011963SAfshin.Ardakani@Sun.COM struct	tm {
6111963SAfshin.Ardakani@Sun.COM 	int	tm_sec;
6211963SAfshin.Ardakani@Sun.COM 	int	tm_min;
6311963SAfshin.Ardakani@Sun.COM 	int	tm_hour;
6411963SAfshin.Ardakani@Sun.COM 	int	tm_mday;
6511963SAfshin.Ardakani@Sun.COM 	int	tm_mon;
6611963SAfshin.Ardakani@Sun.COM 	int	tm_year;
6711963SAfshin.Ardakani@Sun.COM 	int	tm_wday;
6811963SAfshin.Ardakani@Sun.COM 	int	tm_yday;
6911963SAfshin.Ardakani@Sun.COM 	int	tm_isdst;
7011963SAfshin.Ardakani@Sun.COM };
7111963SAfshin.Ardakani@Sun.COM 
7211963SAfshin.Ardakani@Sun.COM static int days_in_month[] = {
7311963SAfshin.Ardakani@Sun.COM 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
7411963SAfshin.Ardakani@Sun.COM };
7511963SAfshin.Ardakani@Sun.COM 
7611963SAfshin.Ardakani@Sun.COM int
7711963SAfshin.Ardakani@Sun.COM smb_ascii_or_unicode_strlen(struct smb_request *sr, char *str)
7811963SAfshin.Ardakani@Sun.COM {
7911963SAfshin.Ardakani@Sun.COM 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
8011963SAfshin.Ardakani@Sun.COM 		return (smb_wcequiv_strlen(str));
8111963SAfshin.Ardakani@Sun.COM 	return (strlen(str));
8211963SAfshin.Ardakani@Sun.COM }
8311963SAfshin.Ardakani@Sun.COM 
8411963SAfshin.Ardakani@Sun.COM int
8511963SAfshin.Ardakani@Sun.COM smb_ascii_or_unicode_strlen_null(struct smb_request *sr, char *str)
8611963SAfshin.Ardakani@Sun.COM {
8711963SAfshin.Ardakani@Sun.COM 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
8811963SAfshin.Ardakani@Sun.COM 		return (smb_wcequiv_strlen(str) + 2);
8911963SAfshin.Ardakani@Sun.COM 	return (strlen(str) + 1);
9011963SAfshin.Ardakani@Sun.COM }
9111963SAfshin.Ardakani@Sun.COM 
9211963SAfshin.Ardakani@Sun.COM int
9311963SAfshin.Ardakani@Sun.COM smb_ascii_or_unicode_null_len(struct smb_request *sr)
9411963SAfshin.Ardakani@Sun.COM {
9511963SAfshin.Ardakani@Sun.COM 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE)
9611963SAfshin.Ardakani@Sun.COM 		return (2);
9711963SAfshin.Ardakani@Sun.COM 	return (1);
9811963SAfshin.Ardakani@Sun.COM }
9911963SAfshin.Ardakani@Sun.COM 
10011963SAfshin.Ardakani@Sun.COM /*
10111963SAfshin.Ardakani@Sun.COM  * Return B_TRUE if pattern contains wildcards
10211963SAfshin.Ardakani@Sun.COM  */
10311963SAfshin.Ardakani@Sun.COM boolean_t
10411963SAfshin.Ardakani@Sun.COM smb_contains_wildcards(const char *pattern)
10511963SAfshin.Ardakani@Sun.COM {
10611963SAfshin.Ardakani@Sun.COM 	static const char *wildcards = "*?";
10711963SAfshin.Ardakani@Sun.COM 
10811963SAfshin.Ardakani@Sun.COM 	return (strpbrk(pattern, wildcards) != NULL);
10911963SAfshin.Ardakani@Sun.COM }
11011963SAfshin.Ardakani@Sun.COM 
11111963SAfshin.Ardakani@Sun.COM /*
11211963SAfshin.Ardakani@Sun.COM  * When converting wildcards a '.' in a name is treated as a base and
11311963SAfshin.Ardakani@Sun.COM  * extension separator even if the name is longer than 8.3.
11411963SAfshin.Ardakani@Sun.COM  *
11511963SAfshin.Ardakani@Sun.COM  * The '*' character matches an entire part of the name.  For example,
11611963SAfshin.Ardakani@Sun.COM  * "*.abc" matches any name with an extension of "abc".
11711963SAfshin.Ardakani@Sun.COM  *
11811963SAfshin.Ardakani@Sun.COM  * The '?' character matches a single character.
11911963SAfshin.Ardakani@Sun.COM  * If the base contains all ? (8 or more) then it is treated as *.
12011963SAfshin.Ardakani@Sun.COM  * If the extension contains all ? (3 or more) then it is treated as *.
12111963SAfshin.Ardakani@Sun.COM  *
12211963SAfshin.Ardakani@Sun.COM  * Clients convert ASCII wildcards to Unicode wildcards as follows:
12311963SAfshin.Ardakani@Sun.COM  *
12411963SAfshin.Ardakani@Sun.COM  *	? is converted to >
12511963SAfshin.Ardakani@Sun.COM  *	. is converted to " if it is followed by ? or *
12611963SAfshin.Ardakani@Sun.COM  *	* is converted to < if it is followed by .
12711963SAfshin.Ardakani@Sun.COM  *
12811963SAfshin.Ardakani@Sun.COM  * Note that clients convert "*." to '< and drop the '.' but "*.txt"
12911963SAfshin.Ardakani@Sun.COM  * is sent as "<.TXT", i.e.
13011963SAfshin.Ardakani@Sun.COM  *
13111963SAfshin.Ardakani@Sun.COM  * 	dir *.		->	dir <
13211963SAfshin.Ardakani@Sun.COM  * 	dir *.txt	->	dir <.TXT
13311963SAfshin.Ardakani@Sun.COM  *
13411963SAfshin.Ardakani@Sun.COM  * Since " and < are illegal in Windows file names, we always convert
13511963SAfshin.Ardakani@Sun.COM  * these Unicode wildcards without checking the following character.
13611963SAfshin.Ardakani@Sun.COM  */
13711963SAfshin.Ardakani@Sun.COM void
13811963SAfshin.Ardakani@Sun.COM smb_convert_wildcards(char *pattern)
13911963SAfshin.Ardakani@Sun.COM {
14011963SAfshin.Ardakani@Sun.COM 	static char *match_all[] = {
14111963SAfshin.Ardakani@Sun.COM 		"*.",
14211963SAfshin.Ardakani@Sun.COM 		"*.*"
14311963SAfshin.Ardakani@Sun.COM 	};
14411963SAfshin.Ardakani@Sun.COM 	char	*extension;
14511963SAfshin.Ardakani@Sun.COM 	char	*p;
14611963SAfshin.Ardakani@Sun.COM 	int	len;
14711963SAfshin.Ardakani@Sun.COM 	int	i;
14811963SAfshin.Ardakani@Sun.COM 
14911963SAfshin.Ardakani@Sun.COM 	/*
15011963SAfshin.Ardakani@Sun.COM 	 * Special case "<" for "dir *.", and fast-track for "*".
15111963SAfshin.Ardakani@Sun.COM 	 */
15211963SAfshin.Ardakani@Sun.COM 	if ((*pattern == '<') || (*pattern == '*')) {
15311963SAfshin.Ardakani@Sun.COM 		if (*(pattern + 1) == '\0') {
15411963SAfshin.Ardakani@Sun.COM 			*pattern = '*';
15511963SAfshin.Ardakani@Sun.COM 			return;
15611963SAfshin.Ardakani@Sun.COM 		}
15711963SAfshin.Ardakani@Sun.COM 	}
15811963SAfshin.Ardakani@Sun.COM 
15911963SAfshin.Ardakani@Sun.COM 	for (p = pattern; *p != '\0'; ++p) {
16011963SAfshin.Ardakani@Sun.COM 		switch (*p) {
16111963SAfshin.Ardakani@Sun.COM 		case '<':
16211963SAfshin.Ardakani@Sun.COM 			*p = '*';
16311963SAfshin.Ardakani@Sun.COM 			break;
16411963SAfshin.Ardakani@Sun.COM 		case '>':
16511963SAfshin.Ardakani@Sun.COM 			*p = '?';
16611963SAfshin.Ardakani@Sun.COM 			break;
16711963SAfshin.Ardakani@Sun.COM 		case '\"':
16811963SAfshin.Ardakani@Sun.COM 			*p = '.';
16911963SAfshin.Ardakani@Sun.COM 			break;
17011963SAfshin.Ardakani@Sun.COM 		default:
17111963SAfshin.Ardakani@Sun.COM 			break;
17211963SAfshin.Ardakani@Sun.COM 		}
17311963SAfshin.Ardakani@Sun.COM 	}
17411963SAfshin.Ardakani@Sun.COM 
17511963SAfshin.Ardakani@Sun.COM 	/*
17611963SAfshin.Ardakani@Sun.COM 	 * Replace "????????.ext" with "*.ext".
17711963SAfshin.Ardakani@Sun.COM 	 */
17811963SAfshin.Ardakani@Sun.COM 	p = pattern;
17911963SAfshin.Ardakani@Sun.COM 	p += strspn(p, "?");
18011963SAfshin.Ardakani@Sun.COM 	if (*p == '.') {
18111963SAfshin.Ardakani@Sun.COM 		*p = '\0';
18211963SAfshin.Ardakani@Sun.COM 		len = strlen(pattern);
18311963SAfshin.Ardakani@Sun.COM 		*p = '.';
18411963SAfshin.Ardakani@Sun.COM 		if (len >= SMB_NAME83_BASELEN) {
18511963SAfshin.Ardakani@Sun.COM 			*pattern = '*';
18611963SAfshin.Ardakani@Sun.COM 			(void) strlcpy(pattern + 1, p, MAXPATHLEN - 1);
18711963SAfshin.Ardakani@Sun.COM 		}
18811963SAfshin.Ardakani@Sun.COM 	}
18911963SAfshin.Ardakani@Sun.COM 
19011963SAfshin.Ardakani@Sun.COM 	/*
19111963SAfshin.Ardakani@Sun.COM 	 * Replace "base.???" with 'base.*'.
19211963SAfshin.Ardakani@Sun.COM 	 */
19311963SAfshin.Ardakani@Sun.COM 	if ((extension = strrchr(pattern, '.')) != NULL) {
19411963SAfshin.Ardakani@Sun.COM 		p = ++extension;
19511963SAfshin.Ardakani@Sun.COM 		p += strspn(p, "?");
19611963SAfshin.Ardakani@Sun.COM 		if (*p == '\0') {
19711963SAfshin.Ardakani@Sun.COM 			len = strlen(extension);
19811963SAfshin.Ardakani@Sun.COM 			if (len >= SMB_NAME83_EXTLEN) {
19911963SAfshin.Ardakani@Sun.COM 				*extension = '\0';
20011963SAfshin.Ardakani@Sun.COM 				(void) strlcat(pattern, "*", MAXPATHLEN);
20111963SAfshin.Ardakani@Sun.COM 			}
20211963SAfshin.Ardakani@Sun.COM 		}
20311963SAfshin.Ardakani@Sun.COM 	}
20411963SAfshin.Ardakani@Sun.COM 
20511963SAfshin.Ardakani@Sun.COM 	/*
20611963SAfshin.Ardakani@Sun.COM 	 * Replace anything that matches an entry in match_all with "*".
20711963SAfshin.Ardakani@Sun.COM 	 */
20811963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sizeof (match_all) / sizeof (match_all[0]); ++i) {
20911963SAfshin.Ardakani@Sun.COM 		if (strcmp(pattern, match_all[i]) == 0) {
21011963SAfshin.Ardakani@Sun.COM 			(void) strlcpy(pattern, "*", MAXPATHLEN);
21111963SAfshin.Ardakani@Sun.COM 			break;
21211963SAfshin.Ardakani@Sun.COM 		}
21311963SAfshin.Ardakani@Sun.COM 	}
21411963SAfshin.Ardakani@Sun.COM }
21511963SAfshin.Ardakani@Sun.COM 
21611963SAfshin.Ardakani@Sun.COM /*
21711963SAfshin.Ardakani@Sun.COM  * smb_sattr_check
21811963SAfshin.Ardakani@Sun.COM  *
21911963SAfshin.Ardakani@Sun.COM  * Check file attributes against a search attribute (sattr) mask.
22011963SAfshin.Ardakani@Sun.COM  *
22111963SAfshin.Ardakani@Sun.COM  * Normal files, which includes READONLY and ARCHIVE, always pass
22211963SAfshin.Ardakani@Sun.COM  * this check.  If the DIRECTORY, HIDDEN or SYSTEM special attributes
22311963SAfshin.Ardakani@Sun.COM  * are set then they must appear in the search mask.  The special
22411963SAfshin.Ardakani@Sun.COM  * attributes are inclusive, i.e. all special attributes that appear
22511963SAfshin.Ardakani@Sun.COM  * in sattr must also appear in the file attributes for the check to
22611963SAfshin.Ardakani@Sun.COM  * pass.
22711963SAfshin.Ardakani@Sun.COM  *
22811963SAfshin.Ardakani@Sun.COM  * The following examples show how this works:
22911963SAfshin.Ardakani@Sun.COM  *
23011963SAfshin.Ardakani@Sun.COM  *		fileA:	READONLY
23111963SAfshin.Ardakani@Sun.COM  *		fileB:	0 (no attributes = normal file)
23211963SAfshin.Ardakani@Sun.COM  *		fileC:	READONLY, ARCHIVE
23311963SAfshin.Ardakani@Sun.COM  *		fileD:	HIDDEN
23411963SAfshin.Ardakani@Sun.COM  *		fileE:	READONLY, HIDDEN, SYSTEM
23511963SAfshin.Ardakani@Sun.COM  *		dirA:	DIRECTORY
23611963SAfshin.Ardakani@Sun.COM  *
23711963SAfshin.Ardakani@Sun.COM  * search attribute: 0
23811963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB and fileC.
23911963SAfshin.Ardakani@Sun.COM  * search attribute: HIDDEN
24011963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB, fileC and fileD.
24111963SAfshin.Ardakani@Sun.COM  * search attribute: SYSTEM
24211963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB and fileC.
24311963SAfshin.Ardakani@Sun.COM  * search attribute: DIRECTORY
24411963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB, fileC and dirA.
24511963SAfshin.Ardakani@Sun.COM  * search attribute: HIDDEN and SYSTEM
24611963SAfshin.Ardakani@Sun.COM  *		Returns: fileA, fileB, fileC, fileD and fileE.
24711963SAfshin.Ardakani@Sun.COM  *
24811963SAfshin.Ardakani@Sun.COM  * Returns true if the file and sattr match; otherwise, returns false.
24911963SAfshin.Ardakani@Sun.COM  */
25011963SAfshin.Ardakani@Sun.COM boolean_t
25111963SAfshin.Ardakani@Sun.COM smb_sattr_check(uint16_t dosattr, uint16_t sattr)
25211963SAfshin.Ardakani@Sun.COM {
25311963SAfshin.Ardakani@Sun.COM 	if ((dosattr & FILE_ATTRIBUTE_DIRECTORY) &&
25411963SAfshin.Ardakani@Sun.COM 	    !(sattr & FILE_ATTRIBUTE_DIRECTORY))
25511963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
25611963SAfshin.Ardakani@Sun.COM 
25711963SAfshin.Ardakani@Sun.COM 	if ((dosattr & FILE_ATTRIBUTE_HIDDEN) &&
25811963SAfshin.Ardakani@Sun.COM 	    !(sattr & FILE_ATTRIBUTE_HIDDEN))
25911963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
26011963SAfshin.Ardakani@Sun.COM 
26111963SAfshin.Ardakani@Sun.COM 	if ((dosattr & FILE_ATTRIBUTE_SYSTEM) &&
26211963SAfshin.Ardakani@Sun.COM 	    !(sattr & FILE_ATTRIBUTE_SYSTEM))
26311963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
26411963SAfshin.Ardakani@Sun.COM 
26511963SAfshin.Ardakani@Sun.COM 	return (B_TRUE);
26611963SAfshin.Ardakani@Sun.COM }
26711963SAfshin.Ardakani@Sun.COM 
26811963SAfshin.Ardakani@Sun.COM int
26911963SAfshin.Ardakani@Sun.COM microtime(timestruc_t *tvp)
27011963SAfshin.Ardakani@Sun.COM {
27111963SAfshin.Ardakani@Sun.COM 	tvp->tv_sec = gethrestime_sec();
27211963SAfshin.Ardakani@Sun.COM 	tvp->tv_nsec = 0;
27311963SAfshin.Ardakani@Sun.COM 	return (0);
27411963SAfshin.Ardakani@Sun.COM }
27511963SAfshin.Ardakani@Sun.COM 
27611963SAfshin.Ardakani@Sun.COM int32_t
27711963SAfshin.Ardakani@Sun.COM clock_get_milli_uptime()
27811963SAfshin.Ardakani@Sun.COM {
27911963SAfshin.Ardakani@Sun.COM 	return (TICK_TO_MSEC(ddi_get_lbolt()));
28011963SAfshin.Ardakani@Sun.COM }
28111963SAfshin.Ardakani@Sun.COM 
28211963SAfshin.Ardakani@Sun.COM int /*ARGSUSED*/
28311963SAfshin.Ardakani@Sun.COM smb_noop(void *p, size_t size, int foo)
28411963SAfshin.Ardakani@Sun.COM {
28511963SAfshin.Ardakani@Sun.COM 	return (0);
28611963SAfshin.Ardakani@Sun.COM }
28711963SAfshin.Ardakani@Sun.COM 
28811963SAfshin.Ardakani@Sun.COM /*
28911963SAfshin.Ardakani@Sun.COM  * smb_idpool_increment
29011963SAfshin.Ardakani@Sun.COM  *
29111963SAfshin.Ardakani@Sun.COM  * This function increments the ID pool by doubling the current size. This
29211963SAfshin.Ardakani@Sun.COM  * function assumes the caller entered the mutex of the pool.
29311963SAfshin.Ardakani@Sun.COM  */
29411963SAfshin.Ardakani@Sun.COM static int
29511963SAfshin.Ardakani@Sun.COM smb_idpool_increment(
29611963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool)
29711963SAfshin.Ardakani@Sun.COM {
29811963SAfshin.Ardakani@Sun.COM 	uint8_t		*new_pool;
29911963SAfshin.Ardakani@Sun.COM 	uint32_t	new_size;
30011963SAfshin.Ardakani@Sun.COM 
30111963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
30211963SAfshin.Ardakani@Sun.COM 
30311963SAfshin.Ardakani@Sun.COM 	new_size = pool->id_size * 2;
30411963SAfshin.Ardakani@Sun.COM 	if (new_size <= SMB_IDPOOL_MAX_SIZE) {
30511963SAfshin.Ardakani@Sun.COM 		new_pool = kmem_alloc(new_size / 8, KM_NOSLEEP);
30611963SAfshin.Ardakani@Sun.COM 		if (new_pool) {
30711963SAfshin.Ardakani@Sun.COM 			bzero(new_pool, new_size / 8);
30811963SAfshin.Ardakani@Sun.COM 			bcopy(pool->id_pool, new_pool, pool->id_size / 8);
30911963SAfshin.Ardakani@Sun.COM 			kmem_free(pool->id_pool, pool->id_size / 8);
31011963SAfshin.Ardakani@Sun.COM 			pool->id_pool = new_pool;
31111963SAfshin.Ardakani@Sun.COM 			pool->id_free_counter += new_size - pool->id_size;
31211963SAfshin.Ardakani@Sun.COM 			pool->id_max_free_counter += new_size - pool->id_size;
31311963SAfshin.Ardakani@Sun.COM 			pool->id_size = new_size;
31411963SAfshin.Ardakani@Sun.COM 			pool->id_idx_msk = (new_size / 8) - 1;
31511963SAfshin.Ardakani@Sun.COM 			if (new_size >= SMB_IDPOOL_MAX_SIZE) {
31611963SAfshin.Ardakani@Sun.COM 				/* id -1 made unavailable */
31711963SAfshin.Ardakani@Sun.COM 				pool->id_pool[pool->id_idx_msk] = 0x80;
31811963SAfshin.Ardakani@Sun.COM 				pool->id_free_counter--;
31911963SAfshin.Ardakani@Sun.COM 				pool->id_max_free_counter--;
32011963SAfshin.Ardakani@Sun.COM 			}
32111963SAfshin.Ardakani@Sun.COM 			return (0);
32211963SAfshin.Ardakani@Sun.COM 		}
32311963SAfshin.Ardakani@Sun.COM 	}
32411963SAfshin.Ardakani@Sun.COM 	return (-1);
32511963SAfshin.Ardakani@Sun.COM }
32611963SAfshin.Ardakani@Sun.COM 
32711963SAfshin.Ardakani@Sun.COM /*
32811963SAfshin.Ardakani@Sun.COM  * smb_idpool_constructor
32911963SAfshin.Ardakani@Sun.COM  *
33011963SAfshin.Ardakani@Sun.COM  * This function initializes the pool structure provided.
33111963SAfshin.Ardakani@Sun.COM  */
33211963SAfshin.Ardakani@Sun.COM int
33311963SAfshin.Ardakani@Sun.COM smb_idpool_constructor(
33411963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool)
33511963SAfshin.Ardakani@Sun.COM {
33611963SAfshin.Ardakani@Sun.COM 
33711963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic != SMB_IDPOOL_MAGIC);
33811963SAfshin.Ardakani@Sun.COM 
33911963SAfshin.Ardakani@Sun.COM 	pool->id_size = SMB_IDPOOL_MIN_SIZE;
34011963SAfshin.Ardakani@Sun.COM 	pool->id_idx_msk = (SMB_IDPOOL_MIN_SIZE / 8) - 1;
34111963SAfshin.Ardakani@Sun.COM 	pool->id_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
34211963SAfshin.Ardakani@Sun.COM 	pool->id_max_free_counter = SMB_IDPOOL_MIN_SIZE - 1;
34311963SAfshin.Ardakani@Sun.COM 	pool->id_bit = 0x02;
34411963SAfshin.Ardakani@Sun.COM 	pool->id_bit_idx = 1;
34511963SAfshin.Ardakani@Sun.COM 	pool->id_idx = 0;
34611963SAfshin.Ardakani@Sun.COM 	pool->id_pool = (uint8_t *)kmem_alloc((SMB_IDPOOL_MIN_SIZE / 8),
34711963SAfshin.Ardakani@Sun.COM 	    KM_SLEEP);
34811963SAfshin.Ardakani@Sun.COM 	bzero(pool->id_pool, (SMB_IDPOOL_MIN_SIZE / 8));
34911963SAfshin.Ardakani@Sun.COM 	/* -1 id made unavailable */
35011963SAfshin.Ardakani@Sun.COM 	pool->id_pool[0] = 0x01;		/* id 0 made unavailable */
35111963SAfshin.Ardakani@Sun.COM 	mutex_init(&pool->id_mutex, NULL, MUTEX_DEFAULT, NULL);
35211963SAfshin.Ardakani@Sun.COM 	pool->id_magic = SMB_IDPOOL_MAGIC;
35311963SAfshin.Ardakani@Sun.COM 	return (0);
35411963SAfshin.Ardakani@Sun.COM }
35511963SAfshin.Ardakani@Sun.COM 
35611963SAfshin.Ardakani@Sun.COM /*
35711963SAfshin.Ardakani@Sun.COM  * smb_idpool_destructor
35811963SAfshin.Ardakani@Sun.COM  *
35911963SAfshin.Ardakani@Sun.COM  * This function tears down and frees the resources associated with the
36011963SAfshin.Ardakani@Sun.COM  * pool provided.
36111963SAfshin.Ardakani@Sun.COM  */
36211963SAfshin.Ardakani@Sun.COM void
36311963SAfshin.Ardakani@Sun.COM smb_idpool_destructor(
36411963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool)
36511963SAfshin.Ardakani@Sun.COM {
36611963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
36711963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_free_counter == pool->id_max_free_counter);
36811963SAfshin.Ardakani@Sun.COM 	pool->id_magic = (uint32_t)~SMB_IDPOOL_MAGIC;
36911963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&pool->id_mutex);
37011963SAfshin.Ardakani@Sun.COM 	kmem_free(pool->id_pool, (size_t)(pool->id_size / 8));
37111963SAfshin.Ardakani@Sun.COM }
37211963SAfshin.Ardakani@Sun.COM 
37311963SAfshin.Ardakani@Sun.COM /*
37411963SAfshin.Ardakani@Sun.COM  * smb_idpool_alloc
37511963SAfshin.Ardakani@Sun.COM  *
37611963SAfshin.Ardakani@Sun.COM  * This function allocates an ID from the pool provided.
37711963SAfshin.Ardakani@Sun.COM  */
37811963SAfshin.Ardakani@Sun.COM int
37911963SAfshin.Ardakani@Sun.COM smb_idpool_alloc(
38011963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool,
38111963SAfshin.Ardakani@Sun.COM     uint16_t		*id)
38211963SAfshin.Ardakani@Sun.COM {
38311963SAfshin.Ardakani@Sun.COM 	uint32_t	i;
38411963SAfshin.Ardakani@Sun.COM 	uint8_t		bit;
38511963SAfshin.Ardakani@Sun.COM 	uint8_t		bit_idx;
38611963SAfshin.Ardakani@Sun.COM 	uint8_t		byte;
38711963SAfshin.Ardakani@Sun.COM 
38811963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
38911963SAfshin.Ardakani@Sun.COM 
39011963SAfshin.Ardakani@Sun.COM 	mutex_enter(&pool->id_mutex);
39111963SAfshin.Ardakani@Sun.COM 	if ((pool->id_free_counter == 0) && smb_idpool_increment(pool)) {
39211963SAfshin.Ardakani@Sun.COM 		mutex_exit(&pool->id_mutex);
39311963SAfshin.Ardakani@Sun.COM 		return (-1);
39411963SAfshin.Ardakani@Sun.COM 	}
39511963SAfshin.Ardakani@Sun.COM 
39611963SAfshin.Ardakani@Sun.COM 	i = pool->id_size;
39711963SAfshin.Ardakani@Sun.COM 	while (i) {
39811963SAfshin.Ardakani@Sun.COM 		bit = pool->id_bit;
39911963SAfshin.Ardakani@Sun.COM 		bit_idx = pool->id_bit_idx;
40011963SAfshin.Ardakani@Sun.COM 		byte = pool->id_pool[pool->id_idx];
40111963SAfshin.Ardakani@Sun.COM 		while (bit) {
40211963SAfshin.Ardakani@Sun.COM 			if (byte & bit) {
40311963SAfshin.Ardakani@Sun.COM 				bit = bit << 1;
40411963SAfshin.Ardakani@Sun.COM 				bit_idx++;
40511963SAfshin.Ardakani@Sun.COM 				continue;
40611963SAfshin.Ardakani@Sun.COM 			}
40711963SAfshin.Ardakani@Sun.COM 			pool->id_pool[pool->id_idx] |= bit;
40811963SAfshin.Ardakani@Sun.COM 			*id = (uint16_t)(pool->id_idx * 8 + (uint32_t)bit_idx);
40911963SAfshin.Ardakani@Sun.COM 			pool->id_free_counter--;
41011963SAfshin.Ardakani@Sun.COM 			pool->id_bit = bit;
41111963SAfshin.Ardakani@Sun.COM 			pool->id_bit_idx = bit_idx;
41211963SAfshin.Ardakani@Sun.COM 			mutex_exit(&pool->id_mutex);
41311963SAfshin.Ardakani@Sun.COM 			return (0);
41411963SAfshin.Ardakani@Sun.COM 		}
41511963SAfshin.Ardakani@Sun.COM 		pool->id_bit = 1;
41611963SAfshin.Ardakani@Sun.COM 		pool->id_bit_idx = 0;
41711963SAfshin.Ardakani@Sun.COM 		pool->id_idx++;
41811963SAfshin.Ardakani@Sun.COM 		pool->id_idx &= pool->id_idx_msk;
41911963SAfshin.Ardakani@Sun.COM 		--i;
42011963SAfshin.Ardakani@Sun.COM 	}
42111963SAfshin.Ardakani@Sun.COM 	/*
42211963SAfshin.Ardakani@Sun.COM 	 * This section of code shouldn't be reached. If there are IDs
42311963SAfshin.Ardakani@Sun.COM 	 * available and none could be found there's a problem.
42411963SAfshin.Ardakani@Sun.COM 	 */
42511963SAfshin.Ardakani@Sun.COM 	ASSERT(0);
42611963SAfshin.Ardakani@Sun.COM 	mutex_exit(&pool->id_mutex);
42711963SAfshin.Ardakani@Sun.COM 	return (-1);
42811963SAfshin.Ardakani@Sun.COM }
42911963SAfshin.Ardakani@Sun.COM 
43011963SAfshin.Ardakani@Sun.COM /*
43111963SAfshin.Ardakani@Sun.COM  * smb_idpool_free
43211963SAfshin.Ardakani@Sun.COM  *
43311963SAfshin.Ardakani@Sun.COM  * This function frees the ID provided.
43411963SAfshin.Ardakani@Sun.COM  */
43511963SAfshin.Ardakani@Sun.COM void
43611963SAfshin.Ardakani@Sun.COM smb_idpool_free(
43711963SAfshin.Ardakani@Sun.COM     smb_idpool_t	*pool,
43811963SAfshin.Ardakani@Sun.COM     uint16_t		id)
43911963SAfshin.Ardakani@Sun.COM {
44011963SAfshin.Ardakani@Sun.COM 	ASSERT(pool->id_magic == SMB_IDPOOL_MAGIC);
44111963SAfshin.Ardakani@Sun.COM 	ASSERT(id != 0);
44211963SAfshin.Ardakani@Sun.COM 	ASSERT(id != 0xFFFF);
44311963SAfshin.Ardakani@Sun.COM 
44411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&pool->id_mutex);
44511963SAfshin.Ardakani@Sun.COM 	if (pool->id_pool[id >> 3] & (1 << (id & 7))) {
44611963SAfshin.Ardakani@Sun.COM 		pool->id_pool[id >> 3] &= ~(1 << (id & 7));
44711963SAfshin.Ardakani@Sun.COM 		pool->id_free_counter++;
44811963SAfshin.Ardakani@Sun.COM 		ASSERT(pool->id_free_counter <= pool->id_max_free_counter);
44911963SAfshin.Ardakani@Sun.COM 		mutex_exit(&pool->id_mutex);
45011963SAfshin.Ardakani@Sun.COM 		return;
45111963SAfshin.Ardakani@Sun.COM 	}
45211963SAfshin.Ardakani@Sun.COM 	/* Freeing a free ID. */
45311963SAfshin.Ardakani@Sun.COM 	ASSERT(0);
45411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&pool->id_mutex);
45511963SAfshin.Ardakani@Sun.COM }
45611963SAfshin.Ardakani@Sun.COM 
45711963SAfshin.Ardakani@Sun.COM /*
45811963SAfshin.Ardakani@Sun.COM  * Initialize the llist delete queue object cache.
45911963SAfshin.Ardakani@Sun.COM  */
46011963SAfshin.Ardakani@Sun.COM void
46111963SAfshin.Ardakani@Sun.COM smb_llist_init(void)
46211963SAfshin.Ardakani@Sun.COM {
46311963SAfshin.Ardakani@Sun.COM 	if (smb_llist_initialized)
46411963SAfshin.Ardakani@Sun.COM 		return;
46511963SAfshin.Ardakani@Sun.COM 
46611963SAfshin.Ardakani@Sun.COM 	smb_dtor_cache = kmem_cache_create("smb_dtor_cache",
46711963SAfshin.Ardakani@Sun.COM 	    sizeof (smb_dtor_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
46811963SAfshin.Ardakani@Sun.COM 
46911963SAfshin.Ardakani@Sun.COM 	smb_llist_initialized = B_TRUE;
47011963SAfshin.Ardakani@Sun.COM }
47111963SAfshin.Ardakani@Sun.COM 
47211963SAfshin.Ardakani@Sun.COM /*
47311963SAfshin.Ardakani@Sun.COM  * Destroy the llist delete queue object cache.
47411963SAfshin.Ardakani@Sun.COM  */
47511963SAfshin.Ardakani@Sun.COM void
47611963SAfshin.Ardakani@Sun.COM smb_llist_fini(void)
47711963SAfshin.Ardakani@Sun.COM {
47811963SAfshin.Ardakani@Sun.COM 	if (!smb_llist_initialized)
47911963SAfshin.Ardakani@Sun.COM 		return;
48011963SAfshin.Ardakani@Sun.COM 
48111963SAfshin.Ardakani@Sun.COM 	kmem_cache_destroy(smb_dtor_cache);
48211963SAfshin.Ardakani@Sun.COM 	smb_llist_initialized = B_FALSE;
48311963SAfshin.Ardakani@Sun.COM }
48411963SAfshin.Ardakani@Sun.COM 
48511963SAfshin.Ardakani@Sun.COM /*
48611963SAfshin.Ardakani@Sun.COM  * smb_llist_constructor
48711963SAfshin.Ardakani@Sun.COM  *
48811963SAfshin.Ardakani@Sun.COM  * This function initializes a locked list.
48911963SAfshin.Ardakani@Sun.COM  */
49011963SAfshin.Ardakani@Sun.COM void
49111963SAfshin.Ardakani@Sun.COM smb_llist_constructor(
49211963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
49311963SAfshin.Ardakani@Sun.COM     size_t	size,
49411963SAfshin.Ardakani@Sun.COM     size_t	offset)
49511963SAfshin.Ardakani@Sun.COM {
49611963SAfshin.Ardakani@Sun.COM 	rw_init(&ll->ll_lock, NULL, RW_DEFAULT, NULL);
49711963SAfshin.Ardakani@Sun.COM 	mutex_init(&ll->ll_mutex, NULL, MUTEX_DEFAULT, NULL);
49811963SAfshin.Ardakani@Sun.COM 	list_create(&ll->ll_list, size, offset);
49911963SAfshin.Ardakani@Sun.COM 	list_create(&ll->ll_deleteq, sizeof (smb_dtor_t),
50011963SAfshin.Ardakani@Sun.COM 	    offsetof(smb_dtor_t, dt_lnd));
50111963SAfshin.Ardakani@Sun.COM 	ll->ll_count = 0;
50211963SAfshin.Ardakani@Sun.COM 	ll->ll_wrop = 0;
50311963SAfshin.Ardakani@Sun.COM 	ll->ll_deleteq_count = 0;
50411963SAfshin.Ardakani@Sun.COM }
50511963SAfshin.Ardakani@Sun.COM 
50611963SAfshin.Ardakani@Sun.COM /*
50711963SAfshin.Ardakani@Sun.COM  * Flush the delete queue and destroy a locked list.
50811963SAfshin.Ardakani@Sun.COM  */
50911963SAfshin.Ardakani@Sun.COM void
51011963SAfshin.Ardakani@Sun.COM smb_llist_destructor(
51111963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll)
51211963SAfshin.Ardakani@Sun.COM {
51311963SAfshin.Ardakani@Sun.COM 	smb_llist_flush(ll);
51411963SAfshin.Ardakani@Sun.COM 
51511963SAfshin.Ardakani@Sun.COM 	ASSERT(ll->ll_count == 0);
51611963SAfshin.Ardakani@Sun.COM 	ASSERT(ll->ll_deleteq_count == 0);
51711963SAfshin.Ardakani@Sun.COM 
51811963SAfshin.Ardakani@Sun.COM 	rw_destroy(&ll->ll_lock);
51911963SAfshin.Ardakani@Sun.COM 	list_destroy(&ll->ll_list);
52011963SAfshin.Ardakani@Sun.COM 	list_destroy(&ll->ll_deleteq);
52111963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&ll->ll_mutex);
52211963SAfshin.Ardakani@Sun.COM }
52311963SAfshin.Ardakani@Sun.COM 
52411963SAfshin.Ardakani@Sun.COM /*
52511963SAfshin.Ardakani@Sun.COM  * Post an object to the delete queue.  The delete queue will be processed
52611963SAfshin.Ardakani@Sun.COM  * during list exit or list destruction.  Objects are often posted for
52711963SAfshin.Ardakani@Sun.COM  * deletion during list iteration (while the list is locked) but that is
52811963SAfshin.Ardakani@Sun.COM  * not required, and an object can be posted at any time.
52911963SAfshin.Ardakani@Sun.COM  */
53011963SAfshin.Ardakani@Sun.COM void
53111963SAfshin.Ardakani@Sun.COM smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc)
53211963SAfshin.Ardakani@Sun.COM {
53311963SAfshin.Ardakani@Sun.COM 	smb_dtor_t	*dtor;
53411963SAfshin.Ardakani@Sun.COM 
53511963SAfshin.Ardakani@Sun.COM 	ASSERT((object != NULL) && (dtorproc != NULL));
53611963SAfshin.Ardakani@Sun.COM 
53711963SAfshin.Ardakani@Sun.COM 	dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP);
53811963SAfshin.Ardakani@Sun.COM 	bzero(dtor, sizeof (smb_dtor_t));
53911963SAfshin.Ardakani@Sun.COM 	dtor->dt_magic = SMB_DTOR_MAGIC;
54011963SAfshin.Ardakani@Sun.COM 	dtor->dt_object = object;
54111963SAfshin.Ardakani@Sun.COM 	dtor->dt_proc = dtorproc;
54211963SAfshin.Ardakani@Sun.COM 
54311963SAfshin.Ardakani@Sun.COM 	mutex_enter(&ll->ll_mutex);
54411963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&ll->ll_deleteq, dtor);
54511963SAfshin.Ardakani@Sun.COM 	++ll->ll_deleteq_count;
54611963SAfshin.Ardakani@Sun.COM 	mutex_exit(&ll->ll_mutex);
54711963SAfshin.Ardakani@Sun.COM }
54811963SAfshin.Ardakani@Sun.COM 
54911963SAfshin.Ardakani@Sun.COM /*
55011963SAfshin.Ardakani@Sun.COM  * Exit the list lock and process the delete queue.
55111963SAfshin.Ardakani@Sun.COM  */
55211963SAfshin.Ardakani@Sun.COM void
55311963SAfshin.Ardakani@Sun.COM smb_llist_exit(smb_llist_t *ll)
55411963SAfshin.Ardakani@Sun.COM {
55511963SAfshin.Ardakani@Sun.COM 	rw_exit(&ll->ll_lock);
55611963SAfshin.Ardakani@Sun.COM 	smb_llist_flush(ll);
55711963SAfshin.Ardakani@Sun.COM }
55811963SAfshin.Ardakani@Sun.COM 
55911963SAfshin.Ardakani@Sun.COM /*
56011963SAfshin.Ardakani@Sun.COM  * Flush the list delete queue.  The mutex is dropped across the destructor
56111963SAfshin.Ardakani@Sun.COM  * call in case this leads to additional objects being posted to the delete
56211963SAfshin.Ardakani@Sun.COM  * queue.
56311963SAfshin.Ardakani@Sun.COM  */
56412065SKeyur.Desai@Sun.COM void
56511963SAfshin.Ardakani@Sun.COM smb_llist_flush(smb_llist_t *ll)
56611963SAfshin.Ardakani@Sun.COM {
56711963SAfshin.Ardakani@Sun.COM 	smb_dtor_t    *dtor;
56811963SAfshin.Ardakani@Sun.COM 
56911963SAfshin.Ardakani@Sun.COM 	mutex_enter(&ll->ll_mutex);
57011963SAfshin.Ardakani@Sun.COM 
57111963SAfshin.Ardakani@Sun.COM 	dtor = list_head(&ll->ll_deleteq);
57211963SAfshin.Ardakani@Sun.COM 	while (dtor != NULL) {
57311963SAfshin.Ardakani@Sun.COM 		SMB_DTOR_VALID(dtor);
57411963SAfshin.Ardakani@Sun.COM 		ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL));
57511963SAfshin.Ardakani@Sun.COM 		list_remove(&ll->ll_deleteq, dtor);
57611963SAfshin.Ardakani@Sun.COM 		--ll->ll_deleteq_count;
57711963SAfshin.Ardakani@Sun.COM 		mutex_exit(&ll->ll_mutex);
57811963SAfshin.Ardakani@Sun.COM 
57911963SAfshin.Ardakani@Sun.COM 		dtor->dt_proc(dtor->dt_object);
58011963SAfshin.Ardakani@Sun.COM 
58111963SAfshin.Ardakani@Sun.COM 		dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC;
58211963SAfshin.Ardakani@Sun.COM 		kmem_cache_free(smb_dtor_cache, dtor);
58311963SAfshin.Ardakani@Sun.COM 		mutex_enter(&ll->ll_mutex);
58411963SAfshin.Ardakani@Sun.COM 		dtor = list_head(&ll->ll_deleteq);
58511963SAfshin.Ardakani@Sun.COM 	}
58611963SAfshin.Ardakani@Sun.COM 
58711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&ll->ll_mutex);
58811963SAfshin.Ardakani@Sun.COM }
58911963SAfshin.Ardakani@Sun.COM 
59011963SAfshin.Ardakani@Sun.COM /*
59111963SAfshin.Ardakani@Sun.COM  * smb_llist_upgrade
59211963SAfshin.Ardakani@Sun.COM  *
59311963SAfshin.Ardakani@Sun.COM  * This function tries to upgrade the lock of the locked list. It assumes the
59411963SAfshin.Ardakani@Sun.COM  * locked has already been entered in RW_READER mode. It first tries using the
59511963SAfshin.Ardakani@Sun.COM  * Solaris function rw_tryupgrade(). If that call fails the lock is released
59611963SAfshin.Ardakani@Sun.COM  * and reentered in RW_WRITER mode. In that last case a window is opened during
59711963SAfshin.Ardakani@Sun.COM  * which the contents of the list may have changed. The return code indicates
59811963SAfshin.Ardakani@Sun.COM  * whether or not the list was modified when the lock was exited.
59911963SAfshin.Ardakani@Sun.COM  */
60011963SAfshin.Ardakani@Sun.COM int smb_llist_upgrade(
60111963SAfshin.Ardakani@Sun.COM     smb_llist_t *ll)
60211963SAfshin.Ardakani@Sun.COM {
60311963SAfshin.Ardakani@Sun.COM 	uint64_t	wrop;
60411963SAfshin.Ardakani@Sun.COM 
60511963SAfshin.Ardakani@Sun.COM 	if (rw_tryupgrade(&ll->ll_lock) != 0) {
60611963SAfshin.Ardakani@Sun.COM 		return (0);
60711963SAfshin.Ardakani@Sun.COM 	}
60811963SAfshin.Ardakani@Sun.COM 	wrop = ll->ll_wrop;
60911963SAfshin.Ardakani@Sun.COM 	rw_exit(&ll->ll_lock);
61011963SAfshin.Ardakani@Sun.COM 	rw_enter(&ll->ll_lock, RW_WRITER);
61111963SAfshin.Ardakani@Sun.COM 	return (wrop != ll->ll_wrop);
61211963SAfshin.Ardakani@Sun.COM }
61311963SAfshin.Ardakani@Sun.COM 
61411963SAfshin.Ardakani@Sun.COM /*
61511963SAfshin.Ardakani@Sun.COM  * smb_llist_insert_head
61611963SAfshin.Ardakani@Sun.COM  *
61711963SAfshin.Ardakani@Sun.COM  * This function inserts the object passed a the beginning of the list. This
61811963SAfshin.Ardakani@Sun.COM  * function assumes the lock of the list has already been entered.
61911963SAfshin.Ardakani@Sun.COM  */
62011963SAfshin.Ardakani@Sun.COM void
62111963SAfshin.Ardakani@Sun.COM smb_llist_insert_head(
62211963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
62311963SAfshin.Ardakani@Sun.COM     void	*obj)
62411963SAfshin.Ardakani@Sun.COM {
62511963SAfshin.Ardakani@Sun.COM 	list_insert_head(&ll->ll_list, obj);
62611963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
62711963SAfshin.Ardakani@Sun.COM 	++ll->ll_count;
62811963SAfshin.Ardakani@Sun.COM }
62911963SAfshin.Ardakani@Sun.COM 
63011963SAfshin.Ardakani@Sun.COM /*
63111963SAfshin.Ardakani@Sun.COM  * smb_llist_insert_tail
63211963SAfshin.Ardakani@Sun.COM  *
63311963SAfshin.Ardakani@Sun.COM  * This function appends to the object passed to the list. This function assumes
63411963SAfshin.Ardakani@Sun.COM  * the lock of the list has already been entered.
63511963SAfshin.Ardakani@Sun.COM  *
63611963SAfshin.Ardakani@Sun.COM  */
63711963SAfshin.Ardakani@Sun.COM void
63811963SAfshin.Ardakani@Sun.COM smb_llist_insert_tail(
63911963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
64011963SAfshin.Ardakani@Sun.COM     void	*obj)
64111963SAfshin.Ardakani@Sun.COM {
64211963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&ll->ll_list, obj);
64311963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
64411963SAfshin.Ardakani@Sun.COM 	++ll->ll_count;
64511963SAfshin.Ardakani@Sun.COM }
64611963SAfshin.Ardakani@Sun.COM 
64711963SAfshin.Ardakani@Sun.COM /*
64811963SAfshin.Ardakani@Sun.COM  * smb_llist_remove
64911963SAfshin.Ardakani@Sun.COM  *
65011963SAfshin.Ardakani@Sun.COM  * This function removes the object passed from the list. This function assumes
65111963SAfshin.Ardakani@Sun.COM  * the lock of the list has already been entered.
65211963SAfshin.Ardakani@Sun.COM  */
65311963SAfshin.Ardakani@Sun.COM void
65411963SAfshin.Ardakani@Sun.COM smb_llist_remove(
65511963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
65611963SAfshin.Ardakani@Sun.COM     void	*obj)
65711963SAfshin.Ardakani@Sun.COM {
65811963SAfshin.Ardakani@Sun.COM 	list_remove(&ll->ll_list, obj);
65911963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
66011963SAfshin.Ardakani@Sun.COM 	--ll->ll_count;
66111963SAfshin.Ardakani@Sun.COM }
66211963SAfshin.Ardakani@Sun.COM 
66311963SAfshin.Ardakani@Sun.COM /*
66411963SAfshin.Ardakani@Sun.COM  * smb_llist_get_count
66511963SAfshin.Ardakani@Sun.COM  *
66611963SAfshin.Ardakani@Sun.COM  * This function returns the number of elements in the specified list.
66711963SAfshin.Ardakani@Sun.COM  */
66811963SAfshin.Ardakani@Sun.COM uint32_t
66911963SAfshin.Ardakani@Sun.COM smb_llist_get_count(
67011963SAfshin.Ardakani@Sun.COM     smb_llist_t *ll)
67111963SAfshin.Ardakani@Sun.COM {
67211963SAfshin.Ardakani@Sun.COM 	return (ll->ll_count);
67311963SAfshin.Ardakani@Sun.COM }
67411963SAfshin.Ardakani@Sun.COM 
67511963SAfshin.Ardakani@Sun.COM /*
67611963SAfshin.Ardakani@Sun.COM  * smb_slist_constructor
67711963SAfshin.Ardakani@Sun.COM  *
67811963SAfshin.Ardakani@Sun.COM  * Synchronized list constructor.
67911963SAfshin.Ardakani@Sun.COM  */
68011963SAfshin.Ardakani@Sun.COM void
68111963SAfshin.Ardakani@Sun.COM smb_slist_constructor(
68211963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
68311963SAfshin.Ardakani@Sun.COM     size_t	size,
68411963SAfshin.Ardakani@Sun.COM     size_t	offset)
68511963SAfshin.Ardakani@Sun.COM {
68611963SAfshin.Ardakani@Sun.COM 	mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL);
68711963SAfshin.Ardakani@Sun.COM 	cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL);
68811963SAfshin.Ardakani@Sun.COM 	list_create(&sl->sl_list, size, offset);
68911963SAfshin.Ardakani@Sun.COM 	sl->sl_count = 0;
69011963SAfshin.Ardakani@Sun.COM 	sl->sl_waiting = B_FALSE;
69111963SAfshin.Ardakani@Sun.COM }
69211963SAfshin.Ardakani@Sun.COM 
69311963SAfshin.Ardakani@Sun.COM /*
69411963SAfshin.Ardakani@Sun.COM  * smb_slist_destructor
69511963SAfshin.Ardakani@Sun.COM  *
69611963SAfshin.Ardakani@Sun.COM  * Synchronized list destructor.
69711963SAfshin.Ardakani@Sun.COM  */
69811963SAfshin.Ardakani@Sun.COM void
69911963SAfshin.Ardakani@Sun.COM smb_slist_destructor(
70011963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
70111963SAfshin.Ardakani@Sun.COM {
702*12508Samw@Sun.COM 	VERIFY(sl->sl_count == 0);
70311963SAfshin.Ardakani@Sun.COM 
70411963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&sl->sl_mutex);
70511963SAfshin.Ardakani@Sun.COM 	cv_destroy(&sl->sl_cv);
70611963SAfshin.Ardakani@Sun.COM 	list_destroy(&sl->sl_list);
70711963SAfshin.Ardakani@Sun.COM }
70811963SAfshin.Ardakani@Sun.COM 
70911963SAfshin.Ardakani@Sun.COM /*
71011963SAfshin.Ardakani@Sun.COM  * smb_slist_insert_head
71111963SAfshin.Ardakani@Sun.COM  *
71211963SAfshin.Ardakani@Sun.COM  * This function inserts the object passed a the beginning of the list.
71311963SAfshin.Ardakani@Sun.COM  */
71411963SAfshin.Ardakani@Sun.COM void
71511963SAfshin.Ardakani@Sun.COM smb_slist_insert_head(
71611963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
71711963SAfshin.Ardakani@Sun.COM     void	*obj)
71811963SAfshin.Ardakani@Sun.COM {
71911963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
72011963SAfshin.Ardakani@Sun.COM 	list_insert_head(&sl->sl_list, obj);
72111963SAfshin.Ardakani@Sun.COM 	++sl->sl_count;
72211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
72311963SAfshin.Ardakani@Sun.COM }
72411963SAfshin.Ardakani@Sun.COM 
72511963SAfshin.Ardakani@Sun.COM /*
72611963SAfshin.Ardakani@Sun.COM  * smb_slist_insert_tail
72711963SAfshin.Ardakani@Sun.COM  *
72811963SAfshin.Ardakani@Sun.COM  * This function appends the object passed to the list.
72911963SAfshin.Ardakani@Sun.COM  */
73011963SAfshin.Ardakani@Sun.COM void
73111963SAfshin.Ardakani@Sun.COM smb_slist_insert_tail(
73211963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
73311963SAfshin.Ardakani@Sun.COM     void	*obj)
73411963SAfshin.Ardakani@Sun.COM {
73511963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
73611963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&sl->sl_list, obj);
73711963SAfshin.Ardakani@Sun.COM 	++sl->sl_count;
73811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
73911963SAfshin.Ardakani@Sun.COM }
74011963SAfshin.Ardakani@Sun.COM 
74111963SAfshin.Ardakani@Sun.COM /*
74211963SAfshin.Ardakani@Sun.COM  * smb_llist_remove
74311963SAfshin.Ardakani@Sun.COM  *
74411963SAfshin.Ardakani@Sun.COM  * This function removes the object passed by the caller from the list.
74511963SAfshin.Ardakani@Sun.COM  */
74611963SAfshin.Ardakani@Sun.COM void
74711963SAfshin.Ardakani@Sun.COM smb_slist_remove(
74811963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
74911963SAfshin.Ardakani@Sun.COM     void	*obj)
75011963SAfshin.Ardakani@Sun.COM {
75111963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
75211963SAfshin.Ardakani@Sun.COM 	list_remove(&sl->sl_list, obj);
75311963SAfshin.Ardakani@Sun.COM 	if ((--sl->sl_count == 0) && (sl->sl_waiting)) {
75411963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_FALSE;
75511963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&sl->sl_cv);
75611963SAfshin.Ardakani@Sun.COM 	}
75711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
75811963SAfshin.Ardakani@Sun.COM }
75911963SAfshin.Ardakani@Sun.COM 
76011963SAfshin.Ardakani@Sun.COM /*
76111963SAfshin.Ardakani@Sun.COM  * smb_slist_move_tail
76211963SAfshin.Ardakani@Sun.COM  *
76311963SAfshin.Ardakani@Sun.COM  * This function transfers all the contents of the synchronized list to the
76411963SAfshin.Ardakani@Sun.COM  * list_t provided. It returns the number of objects transferred.
76511963SAfshin.Ardakani@Sun.COM  */
76611963SAfshin.Ardakani@Sun.COM uint32_t
76711963SAfshin.Ardakani@Sun.COM smb_slist_move_tail(
76811963SAfshin.Ardakani@Sun.COM     list_t	*lst,
76911963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
77011963SAfshin.Ardakani@Sun.COM {
77111963SAfshin.Ardakani@Sun.COM 	uint32_t	rv;
77211963SAfshin.Ardakani@Sun.COM 
77311963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
77411963SAfshin.Ardakani@Sun.COM 	rv = sl->sl_count;
77511963SAfshin.Ardakani@Sun.COM 	if (sl->sl_count) {
77611963SAfshin.Ardakani@Sun.COM 		list_move_tail(lst, &sl->sl_list);
77711963SAfshin.Ardakani@Sun.COM 		sl->sl_count = 0;
77811963SAfshin.Ardakani@Sun.COM 		if (sl->sl_waiting) {
77911963SAfshin.Ardakani@Sun.COM 			sl->sl_waiting = B_FALSE;
78011963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&sl->sl_cv);
78111963SAfshin.Ardakani@Sun.COM 		}
78211963SAfshin.Ardakani@Sun.COM 	}
78311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
78411963SAfshin.Ardakani@Sun.COM 	return (rv);
78511963SAfshin.Ardakani@Sun.COM }
78611963SAfshin.Ardakani@Sun.COM 
78711963SAfshin.Ardakani@Sun.COM /*
78811963SAfshin.Ardakani@Sun.COM  * smb_slist_obj_move
78911963SAfshin.Ardakani@Sun.COM  *
79011963SAfshin.Ardakani@Sun.COM  * This function moves an object from one list to the end of the other list. It
79111963SAfshin.Ardakani@Sun.COM  * assumes the mutex of each list has been entered.
79211963SAfshin.Ardakani@Sun.COM  */
79311963SAfshin.Ardakani@Sun.COM void
79411963SAfshin.Ardakani@Sun.COM smb_slist_obj_move(
79511963SAfshin.Ardakani@Sun.COM     smb_slist_t	*dst,
79611963SAfshin.Ardakani@Sun.COM     smb_slist_t	*src,
79711963SAfshin.Ardakani@Sun.COM     void	*obj)
79811963SAfshin.Ardakani@Sun.COM {
79911963SAfshin.Ardakani@Sun.COM 	ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset);
80011963SAfshin.Ardakani@Sun.COM 	ASSERT(dst->sl_list.list_size == src->sl_list.list_size);
80111963SAfshin.Ardakani@Sun.COM 
80211963SAfshin.Ardakani@Sun.COM 	list_remove(&src->sl_list, obj);
80311963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&dst->sl_list, obj);
80411963SAfshin.Ardakani@Sun.COM 	dst->sl_count++;
80511963SAfshin.Ardakani@Sun.COM 	src->sl_count--;
80611963SAfshin.Ardakani@Sun.COM 	if ((src->sl_count == 0) && (src->sl_waiting)) {
80711963SAfshin.Ardakani@Sun.COM 		src->sl_waiting = B_FALSE;
80811963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&src->sl_cv);
80911963SAfshin.Ardakani@Sun.COM 	}
81011963SAfshin.Ardakani@Sun.COM }
81111963SAfshin.Ardakani@Sun.COM 
81211963SAfshin.Ardakani@Sun.COM /*
81311963SAfshin.Ardakani@Sun.COM  * smb_slist_wait_for_empty
81411963SAfshin.Ardakani@Sun.COM  *
81511963SAfshin.Ardakani@Sun.COM  * This function waits for a list to be emptied.
81611963SAfshin.Ardakani@Sun.COM  */
81711963SAfshin.Ardakani@Sun.COM void
81811963SAfshin.Ardakani@Sun.COM smb_slist_wait_for_empty(
81911963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
82011963SAfshin.Ardakani@Sun.COM {
82111963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
82211963SAfshin.Ardakani@Sun.COM 	while (sl->sl_count) {
82311963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_TRUE;
82411963SAfshin.Ardakani@Sun.COM 		cv_wait(&sl->sl_cv, &sl->sl_mutex);
82511963SAfshin.Ardakani@Sun.COM 	}
82611963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
82711963SAfshin.Ardakani@Sun.COM }
82811963SAfshin.Ardakani@Sun.COM 
82911963SAfshin.Ardakani@Sun.COM /*
83011963SAfshin.Ardakani@Sun.COM  * smb_slist_exit
83111963SAfshin.Ardakani@Sun.COM  *
83211963SAfshin.Ardakani@Sun.COM  * This function exits the muetx of the list and signal the condition variable
83311963SAfshin.Ardakani@Sun.COM  * if the list is empty.
83411963SAfshin.Ardakani@Sun.COM  */
83511963SAfshin.Ardakani@Sun.COM void
83611963SAfshin.Ardakani@Sun.COM smb_slist_exit(smb_slist_t *sl)
83711963SAfshin.Ardakani@Sun.COM {
83811963SAfshin.Ardakani@Sun.COM 	if ((sl->sl_count == 0) && (sl->sl_waiting)) {
83911963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_FALSE;
84011963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&sl->sl_cv);
84111963SAfshin.Ardakani@Sun.COM 	}
84211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
84311963SAfshin.Ardakani@Sun.COM }
84411963SAfshin.Ardakani@Sun.COM 
84511963SAfshin.Ardakani@Sun.COM /*
84611963SAfshin.Ardakani@Sun.COM  * smb_thread_entry_point
84711963SAfshin.Ardakani@Sun.COM  *
84811963SAfshin.Ardakani@Sun.COM  * Common entry point for all the threads created through smb_thread_start.
84911963SAfshin.Ardakani@Sun.COM  * The state of the thread is set to "running" at the beginning and moved to
85011963SAfshin.Ardakani@Sun.COM  * "exiting" just before calling thread_exit(). The condition variable is
85111963SAfshin.Ardakani@Sun.COM  *  also signaled.
85211963SAfshin.Ardakani@Sun.COM  */
85311963SAfshin.Ardakani@Sun.COM static void
85411963SAfshin.Ardakani@Sun.COM smb_thread_entry_point(
85511963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
85611963SAfshin.Ardakani@Sun.COM {
85711963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
85811963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
85911963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING);
86011963SAfshin.Ardakani@Sun.COM 	thread->sth_th = curthread;
86111963SAfshin.Ardakani@Sun.COM 	thread->sth_did = thread->sth_th->t_did;
86211963SAfshin.Ardakani@Sun.COM 
86311963SAfshin.Ardakani@Sun.COM 	if (!thread->sth_kill) {
86411963SAfshin.Ardakani@Sun.COM 		thread->sth_state = SMB_THREAD_STATE_RUNNING;
86511963SAfshin.Ardakani@Sun.COM 		cv_signal(&thread->sth_cv);
86611963SAfshin.Ardakani@Sun.COM 		mutex_exit(&thread->sth_mtx);
86711963SAfshin.Ardakani@Sun.COM 		thread->sth_ep(thread, thread->sth_ep_arg);
86811963SAfshin.Ardakani@Sun.COM 		mutex_enter(&thread->sth_mtx);
86911963SAfshin.Ardakani@Sun.COM 	}
87011963SAfshin.Ardakani@Sun.COM 	thread->sth_th = NULL;
87111963SAfshin.Ardakani@Sun.COM 	thread->sth_state = SMB_THREAD_STATE_EXITING;
87211963SAfshin.Ardakani@Sun.COM 	cv_broadcast(&thread->sth_cv);
87311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
87411963SAfshin.Ardakani@Sun.COM 	thread_exit();
87511963SAfshin.Ardakani@Sun.COM }
87611963SAfshin.Ardakani@Sun.COM 
87711963SAfshin.Ardakani@Sun.COM /*
87811963SAfshin.Ardakani@Sun.COM  * smb_thread_init
87911963SAfshin.Ardakani@Sun.COM  */
88011963SAfshin.Ardakani@Sun.COM void
88111963SAfshin.Ardakani@Sun.COM smb_thread_init(
88211963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread,
88311963SAfshin.Ardakani@Sun.COM     char		*name,
88411963SAfshin.Ardakani@Sun.COM     smb_thread_ep_t	ep,
88511963SAfshin.Ardakani@Sun.COM     void		*ep_arg,
88611963SAfshin.Ardakani@Sun.COM     smb_thread_aw_t	aw,
88711963SAfshin.Ardakani@Sun.COM     void		*aw_arg)
88811963SAfshin.Ardakani@Sun.COM {
88911963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic != SMB_THREAD_MAGIC);
89011963SAfshin.Ardakani@Sun.COM 
89111963SAfshin.Ardakani@Sun.COM 	bzero(thread, sizeof (*thread));
89211963SAfshin.Ardakani@Sun.COM 
89311963SAfshin.Ardakani@Sun.COM 	(void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name));
89411963SAfshin.Ardakani@Sun.COM 	thread->sth_ep = ep;
89511963SAfshin.Ardakani@Sun.COM 	thread->sth_ep_arg = ep_arg;
89611963SAfshin.Ardakani@Sun.COM 	thread->sth_aw = aw;
89711963SAfshin.Ardakani@Sun.COM 	thread->sth_aw_arg = aw_arg;
89811963SAfshin.Ardakani@Sun.COM 	thread->sth_state = SMB_THREAD_STATE_EXITED;
89911963SAfshin.Ardakani@Sun.COM 	mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL);
90011963SAfshin.Ardakani@Sun.COM 	cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL);
90111963SAfshin.Ardakani@Sun.COM 	thread->sth_magic = SMB_THREAD_MAGIC;
90211963SAfshin.Ardakani@Sun.COM }
90311963SAfshin.Ardakani@Sun.COM 
90411963SAfshin.Ardakani@Sun.COM /*
90511963SAfshin.Ardakani@Sun.COM  * smb_thread_destroy
90611963SAfshin.Ardakani@Sun.COM  */
90711963SAfshin.Ardakani@Sun.COM void
90811963SAfshin.Ardakani@Sun.COM smb_thread_destroy(
90911963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
91011963SAfshin.Ardakani@Sun.COM {
91111963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
91211963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED);
91311963SAfshin.Ardakani@Sun.COM 	thread->sth_magic = 0;
91411963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&thread->sth_mtx);
91511963SAfshin.Ardakani@Sun.COM 	cv_destroy(&thread->sth_cv);
91611963SAfshin.Ardakani@Sun.COM }
91711963SAfshin.Ardakani@Sun.COM 
91811963SAfshin.Ardakani@Sun.COM /*
91911963SAfshin.Ardakani@Sun.COM  * smb_thread_start
92011963SAfshin.Ardakani@Sun.COM  *
92111963SAfshin.Ardakani@Sun.COM  * This function starts a thread with the parameters provided. It waits until
92211963SAfshin.Ardakani@Sun.COM  * the state of the thread has been moved to running.
92311963SAfshin.Ardakani@Sun.COM  */
92411963SAfshin.Ardakani@Sun.COM /*ARGSUSED*/
92511963SAfshin.Ardakani@Sun.COM int
92611963SAfshin.Ardakani@Sun.COM smb_thread_start(
92711963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
92811963SAfshin.Ardakani@Sun.COM {
92911963SAfshin.Ardakani@Sun.COM 	int		rc = 0;
93011963SAfshin.Ardakani@Sun.COM 	kthread_t	*tmpthread;
93111963SAfshin.Ardakani@Sun.COM 
93211963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
93311963SAfshin.Ardakani@Sun.COM 
93411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
93511963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
93611963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_EXITED:
93711963SAfshin.Ardakani@Sun.COM 		thread->sth_state = SMB_THREAD_STATE_STARTING;
93811963SAfshin.Ardakani@Sun.COM 		mutex_exit(&thread->sth_mtx);
93911963SAfshin.Ardakani@Sun.COM 		tmpthread = thread_create(NULL, 0, smb_thread_entry_point,
94011963SAfshin.Ardakani@Sun.COM 		    thread, 0, &p0, TS_RUN, minclsyspri);
94111963SAfshin.Ardakani@Sun.COM 		ASSERT(tmpthread != NULL);
94211963SAfshin.Ardakani@Sun.COM 		mutex_enter(&thread->sth_mtx);
94311963SAfshin.Ardakani@Sun.COM 		while (thread->sth_state == SMB_THREAD_STATE_STARTING)
94411963SAfshin.Ardakani@Sun.COM 			cv_wait(&thread->sth_cv, &thread->sth_mtx);
94511963SAfshin.Ardakani@Sun.COM 		if (thread->sth_state != SMB_THREAD_STATE_RUNNING)
94611963SAfshin.Ardakani@Sun.COM 			rc = -1;
94711963SAfshin.Ardakani@Sun.COM 		break;
94811963SAfshin.Ardakani@Sun.COM 	default:
94911963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
95011963SAfshin.Ardakani@Sun.COM 		rc = -1;
95111963SAfshin.Ardakani@Sun.COM 		break;
95211963SAfshin.Ardakani@Sun.COM 	}
95311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
95411963SAfshin.Ardakani@Sun.COM 	return (rc);
95511963SAfshin.Ardakani@Sun.COM }
95611963SAfshin.Ardakani@Sun.COM 
95711963SAfshin.Ardakani@Sun.COM /*
95811963SAfshin.Ardakani@Sun.COM  * smb_thread_stop
95911963SAfshin.Ardakani@Sun.COM  *
96011963SAfshin.Ardakani@Sun.COM  * This function signals a thread to kill itself and waits until the "exiting"
96111963SAfshin.Ardakani@Sun.COM  * state has been reached.
96211963SAfshin.Ardakani@Sun.COM  */
96311963SAfshin.Ardakani@Sun.COM void
96411963SAfshin.Ardakani@Sun.COM smb_thread_stop(
96511963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
96611963SAfshin.Ardakani@Sun.COM {
96711963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
96811963SAfshin.Ardakani@Sun.COM 
96911963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
97011963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
97111963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_RUNNING:
97211963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_STARTING:
97311963SAfshin.Ardakani@Sun.COM 		if (!thread->sth_kill) {
97411963SAfshin.Ardakani@Sun.COM 			thread->sth_kill = B_TRUE;
97511963SAfshin.Ardakani@Sun.COM 			if (thread->sth_aw)
97611963SAfshin.Ardakani@Sun.COM 				thread->sth_aw(thread, thread->sth_aw_arg);
97711963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&thread->sth_cv);
97811963SAfshin.Ardakani@Sun.COM 			while (thread->sth_state != SMB_THREAD_STATE_EXITING)
97911963SAfshin.Ardakani@Sun.COM 				cv_wait(&thread->sth_cv, &thread->sth_mtx);
98011963SAfshin.Ardakani@Sun.COM 			mutex_exit(&thread->sth_mtx);
98111963SAfshin.Ardakani@Sun.COM 			thread_join(thread->sth_did);
98211963SAfshin.Ardakani@Sun.COM 			mutex_enter(&thread->sth_mtx);
98311963SAfshin.Ardakani@Sun.COM 			thread->sth_state = SMB_THREAD_STATE_EXITED;
98411963SAfshin.Ardakani@Sun.COM 			thread->sth_did = 0;
98511963SAfshin.Ardakani@Sun.COM 			thread->sth_kill = B_FALSE;
98611963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&thread->sth_cv);
98711963SAfshin.Ardakani@Sun.COM 			break;
98811963SAfshin.Ardakani@Sun.COM 		}
98911963SAfshin.Ardakani@Sun.COM 		/*FALLTHRU*/
99011963SAfshin.Ardakani@Sun.COM 
99111963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_EXITING:
99211963SAfshin.Ardakani@Sun.COM 		if (thread->sth_kill) {
99311963SAfshin.Ardakani@Sun.COM 			while (thread->sth_state != SMB_THREAD_STATE_EXITED)
99411963SAfshin.Ardakani@Sun.COM 				cv_wait(&thread->sth_cv, &thread->sth_mtx);
99511963SAfshin.Ardakani@Sun.COM 		} else {
99611963SAfshin.Ardakani@Sun.COM 			thread->sth_state = SMB_THREAD_STATE_EXITED;
99711963SAfshin.Ardakani@Sun.COM 			thread->sth_did = 0;
99811963SAfshin.Ardakani@Sun.COM 		}
99911963SAfshin.Ardakani@Sun.COM 		break;
100011963SAfshin.Ardakani@Sun.COM 
100111963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_EXITED:
100211963SAfshin.Ardakani@Sun.COM 		break;
100311963SAfshin.Ardakani@Sun.COM 
100411963SAfshin.Ardakani@Sun.COM 	default:
100511963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
100611963SAfshin.Ardakani@Sun.COM 		break;
100711963SAfshin.Ardakani@Sun.COM 	}
100811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
100911963SAfshin.Ardakani@Sun.COM }
101011963SAfshin.Ardakani@Sun.COM 
101111963SAfshin.Ardakani@Sun.COM /*
101211963SAfshin.Ardakani@Sun.COM  * smb_thread_signal
101311963SAfshin.Ardakani@Sun.COM  *
101411963SAfshin.Ardakani@Sun.COM  * This function signals a thread.
101511963SAfshin.Ardakani@Sun.COM  */
101611963SAfshin.Ardakani@Sun.COM void
101711963SAfshin.Ardakani@Sun.COM smb_thread_signal(
101811963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
101911963SAfshin.Ardakani@Sun.COM {
102011963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
102111963SAfshin.Ardakani@Sun.COM 
102211963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
102311963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
102411963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_RUNNING:
102511963SAfshin.Ardakani@Sun.COM 		if (thread->sth_aw)
102611963SAfshin.Ardakani@Sun.COM 			thread->sth_aw(thread, thread->sth_aw_arg);
102711963SAfshin.Ardakani@Sun.COM 		cv_signal(&thread->sth_cv);
102811963SAfshin.Ardakani@Sun.COM 		break;
102911963SAfshin.Ardakani@Sun.COM 
103011963SAfshin.Ardakani@Sun.COM 	default:
103111963SAfshin.Ardakani@Sun.COM 		break;
103211963SAfshin.Ardakani@Sun.COM 	}
103311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
103411963SAfshin.Ardakani@Sun.COM }
103511963SAfshin.Ardakani@Sun.COM 
103611963SAfshin.Ardakani@Sun.COM boolean_t
103711963SAfshin.Ardakani@Sun.COM smb_thread_continue(smb_thread_t *thread)
103811963SAfshin.Ardakani@Sun.COM {
103911963SAfshin.Ardakani@Sun.COM 	boolean_t result;
104011963SAfshin.Ardakani@Sun.COM 
104111963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
104211963SAfshin.Ardakani@Sun.COM 
104311963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
104411963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread, 0);
104511963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
104611963SAfshin.Ardakani@Sun.COM 
104711963SAfshin.Ardakani@Sun.COM 	return (result);
104811963SAfshin.Ardakani@Sun.COM }
104911963SAfshin.Ardakani@Sun.COM 
105011963SAfshin.Ardakani@Sun.COM boolean_t
105111963SAfshin.Ardakani@Sun.COM smb_thread_continue_nowait(smb_thread_t *thread)
105211963SAfshin.Ardakani@Sun.COM {
105311963SAfshin.Ardakani@Sun.COM 	boolean_t result;
105411963SAfshin.Ardakani@Sun.COM 
105511963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
105611963SAfshin.Ardakani@Sun.COM 
105711963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
105811963SAfshin.Ardakani@Sun.COM 	/*
105911963SAfshin.Ardakani@Sun.COM 	 * Setting ticks=-1 requests a non-blocking check.  We will
106011963SAfshin.Ardakani@Sun.COM 	 * still block if the thread is in "suspend" state.
106111963SAfshin.Ardakani@Sun.COM 	 */
106211963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread, -1);
106311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
106411963SAfshin.Ardakani@Sun.COM 
106511963SAfshin.Ardakani@Sun.COM 	return (result);
106611963SAfshin.Ardakani@Sun.COM }
106711963SAfshin.Ardakani@Sun.COM 
106811963SAfshin.Ardakani@Sun.COM boolean_t
106911963SAfshin.Ardakani@Sun.COM smb_thread_continue_timedwait(smb_thread_t *thread, int seconds)
107011963SAfshin.Ardakani@Sun.COM {
107111963SAfshin.Ardakani@Sun.COM 	boolean_t result;
107211963SAfshin.Ardakani@Sun.COM 
107311963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
107411963SAfshin.Ardakani@Sun.COM 
107511963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
107611963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread,
107711963SAfshin.Ardakani@Sun.COM 	    SEC_TO_TICK(seconds));
107811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
107911963SAfshin.Ardakani@Sun.COM 
108011963SAfshin.Ardakani@Sun.COM 	return (result);
108111963SAfshin.Ardakani@Sun.COM }
108211963SAfshin.Ardakani@Sun.COM 
108311963SAfshin.Ardakani@Sun.COM /*
108411963SAfshin.Ardakani@Sun.COM  * smb_thread_continue_timedwait_locked
108511963SAfshin.Ardakani@Sun.COM  *
108611963SAfshin.Ardakani@Sun.COM  * Internal only.  Ticks==-1 means don't block, Ticks == 0 means wait
108711963SAfshin.Ardakani@Sun.COM  * indefinitely
108811963SAfshin.Ardakani@Sun.COM  */
108911963SAfshin.Ardakani@Sun.COM static boolean_t
109011963SAfshin.Ardakani@Sun.COM smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks)
109111963SAfshin.Ardakani@Sun.COM {
109211963SAfshin.Ardakani@Sun.COM 	boolean_t	result;
109311963SAfshin.Ardakani@Sun.COM 
109411963SAfshin.Ardakani@Sun.COM 	/* -1 means don't block */
109511963SAfshin.Ardakani@Sun.COM 	if (ticks != -1 && !thread->sth_kill) {
109611963SAfshin.Ardakani@Sun.COM 		if (ticks == 0) {
109711963SAfshin.Ardakani@Sun.COM 			cv_wait(&thread->sth_cv, &thread->sth_mtx);
109811963SAfshin.Ardakani@Sun.COM 		} else {
109911963SAfshin.Ardakani@Sun.COM 			(void) cv_reltimedwait(&thread->sth_cv,
110011963SAfshin.Ardakani@Sun.COM 			    &thread->sth_mtx, (clock_t)ticks, TR_CLOCK_TICK);
110111963SAfshin.Ardakani@Sun.COM 		}
110211963SAfshin.Ardakani@Sun.COM 	}
110311963SAfshin.Ardakani@Sun.COM 	result = (thread->sth_kill == 0);
110411963SAfshin.Ardakani@Sun.COM 
110511963SAfshin.Ardakani@Sun.COM 	return (result);
110611963SAfshin.Ardakani@Sun.COM }
110711963SAfshin.Ardakani@Sun.COM 
110811963SAfshin.Ardakani@Sun.COM void
110911963SAfshin.Ardakani@Sun.COM smb_thread_set_awaken(smb_thread_t *thread, smb_thread_aw_t new_aw_fn,
111011963SAfshin.Ardakani@Sun.COM     void *new_aw_arg)
111111963SAfshin.Ardakani@Sun.COM {
111211963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
111311963SAfshin.Ardakani@Sun.COM 
111411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
111511963SAfshin.Ardakani@Sun.COM 	thread->sth_aw = new_aw_fn;
111611963SAfshin.Ardakani@Sun.COM 	thread->sth_aw_arg = new_aw_arg;
111711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
111811963SAfshin.Ardakani@Sun.COM }
111911963SAfshin.Ardakani@Sun.COM 
112011963SAfshin.Ardakani@Sun.COM /*
112111963SAfshin.Ardakani@Sun.COM  * smb_rwx_init
112211963SAfshin.Ardakani@Sun.COM  */
112311963SAfshin.Ardakani@Sun.COM void
112411963SAfshin.Ardakani@Sun.COM smb_rwx_init(
112511963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
112611963SAfshin.Ardakani@Sun.COM {
112711963SAfshin.Ardakani@Sun.COM 	bzero(rwx, sizeof (smb_rwx_t));
112811963SAfshin.Ardakani@Sun.COM 	cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL);
112911963SAfshin.Ardakani@Sun.COM 	mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
113011963SAfshin.Ardakani@Sun.COM 	rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
113111963SAfshin.Ardakani@Sun.COM }
113211963SAfshin.Ardakani@Sun.COM 
113311963SAfshin.Ardakani@Sun.COM /*
113411963SAfshin.Ardakani@Sun.COM  * smb_rwx_destroy
113511963SAfshin.Ardakani@Sun.COM  */
113611963SAfshin.Ardakani@Sun.COM void
113711963SAfshin.Ardakani@Sun.COM smb_rwx_destroy(
113811963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
113911963SAfshin.Ardakani@Sun.COM {
114011963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&rwx->rwx_mutex);
114111963SAfshin.Ardakani@Sun.COM 	cv_destroy(&rwx->rwx_cv);
114211963SAfshin.Ardakani@Sun.COM 	rw_destroy(&rwx->rwx_lock);
114311963SAfshin.Ardakani@Sun.COM }
114411963SAfshin.Ardakani@Sun.COM 
114511963SAfshin.Ardakani@Sun.COM /*
114611963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwexit
114711963SAfshin.Ardakani@Sun.COM  */
114811963SAfshin.Ardakani@Sun.COM void
114911963SAfshin.Ardakani@Sun.COM smb_rwx_rwexit(
115011963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
115111963SAfshin.Ardakani@Sun.COM {
115211963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
115311963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
115411963SAfshin.Ardakani@Sun.COM 		mutex_enter(&rwx->rwx_mutex);
115511963SAfshin.Ardakani@Sun.COM 		if (rwx->rwx_waiting) {
115611963SAfshin.Ardakani@Sun.COM 			rwx->rwx_waiting = B_FALSE;
115711963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&rwx->rwx_cv);
115811963SAfshin.Ardakani@Sun.COM 		}
115911963SAfshin.Ardakani@Sun.COM 		mutex_exit(&rwx->rwx_mutex);
116011963SAfshin.Ardakani@Sun.COM 	}
116111963SAfshin.Ardakani@Sun.COM 	rw_exit(&rwx->rwx_lock);
116211963SAfshin.Ardakani@Sun.COM }
116311963SAfshin.Ardakani@Sun.COM 
116411963SAfshin.Ardakani@Sun.COM /*
116511963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwupgrade
116611963SAfshin.Ardakani@Sun.COM  */
116711963SAfshin.Ardakani@Sun.COM krw_t
116811963SAfshin.Ardakani@Sun.COM smb_rwx_rwupgrade(
116911963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
117011963SAfshin.Ardakani@Sun.COM {
117111963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
117211963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
117311963SAfshin.Ardakani@Sun.COM 		return (RW_WRITER);
117411963SAfshin.Ardakani@Sun.COM 	}
117511963SAfshin.Ardakani@Sun.COM 	if (!rw_tryupgrade(&rwx->rwx_lock)) {
117611963SAfshin.Ardakani@Sun.COM 		rw_exit(&rwx->rwx_lock);
117711963SAfshin.Ardakani@Sun.COM 		rw_enter(&rwx->rwx_lock, RW_WRITER);
117811963SAfshin.Ardakani@Sun.COM 	}
117911963SAfshin.Ardakani@Sun.COM 	return (RW_READER);
118011963SAfshin.Ardakani@Sun.COM }
118111963SAfshin.Ardakani@Sun.COM 
118211963SAfshin.Ardakani@Sun.COM /*
118311963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwrestore
118411963SAfshin.Ardakani@Sun.COM  */
118511963SAfshin.Ardakani@Sun.COM void
118611963SAfshin.Ardakani@Sun.COM smb_rwx_rwdowngrade(
118711963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx,
118811963SAfshin.Ardakani@Sun.COM     krw_t	mode)
118911963SAfshin.Ardakani@Sun.COM {
119011963SAfshin.Ardakani@Sun.COM 	ASSERT(rw_write_held(&rwx->rwx_lock));
119111963SAfshin.Ardakani@Sun.COM 	ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
119211963SAfshin.Ardakani@Sun.COM 
119311963SAfshin.Ardakani@Sun.COM 	if (mode == RW_WRITER) {
119411963SAfshin.Ardakani@Sun.COM 		return;
119511963SAfshin.Ardakani@Sun.COM 	}
119611963SAfshin.Ardakani@Sun.COM 	ASSERT(mode == RW_READER);
119711963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
119811963SAfshin.Ardakani@Sun.COM 	if (rwx->rwx_waiting) {
119911963SAfshin.Ardakani@Sun.COM 		rwx->rwx_waiting = B_FALSE;
120011963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&rwx->rwx_cv);
120111963SAfshin.Ardakani@Sun.COM 	}
120211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
120311963SAfshin.Ardakani@Sun.COM 	rw_downgrade(&rwx->rwx_lock);
120411963SAfshin.Ardakani@Sun.COM }
120511963SAfshin.Ardakani@Sun.COM 
120611963SAfshin.Ardakani@Sun.COM /*
120711963SAfshin.Ardakani@Sun.COM  * smb_rwx_wait
120811963SAfshin.Ardakani@Sun.COM  *
120911963SAfshin.Ardakani@Sun.COM  * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER
121011963SAfshin.Ardakani@Sun.COM  * mode. It will:
121111963SAfshin.Ardakani@Sun.COM  *
121211963SAfshin.Ardakani@Sun.COM  *	1) release the lock and save its current mode.
121311963SAfshin.Ardakani@Sun.COM  *	2) wait until the condition variable is signaled. This can happen for
121411963SAfshin.Ardakani@Sun.COM  *	   2 reasons: When a writer releases the lock or when the time out (if
121511963SAfshin.Ardakani@Sun.COM  *	   provided) expires.
121611963SAfshin.Ardakani@Sun.COM  *	3) re-acquire the lock in the mode saved in (1).
121711963SAfshin.Ardakani@Sun.COM  */
121811963SAfshin.Ardakani@Sun.COM int
121911963SAfshin.Ardakani@Sun.COM smb_rwx_rwwait(
122011963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx,
122111963SAfshin.Ardakani@Sun.COM     clock_t	timeout)
122211963SAfshin.Ardakani@Sun.COM {
122311963SAfshin.Ardakani@Sun.COM 	int	rc;
122411963SAfshin.Ardakani@Sun.COM 	krw_t	mode;
122511963SAfshin.Ardakani@Sun.COM 
122611963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
122711963SAfshin.Ardakani@Sun.COM 	rwx->rwx_waiting = B_TRUE;
122811963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
122911963SAfshin.Ardakani@Sun.COM 
123011963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
123111963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
123211963SAfshin.Ardakani@Sun.COM 		mode = RW_WRITER;
123311963SAfshin.Ardakani@Sun.COM 	} else {
123411963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_read_held(&rwx->rwx_lock));
123511963SAfshin.Ardakani@Sun.COM 		mode = RW_READER;
123611963SAfshin.Ardakani@Sun.COM 	}
123711963SAfshin.Ardakani@Sun.COM 	rw_exit(&rwx->rwx_lock);
123811963SAfshin.Ardakani@Sun.COM 
123911963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
124011963SAfshin.Ardakani@Sun.COM 	if (rwx->rwx_waiting) {
124111963SAfshin.Ardakani@Sun.COM 		if (timeout == -1) {
124211963SAfshin.Ardakani@Sun.COM 			rc = 1;
124311963SAfshin.Ardakani@Sun.COM 			cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
124411963SAfshin.Ardakani@Sun.COM 		} else {
124511963SAfshin.Ardakani@Sun.COM 			rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
124611963SAfshin.Ardakani@Sun.COM 			    timeout, TR_CLOCK_TICK);
124711963SAfshin.Ardakani@Sun.COM 		}
124811963SAfshin.Ardakani@Sun.COM 	}
124911963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
125011963SAfshin.Ardakani@Sun.COM 
125111963SAfshin.Ardakani@Sun.COM 	rw_enter(&rwx->rwx_lock, mode);
125211963SAfshin.Ardakani@Sun.COM 	return (rc);
125311963SAfshin.Ardakani@Sun.COM }
125411963SAfshin.Ardakani@Sun.COM 
125511963SAfshin.Ardakani@Sun.COM /*
125611963SAfshin.Ardakani@Sun.COM  * SMB ID mapping
125711963SAfshin.Ardakani@Sun.COM  *
125811963SAfshin.Ardakani@Sun.COM  * Solaris ID mapping service (aka Winchester) works with domain SIDs
125911963SAfshin.Ardakani@Sun.COM  * and RIDs where domain SIDs are in string format. CIFS service works
126011963SAfshin.Ardakani@Sun.COM  * with binary SIDs understandable by CIFS clients. A layer of SMB ID
126111963SAfshin.Ardakani@Sun.COM  * mapping functions are implemeted to hide the SID conversion details
126211963SAfshin.Ardakani@Sun.COM  * and also hide the handling of array of batch mapping requests.
126311963SAfshin.Ardakani@Sun.COM  *
126411963SAfshin.Ardakani@Sun.COM  * IMPORTANT NOTE The Winchester API requires a zone. Because CIFS server
126511963SAfshin.Ardakani@Sun.COM  * currently only runs in the global zone the global zone is specified.
126611963SAfshin.Ardakani@Sun.COM  * This needs to be fixed when the CIFS server supports zones.
126711963SAfshin.Ardakani@Sun.COM  */
126811963SAfshin.Ardakani@Sun.COM 
126911963SAfshin.Ardakani@Sun.COM static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
127011963SAfshin.Ardakani@Sun.COM 
127111963SAfshin.Ardakani@Sun.COM /*
127211963SAfshin.Ardakani@Sun.COM  * smb_idmap_getid
127311963SAfshin.Ardakani@Sun.COM  *
127411963SAfshin.Ardakani@Sun.COM  * Maps the given Windows SID to a Solaris ID using the
127511963SAfshin.Ardakani@Sun.COM  * simple mapping API.
127611963SAfshin.Ardakani@Sun.COM  */
127711963SAfshin.Ardakani@Sun.COM idmap_stat
127811963SAfshin.Ardakani@Sun.COM smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
127911963SAfshin.Ardakani@Sun.COM {
128011963SAfshin.Ardakani@Sun.COM 	smb_idmap_t sim;
128111963SAfshin.Ardakani@Sun.COM 	char sidstr[SMB_SID_STRSZ];
128211963SAfshin.Ardakani@Sun.COM 
128311963SAfshin.Ardakani@Sun.COM 	smb_sid_tostr(sid, sidstr);
128411963SAfshin.Ardakani@Sun.COM 	if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
128511963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_SID);
128611963SAfshin.Ardakani@Sun.COM 	sim.sim_domsid = sidstr;
128711963SAfshin.Ardakani@Sun.COM 	sim.sim_id = id;
128811963SAfshin.Ardakani@Sun.COM 
128911963SAfshin.Ardakani@Sun.COM 	switch (*idtype) {
129011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
129111963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid,
129211963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id);
129311963SAfshin.Ardakani@Sun.COM 		break;
129411963SAfshin.Ardakani@Sun.COM 
129511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
129611963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid,
129711963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id);
129811963SAfshin.Ardakani@Sun.COM 		break;
129911963SAfshin.Ardakani@Sun.COM 
130011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_UNKNOWN:
130111963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid,
130211963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id, &sim.sim_idtype);
130311963SAfshin.Ardakani@Sun.COM 		break;
130411963SAfshin.Ardakani@Sun.COM 
130511963SAfshin.Ardakani@Sun.COM 	default:
130611963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
130711963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
130811963SAfshin.Ardakani@Sun.COM 	}
130911963SAfshin.Ardakani@Sun.COM 
131011963SAfshin.Ardakani@Sun.COM 	*idtype = sim.sim_idtype;
131111963SAfshin.Ardakani@Sun.COM 
131211963SAfshin.Ardakani@Sun.COM 	return (sim.sim_stat);
131311963SAfshin.Ardakani@Sun.COM }
131411963SAfshin.Ardakani@Sun.COM 
131511963SAfshin.Ardakani@Sun.COM /*
131611963SAfshin.Ardakani@Sun.COM  * smb_idmap_getsid
131711963SAfshin.Ardakani@Sun.COM  *
131811963SAfshin.Ardakani@Sun.COM  * Maps the given Solaris ID to a Windows SID using the
131911963SAfshin.Ardakani@Sun.COM  * simple mapping API.
132011963SAfshin.Ardakani@Sun.COM  */
132111963SAfshin.Ardakani@Sun.COM idmap_stat
132211963SAfshin.Ardakani@Sun.COM smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid)
132311963SAfshin.Ardakani@Sun.COM {
132411963SAfshin.Ardakani@Sun.COM 	smb_idmap_t sim;
132511963SAfshin.Ardakani@Sun.COM 
132611963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
132711963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
132811963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getsidbyuid(global_zone, id,
132911963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim.sim_domsid, &sim.sim_rid);
133011963SAfshin.Ardakani@Sun.COM 		break;
133111963SAfshin.Ardakani@Sun.COM 
133211963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
133311963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getsidbygid(global_zone, id,
133411963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim.sim_domsid, &sim.sim_rid);
133511963SAfshin.Ardakani@Sun.COM 		break;
133611963SAfshin.Ardakani@Sun.COM 
133711963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_EVERYONE:
133811963SAfshin.Ardakani@Sun.COM 		/* Everyone S-1-1-0 */
133911963SAfshin.Ardakani@Sun.COM 		sim.sim_domsid = "S-1-1";
134011963SAfshin.Ardakani@Sun.COM 		sim.sim_rid = 0;
134111963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = IDMAP_SUCCESS;
134211963SAfshin.Ardakani@Sun.COM 		break;
134311963SAfshin.Ardakani@Sun.COM 
134411963SAfshin.Ardakani@Sun.COM 	default:
134511963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
134611963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
134711963SAfshin.Ardakani@Sun.COM 	}
134811963SAfshin.Ardakani@Sun.COM 
134911963SAfshin.Ardakani@Sun.COM 	if (sim.sim_stat != IDMAP_SUCCESS)
135011963SAfshin.Ardakani@Sun.COM 		return (sim.sim_stat);
135111963SAfshin.Ardakani@Sun.COM 
135211963SAfshin.Ardakani@Sun.COM 	if (sim.sim_domsid == NULL)
135311963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_NOMAPPING);
135411963SAfshin.Ardakani@Sun.COM 
135511963SAfshin.Ardakani@Sun.COM 	sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
135611963SAfshin.Ardakani@Sun.COM 	if (sim.sim_sid == NULL)
135711963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_INTERNAL);
135811963SAfshin.Ardakani@Sun.COM 
135911963SAfshin.Ardakani@Sun.COM 	*sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
136011963SAfshin.Ardakani@Sun.COM 	smb_sid_free(sim.sim_sid);
136111963SAfshin.Ardakani@Sun.COM 	if (*sid == NULL)
136211963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = IDMAP_ERR_INTERNAL;
136311963SAfshin.Ardakani@Sun.COM 
136411963SAfshin.Ardakani@Sun.COM 	return (sim.sim_stat);
136511963SAfshin.Ardakani@Sun.COM }
136611963SAfshin.Ardakani@Sun.COM 
136711963SAfshin.Ardakani@Sun.COM /*
136811963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_create
136911963SAfshin.Ardakani@Sun.COM  *
137011963SAfshin.Ardakani@Sun.COM  * Creates and initializes the context for batch ID mapping.
137111963SAfshin.Ardakani@Sun.COM  */
137211963SAfshin.Ardakani@Sun.COM idmap_stat
137311963SAfshin.Ardakani@Sun.COM smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
137411963SAfshin.Ardakani@Sun.COM {
137511963SAfshin.Ardakani@Sun.COM 	ASSERT(sib);
137611963SAfshin.Ardakani@Sun.COM 
137711963SAfshin.Ardakani@Sun.COM 	bzero(sib, sizeof (smb_idmap_batch_t));
137811963SAfshin.Ardakani@Sun.COM 
137911963SAfshin.Ardakani@Sun.COM 	sib->sib_idmaph = kidmap_get_create(global_zone);
138011963SAfshin.Ardakani@Sun.COM 
138111963SAfshin.Ardakani@Sun.COM 	sib->sib_flags = flags;
138211963SAfshin.Ardakani@Sun.COM 	sib->sib_nmap = nmap;
138311963SAfshin.Ardakani@Sun.COM 	sib->sib_size = nmap * sizeof (smb_idmap_t);
138411963SAfshin.Ardakani@Sun.COM 	sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
138511963SAfshin.Ardakani@Sun.COM 
138611963SAfshin.Ardakani@Sun.COM 	return (IDMAP_SUCCESS);
138711963SAfshin.Ardakani@Sun.COM }
138811963SAfshin.Ardakani@Sun.COM 
138911963SAfshin.Ardakani@Sun.COM /*
139011963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_destroy
139111963SAfshin.Ardakani@Sun.COM  *
139211963SAfshin.Ardakani@Sun.COM  * Frees the batch ID mapping context.
139311963SAfshin.Ardakani@Sun.COM  * If ID mapping is Solaris -> Windows it frees memories
139411963SAfshin.Ardakani@Sun.COM  * allocated for binary SIDs.
139511963SAfshin.Ardakani@Sun.COM  */
139611963SAfshin.Ardakani@Sun.COM void
139711963SAfshin.Ardakani@Sun.COM smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
139811963SAfshin.Ardakani@Sun.COM {
139911963SAfshin.Ardakani@Sun.COM 	char *domsid;
140011963SAfshin.Ardakani@Sun.COM 	int i;
140111963SAfshin.Ardakani@Sun.COM 
140211963SAfshin.Ardakani@Sun.COM 	ASSERT(sib);
140311963SAfshin.Ardakani@Sun.COM 	ASSERT(sib->sib_maps);
140411963SAfshin.Ardakani@Sun.COM 
140511963SAfshin.Ardakani@Sun.COM 	if (sib->sib_idmaph)
140611963SAfshin.Ardakani@Sun.COM 		kidmap_get_destroy(sib->sib_idmaph);
140711963SAfshin.Ardakani@Sun.COM 
140811963SAfshin.Ardakani@Sun.COM 	if (sib->sib_flags & SMB_IDMAP_ID2SID) {
140911963SAfshin.Ardakani@Sun.COM 		/*
141011963SAfshin.Ardakani@Sun.COM 		 * SIDs are allocated only when mapping
141111963SAfshin.Ardakani@Sun.COM 		 * UID/GID to SIDs
141211963SAfshin.Ardakani@Sun.COM 		 */
141311963SAfshin.Ardakani@Sun.COM 		for (i = 0; i < sib->sib_nmap; i++)
141411963SAfshin.Ardakani@Sun.COM 			smb_sid_free(sib->sib_maps[i].sim_sid);
141511963SAfshin.Ardakani@Sun.COM 	} else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
141611963SAfshin.Ardakani@Sun.COM 		/*
141711963SAfshin.Ardakani@Sun.COM 		 * SID prefixes are allocated only when mapping
141811963SAfshin.Ardakani@Sun.COM 		 * SIDs to UID/GID
141911963SAfshin.Ardakani@Sun.COM 		 */
142011963SAfshin.Ardakani@Sun.COM 		for (i = 0; i < sib->sib_nmap; i++) {
142111963SAfshin.Ardakani@Sun.COM 			domsid = sib->sib_maps[i].sim_domsid;
142211963SAfshin.Ardakani@Sun.COM 			if (domsid)
142311963SAfshin.Ardakani@Sun.COM 				smb_mem_free(domsid);
142411963SAfshin.Ardakani@Sun.COM 		}
142511963SAfshin.Ardakani@Sun.COM 	}
142611963SAfshin.Ardakani@Sun.COM 
142711963SAfshin.Ardakani@Sun.COM 	if (sib->sib_size && sib->sib_maps)
142811963SAfshin.Ardakani@Sun.COM 		kmem_free(sib->sib_maps, sib->sib_size);
142911963SAfshin.Ardakani@Sun.COM }
143011963SAfshin.Ardakani@Sun.COM 
143111963SAfshin.Ardakani@Sun.COM /*
143211963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getid
143311963SAfshin.Ardakani@Sun.COM  *
143411963SAfshin.Ardakani@Sun.COM  * Queue a request to map the given SID to a UID or GID.
143511963SAfshin.Ardakani@Sun.COM  *
143611963SAfshin.Ardakani@Sun.COM  * sim->sim_id should point to variable that's supposed to
143711963SAfshin.Ardakani@Sun.COM  * hold the returned UID/GID. This needs to be setup by caller
143811963SAfshin.Ardakani@Sun.COM  * of this function.
143911963SAfshin.Ardakani@Sun.COM  *
144011963SAfshin.Ardakani@Sun.COM  * If requested ID type is known, it's passed as 'idtype',
144111963SAfshin.Ardakani@Sun.COM  * if it's unknown it'll be returned in sim->sim_idtype.
144211963SAfshin.Ardakani@Sun.COM  */
144311963SAfshin.Ardakani@Sun.COM idmap_stat
144411963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
144511963SAfshin.Ardakani@Sun.COM     smb_sid_t *sid, int idtype)
144611963SAfshin.Ardakani@Sun.COM {
144711963SAfshin.Ardakani@Sun.COM 	char strsid[SMB_SID_STRSZ];
144811963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat;
144911963SAfshin.Ardakani@Sun.COM 
145011963SAfshin.Ardakani@Sun.COM 	ASSERT(idmaph);
145111963SAfshin.Ardakani@Sun.COM 	ASSERT(sim);
145211963SAfshin.Ardakani@Sun.COM 	ASSERT(sid);
145311963SAfshin.Ardakani@Sun.COM 
145411963SAfshin.Ardakani@Sun.COM 	smb_sid_tostr(sid, strsid);
145511963SAfshin.Ardakani@Sun.COM 	if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
145611963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_SID);
145711963SAfshin.Ardakani@Sun.COM 	sim->sim_domsid = smb_mem_strdup(strsid);
145811963SAfshin.Ardakani@Sun.COM 
145911963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
146011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
146111963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
146211963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_stat);
146311963SAfshin.Ardakani@Sun.COM 		break;
146411963SAfshin.Ardakani@Sun.COM 
146511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
146611963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
146711963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_stat);
146811963SAfshin.Ardakani@Sun.COM 		break;
146911963SAfshin.Ardakani@Sun.COM 
147011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_UNKNOWN:
147111963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
147211963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_idtype,
147311963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
147411963SAfshin.Ardakani@Sun.COM 		break;
147511963SAfshin.Ardakani@Sun.COM 
147611963SAfshin.Ardakani@Sun.COM 	default:
147711963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
147811963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
147911963SAfshin.Ardakani@Sun.COM 	}
148011963SAfshin.Ardakani@Sun.COM 
148111963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
148211963SAfshin.Ardakani@Sun.COM }
148311963SAfshin.Ardakani@Sun.COM 
148411963SAfshin.Ardakani@Sun.COM /*
148511963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getsid
148611963SAfshin.Ardakani@Sun.COM  *
148711963SAfshin.Ardakani@Sun.COM  * Queue a request to map the given UID/GID to a SID.
148811963SAfshin.Ardakani@Sun.COM  *
148911963SAfshin.Ardakani@Sun.COM  * sim->sim_domsid and sim->sim_rid will contain the mapping
149011963SAfshin.Ardakani@Sun.COM  * result upon successful process of the batched request.
149111963SAfshin.Ardakani@Sun.COM  */
149211963SAfshin.Ardakani@Sun.COM idmap_stat
149311963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
149411963SAfshin.Ardakani@Sun.COM     uid_t id, int idtype)
149511963SAfshin.Ardakani@Sun.COM {
149611963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat;
149711963SAfshin.Ardakani@Sun.COM 
149811963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
149911963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
150011963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
150111963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim->sim_domsid, &sim->sim_rid,
150211963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
150311963SAfshin.Ardakani@Sun.COM 		break;
150411963SAfshin.Ardakani@Sun.COM 
150511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
150611963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getsidbygid(idmaph, id,
150711963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim->sim_domsid, &sim->sim_rid,
150811963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
150911963SAfshin.Ardakani@Sun.COM 		break;
151011963SAfshin.Ardakani@Sun.COM 
151111963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_OWNERAT:
151211963SAfshin.Ardakani@Sun.COM 		/* Current Owner S-1-5-32-766 */
151311963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
151411963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
151511963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
151611963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
151711963SAfshin.Ardakani@Sun.COM 		break;
151811963SAfshin.Ardakani@Sun.COM 
151911963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUPAT:
152011963SAfshin.Ardakani@Sun.COM 		/* Current Group S-1-5-32-767 */
152111963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
152211963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
152311963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
152411963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
152511963SAfshin.Ardakani@Sun.COM 		break;
152611963SAfshin.Ardakani@Sun.COM 
152711963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_EVERYONE:
152811963SAfshin.Ardakani@Sun.COM 		/* Everyone S-1-1-0 */
152911963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
153011963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = 0;
153111963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
153211963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
153311963SAfshin.Ardakani@Sun.COM 		break;
153411963SAfshin.Ardakani@Sun.COM 
153511963SAfshin.Ardakani@Sun.COM 	default:
153611963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
153711963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
153811963SAfshin.Ardakani@Sun.COM 	}
153911963SAfshin.Ardakani@Sun.COM 
154011963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
154111963SAfshin.Ardakani@Sun.COM }
154211963SAfshin.Ardakani@Sun.COM 
154311963SAfshin.Ardakani@Sun.COM /*
154411963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_binsid
154511963SAfshin.Ardakani@Sun.COM  *
154611963SAfshin.Ardakani@Sun.COM  * Convert sidrids to binary sids
154711963SAfshin.Ardakani@Sun.COM  *
154811963SAfshin.Ardakani@Sun.COM  * Returns 0 if successful and non-zero upon failure.
154911963SAfshin.Ardakani@Sun.COM  */
155011963SAfshin.Ardakani@Sun.COM static int
155111963SAfshin.Ardakani@Sun.COM smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
155211963SAfshin.Ardakani@Sun.COM {
155311963SAfshin.Ardakani@Sun.COM 	smb_sid_t *sid;
155411963SAfshin.Ardakani@Sun.COM 	smb_idmap_t *sim;
155511963SAfshin.Ardakani@Sun.COM 	int i;
155611963SAfshin.Ardakani@Sun.COM 
155711963SAfshin.Ardakani@Sun.COM 	if (sib->sib_flags & SMB_IDMAP_SID2ID)
155811963SAfshin.Ardakani@Sun.COM 		/* This operation is not required */
155911963SAfshin.Ardakani@Sun.COM 		return (0);
156011963SAfshin.Ardakani@Sun.COM 
156111963SAfshin.Ardakani@Sun.COM 	sim = sib->sib_maps;
156211963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
156311963SAfshin.Ardakani@Sun.COM 		ASSERT(sim->sim_domsid);
156411963SAfshin.Ardakani@Sun.COM 		if (sim->sim_domsid == NULL)
156511963SAfshin.Ardakani@Sun.COM 			return (1);
156611963SAfshin.Ardakani@Sun.COM 
156711963SAfshin.Ardakani@Sun.COM 		if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
156811963SAfshin.Ardakani@Sun.COM 			return (1);
156911963SAfshin.Ardakani@Sun.COM 
157011963SAfshin.Ardakani@Sun.COM 		sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
157111963SAfshin.Ardakani@Sun.COM 		smb_sid_free(sid);
157211963SAfshin.Ardakani@Sun.COM 	}
157311963SAfshin.Ardakani@Sun.COM 
157411963SAfshin.Ardakani@Sun.COM 	return (0);
157511963SAfshin.Ardakani@Sun.COM }
157611963SAfshin.Ardakani@Sun.COM 
157711963SAfshin.Ardakani@Sun.COM /*
157811963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getmappings
157911963SAfshin.Ardakani@Sun.COM  *
158011963SAfshin.Ardakani@Sun.COM  * trigger ID mapping service to get the mappings for queued
158111963SAfshin.Ardakani@Sun.COM  * requests.
158211963SAfshin.Ardakani@Sun.COM  *
158311963SAfshin.Ardakani@Sun.COM  * Checks the result of all the queued requests.
158411963SAfshin.Ardakani@Sun.COM  * If this is a Solaris -> Windows mapping it generates
158511963SAfshin.Ardakani@Sun.COM  * binary SIDs from returned (domsid, rid) pairs.
158611963SAfshin.Ardakani@Sun.COM  */
158711963SAfshin.Ardakani@Sun.COM idmap_stat
158811963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
158911963SAfshin.Ardakani@Sun.COM {
159011963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat = IDMAP_SUCCESS;
159111963SAfshin.Ardakani@Sun.COM 	int i;
159211963SAfshin.Ardakani@Sun.COM 
159311963SAfshin.Ardakani@Sun.COM 	idm_stat = kidmap_get_mappings(sib->sib_idmaph);
159411963SAfshin.Ardakani@Sun.COM 	if (idm_stat != IDMAP_SUCCESS)
159511963SAfshin.Ardakani@Sun.COM 		return (idm_stat);
159611963SAfshin.Ardakani@Sun.COM 
159711963SAfshin.Ardakani@Sun.COM 	/*
159811963SAfshin.Ardakani@Sun.COM 	 * Check the status for all the queued requests
159911963SAfshin.Ardakani@Sun.COM 	 */
160011963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sib->sib_nmap; i++) {
160111963SAfshin.Ardakani@Sun.COM 		if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS)
160211963SAfshin.Ardakani@Sun.COM 			return (sib->sib_maps[i].sim_stat);
160311963SAfshin.Ardakani@Sun.COM 	}
160411963SAfshin.Ardakani@Sun.COM 
160511963SAfshin.Ardakani@Sun.COM 	if (smb_idmap_batch_binsid(sib) != 0)
160611963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_ERR_OTHER;
160711963SAfshin.Ardakani@Sun.COM 
160811963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
160911963SAfshin.Ardakani@Sun.COM }
161011963SAfshin.Ardakani@Sun.COM 
161111963SAfshin.Ardakani@Sun.COM uint64_t
161211963SAfshin.Ardakani@Sun.COM smb_time_unix_to_nt(timestruc_t *unix_time)
161311963SAfshin.Ardakani@Sun.COM {
161411963SAfshin.Ardakani@Sun.COM 	uint64_t nt_time;
161511963SAfshin.Ardakani@Sun.COM 
161611963SAfshin.Ardakani@Sun.COM 	if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
161711963SAfshin.Ardakani@Sun.COM 		return (0);
161811963SAfshin.Ardakani@Sun.COM 
161911963SAfshin.Ardakani@Sun.COM 	nt_time = unix_time->tv_sec;
162011963SAfshin.Ardakani@Sun.COM 	nt_time *= 10000000;  /* seconds to 100ns */
162111963SAfshin.Ardakani@Sun.COM 	nt_time += unix_time->tv_nsec / 100;
162211963SAfshin.Ardakani@Sun.COM 	return (nt_time + NT_TIME_BIAS);
162311963SAfshin.Ardakani@Sun.COM }
162411963SAfshin.Ardakani@Sun.COM 
162511963SAfshin.Ardakani@Sun.COM void
162611963SAfshin.Ardakani@Sun.COM smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
162711963SAfshin.Ardakani@Sun.COM {
162811963SAfshin.Ardakani@Sun.COM 	uint32_t seconds;
162911963SAfshin.Ardakani@Sun.COM 
163011963SAfshin.Ardakani@Sun.COM 	ASSERT(unix_time);
163111963SAfshin.Ardakani@Sun.COM 
163211963SAfshin.Ardakani@Sun.COM 	if ((nt_time == 0) || (nt_time == -1)) {
163311963SAfshin.Ardakani@Sun.COM 		unix_time->tv_sec = 0;
163411963SAfshin.Ardakani@Sun.COM 		unix_time->tv_nsec = 0;
163511963SAfshin.Ardakani@Sun.COM 		return;
163611963SAfshin.Ardakani@Sun.COM 	}
163711963SAfshin.Ardakani@Sun.COM 
163811963SAfshin.Ardakani@Sun.COM 	nt_time -= NT_TIME_BIAS;
163911963SAfshin.Ardakani@Sun.COM 	seconds = nt_time / 10000000;
164011963SAfshin.Ardakani@Sun.COM 	unix_time->tv_sec = seconds;
164111963SAfshin.Ardakani@Sun.COM 	unix_time->tv_nsec = (nt_time  % 10000000) * 100;
164211963SAfshin.Ardakani@Sun.COM }
164311963SAfshin.Ardakani@Sun.COM 
164411963SAfshin.Ardakani@Sun.COM /*
164511963SAfshin.Ardakani@Sun.COM  * smb_time_gmt_to_local, smb_time_local_to_gmt
164611963SAfshin.Ardakani@Sun.COM  *
164711963SAfshin.Ardakani@Sun.COM  * Apply the gmt offset to convert between local time and gmt
164811963SAfshin.Ardakani@Sun.COM  */
164911963SAfshin.Ardakani@Sun.COM int32_t
165011963SAfshin.Ardakani@Sun.COM smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt)
165111963SAfshin.Ardakani@Sun.COM {
165211963SAfshin.Ardakani@Sun.COM 	if ((gmt == 0) || (gmt == -1))
165311963SAfshin.Ardakani@Sun.COM 		return (0);
165411963SAfshin.Ardakani@Sun.COM 
165511963SAfshin.Ardakani@Sun.COM 	return (gmt - sr->sr_gmtoff);
165611963SAfshin.Ardakani@Sun.COM }
165711963SAfshin.Ardakani@Sun.COM 
165811963SAfshin.Ardakani@Sun.COM int32_t
165911963SAfshin.Ardakani@Sun.COM smb_time_local_to_gmt(smb_request_t *sr, int32_t local)
166011963SAfshin.Ardakani@Sun.COM {
166111963SAfshin.Ardakani@Sun.COM 	if ((local == 0) || (local == -1))
166211963SAfshin.Ardakani@Sun.COM 		return (0);
166311963SAfshin.Ardakani@Sun.COM 
166411963SAfshin.Ardakani@Sun.COM 	return (local + sr->sr_gmtoff);
166511963SAfshin.Ardakani@Sun.COM }
166611963SAfshin.Ardakani@Sun.COM 
166711963SAfshin.Ardakani@Sun.COM 
166811963SAfshin.Ardakani@Sun.COM /*
166911963SAfshin.Ardakani@Sun.COM  * smb_time_dos_to_unix
167011963SAfshin.Ardakani@Sun.COM  *
167111963SAfshin.Ardakani@Sun.COM  * Convert SMB_DATE & SMB_TIME values to a unix timestamp.
167211963SAfshin.Ardakani@Sun.COM  *
167311963SAfshin.Ardakani@Sun.COM  * A date/time field of 0 means that that server file system
167411963SAfshin.Ardakani@Sun.COM  * assigned value need not be changed. The behaviour when the
167511963SAfshin.Ardakani@Sun.COM  * date/time field is set to -1 is not documented but is
167611963SAfshin.Ardakani@Sun.COM  * generally treated like 0.
167711963SAfshin.Ardakani@Sun.COM  * If date or time is 0 or -1 the unix time is returned as 0
167811963SAfshin.Ardakani@Sun.COM  * so that the caller can identify and handle this special case.
167911963SAfshin.Ardakani@Sun.COM  */
168011963SAfshin.Ardakani@Sun.COM int32_t
168111963SAfshin.Ardakani@Sun.COM smb_time_dos_to_unix(int16_t date, int16_t time)
168211963SAfshin.Ardakani@Sun.COM {
168311963SAfshin.Ardakani@Sun.COM 	struct tm	atm;
168411963SAfshin.Ardakani@Sun.COM 
168511963SAfshin.Ardakani@Sun.COM 	if (((date == 0) || (time == 0)) ||
168611963SAfshin.Ardakani@Sun.COM 	    ((date == -1) || (time == -1))) {
168711963SAfshin.Ardakani@Sun.COM 		return (0);
168811963SAfshin.Ardakani@Sun.COM 	}
168911963SAfshin.Ardakani@Sun.COM 
169011963SAfshin.Ardakani@Sun.COM 	atm.tm_year = ((date >>  9) & 0x3F) + 80;
169111963SAfshin.Ardakani@Sun.COM 	atm.tm_mon  = ((date >>  5) & 0x0F) - 1;
169211963SAfshin.Ardakani@Sun.COM 	atm.tm_mday = ((date >>  0) & 0x1F);
169311963SAfshin.Ardakani@Sun.COM 	atm.tm_hour = ((time >> 11) & 0x1F);
169411963SAfshin.Ardakani@Sun.COM 	atm.tm_min  = ((time >>  5) & 0x3F);
169511963SAfshin.Ardakani@Sun.COM 	atm.tm_sec  = ((time >>  0) & 0x1F) << 1;
169611963SAfshin.Ardakani@Sun.COM 
169711963SAfshin.Ardakani@Sun.COM 	return (smb_timegm(&atm));
169811963SAfshin.Ardakani@Sun.COM }
169911963SAfshin.Ardakani@Sun.COM 
170011963SAfshin.Ardakani@Sun.COM void
170111963SAfshin.Ardakani@Sun.COM smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p)
170211963SAfshin.Ardakani@Sun.COM {
170311963SAfshin.Ardakani@Sun.COM 	struct tm	atm;
170411963SAfshin.Ardakani@Sun.COM 	int		i;
170511963SAfshin.Ardakani@Sun.COM 	time_t		tmp_time;
170611963SAfshin.Ardakani@Sun.COM 
170711963SAfshin.Ardakani@Sun.COM 	if (ux_time == 0) {
170811963SAfshin.Ardakani@Sun.COM 		*date_p = 0;
170911963SAfshin.Ardakani@Sun.COM 		*time_p = 0;
171011963SAfshin.Ardakani@Sun.COM 		return;
171111963SAfshin.Ardakani@Sun.COM 	}
171211963SAfshin.Ardakani@Sun.COM 
171311963SAfshin.Ardakani@Sun.COM 	tmp_time = (time_t)ux_time;
171411963SAfshin.Ardakani@Sun.COM 	(void) smb_gmtime_r(&tmp_time, &atm);
171511963SAfshin.Ardakani@Sun.COM 
171611963SAfshin.Ardakani@Sun.COM 	if (date_p) {
171711963SAfshin.Ardakani@Sun.COM 		i = 0;
171811963SAfshin.Ardakani@Sun.COM 		i += atm.tm_year - 80;
171911963SAfshin.Ardakani@Sun.COM 		i <<= 4;
172011963SAfshin.Ardakani@Sun.COM 		i += atm.tm_mon + 1;
172111963SAfshin.Ardakani@Sun.COM 		i <<= 5;
172211963SAfshin.Ardakani@Sun.COM 		i += atm.tm_mday;
172311963SAfshin.Ardakani@Sun.COM 
172411963SAfshin.Ardakani@Sun.COM 		*date_p = (short)i;
172511963SAfshin.Ardakani@Sun.COM 	}
172611963SAfshin.Ardakani@Sun.COM 	if (time_p) {
172711963SAfshin.Ardakani@Sun.COM 		i = 0;
172811963SAfshin.Ardakani@Sun.COM 		i += atm.tm_hour;
172911963SAfshin.Ardakani@Sun.COM 		i <<= 6;
173011963SAfshin.Ardakani@Sun.COM 		i += atm.tm_min;
173111963SAfshin.Ardakani@Sun.COM 		i <<= 5;
173211963SAfshin.Ardakani@Sun.COM 		i += atm.tm_sec >> 1;
173311963SAfshin.Ardakani@Sun.COM 
173411963SAfshin.Ardakani@Sun.COM 		*time_p = (short)i;
173511963SAfshin.Ardakani@Sun.COM 	}
173611963SAfshin.Ardakani@Sun.COM }
173711963SAfshin.Ardakani@Sun.COM 
173811963SAfshin.Ardakani@Sun.COM 
173911963SAfshin.Ardakani@Sun.COM /*
174011963SAfshin.Ardakani@Sun.COM  * smb_gmtime_r
174111963SAfshin.Ardakani@Sun.COM  *
174211963SAfshin.Ardakani@Sun.COM  * Thread-safe version of smb_gmtime. Returns a null pointer if either
174311963SAfshin.Ardakani@Sun.COM  * input parameter is a null pointer. Otherwise returns a pointer
174411963SAfshin.Ardakani@Sun.COM  * to result.
174511963SAfshin.Ardakani@Sun.COM  *
174611963SAfshin.Ardakani@Sun.COM  * Day of the week calculation: the Epoch was a thursday.
174711963SAfshin.Ardakani@Sun.COM  *
174811963SAfshin.Ardakani@Sun.COM  * There are no timezone corrections so tm_isdst and tm_gmtoff are
174911963SAfshin.Ardakani@Sun.COM  * always zero, and the zone is always WET.
175011963SAfshin.Ardakani@Sun.COM  */
175111963SAfshin.Ardakani@Sun.COM struct tm *
175211963SAfshin.Ardakani@Sun.COM smb_gmtime_r(time_t *clock, struct tm *result)
175311963SAfshin.Ardakani@Sun.COM {
175411963SAfshin.Ardakani@Sun.COM 	time_t tsec;
175511963SAfshin.Ardakani@Sun.COM 	int year;
175611963SAfshin.Ardakani@Sun.COM 	int month;
175711963SAfshin.Ardakani@Sun.COM 	int sec_per_month;
175811963SAfshin.Ardakani@Sun.COM 
175911963SAfshin.Ardakani@Sun.COM 	if (clock == 0 || result == 0)
176011963SAfshin.Ardakani@Sun.COM 		return (0);
176111963SAfshin.Ardakani@Sun.COM 
176211963SAfshin.Ardakani@Sun.COM 	bzero(result, sizeof (struct tm));
176311963SAfshin.Ardakani@Sun.COM 	tsec = *clock;
176411963SAfshin.Ardakani@Sun.COM 	tsec -= tzh_leapcnt;
176511963SAfshin.Ardakani@Sun.COM 
176611963SAfshin.Ardakani@Sun.COM 	result->tm_wday = tsec / SECSPERDAY;
176711963SAfshin.Ardakani@Sun.COM 	result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK;
176811963SAfshin.Ardakani@Sun.COM 
176911963SAfshin.Ardakani@Sun.COM 	year = EPOCH_YEAR;
177011963SAfshin.Ardakani@Sun.COM 	while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) :
177111963SAfshin.Ardakani@Sun.COM 	    (SECSPERDAY * DAYSPERNYEAR))) {
177211963SAfshin.Ardakani@Sun.COM 		if (isleap(year))
177311963SAfshin.Ardakani@Sun.COM 			tsec -= SECSPERDAY * DAYSPERLYEAR;
177411963SAfshin.Ardakani@Sun.COM 		else
177511963SAfshin.Ardakani@Sun.COM 			tsec -= SECSPERDAY * DAYSPERNYEAR;
177611963SAfshin.Ardakani@Sun.COM 
177711963SAfshin.Ardakani@Sun.COM 		++year;
177811963SAfshin.Ardakani@Sun.COM 	}
177911963SAfshin.Ardakani@Sun.COM 
178011963SAfshin.Ardakani@Sun.COM 	result->tm_year = year - TM_YEAR_BASE;
178111963SAfshin.Ardakani@Sun.COM 	result->tm_yday = tsec / SECSPERDAY;
178211963SAfshin.Ardakani@Sun.COM 
178311963SAfshin.Ardakani@Sun.COM 	for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) {
178411963SAfshin.Ardakani@Sun.COM 		sec_per_month = days_in_month[month] * SECSPERDAY;
178511963SAfshin.Ardakani@Sun.COM 
178611963SAfshin.Ardakani@Sun.COM 		if (month == TM_FEBRUARY && isleap(year))
178711963SAfshin.Ardakani@Sun.COM 			sec_per_month += SECSPERDAY;
178811963SAfshin.Ardakani@Sun.COM 
178911963SAfshin.Ardakani@Sun.COM 		if (tsec < sec_per_month)
179011963SAfshin.Ardakani@Sun.COM 			break;
179111963SAfshin.Ardakani@Sun.COM 
179211963SAfshin.Ardakani@Sun.COM 		tsec -= sec_per_month;
179311963SAfshin.Ardakani@Sun.COM 	}
179411963SAfshin.Ardakani@Sun.COM 
179511963SAfshin.Ardakani@Sun.COM 	result->tm_mon = month;
179611963SAfshin.Ardakani@Sun.COM 	result->tm_mday = (tsec / SECSPERDAY) + 1;
179711963SAfshin.Ardakani@Sun.COM 	tsec %= SECSPERDAY;
179811963SAfshin.Ardakani@Sun.COM 	result->tm_sec = tsec % 60;
179911963SAfshin.Ardakani@Sun.COM 	tsec /= 60;
180011963SAfshin.Ardakani@Sun.COM 	result->tm_min = tsec % 60;
180111963SAfshin.Ardakani@Sun.COM 	tsec /= 60;
180211963SAfshin.Ardakani@Sun.COM 	result->tm_hour = (int)tsec;
180311963SAfshin.Ardakani@Sun.COM 
180411963SAfshin.Ardakani@Sun.COM 	return (result);
180511963SAfshin.Ardakani@Sun.COM }
180611963SAfshin.Ardakani@Sun.COM 
180711963SAfshin.Ardakani@Sun.COM 
180811963SAfshin.Ardakani@Sun.COM /*
180911963SAfshin.Ardakani@Sun.COM  * smb_timegm
181011963SAfshin.Ardakani@Sun.COM  *
181111963SAfshin.Ardakani@Sun.COM  * Converts the broken-down time in tm to a time value, i.e. the number
181211963SAfshin.Ardakani@Sun.COM  * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is
181311963SAfshin.Ardakani@Sun.COM  * not a POSIX or ANSI function. Per the man page, the input values of
181411963SAfshin.Ardakani@Sun.COM  * tm_wday and tm_yday are ignored and, as the input data is assumed to
181511963SAfshin.Ardakani@Sun.COM  * represent GMT, we force tm_isdst and tm_gmtoff to 0.
181611963SAfshin.Ardakani@Sun.COM  *
181711963SAfshin.Ardakani@Sun.COM  * Before returning the clock time, we use smb_gmtime_r to set up tm_wday
181811963SAfshin.Ardakani@Sun.COM  * and tm_yday, and bring the other fields within normal range. I don't
181911963SAfshin.Ardakani@Sun.COM  * think this is really how it should be done but it's convenient for
182011963SAfshin.Ardakani@Sun.COM  * now.
182111963SAfshin.Ardakani@Sun.COM  */
182211963SAfshin.Ardakani@Sun.COM time_t
182311963SAfshin.Ardakani@Sun.COM smb_timegm(struct tm *tm)
182411963SAfshin.Ardakani@Sun.COM {
182511963SAfshin.Ardakani@Sun.COM 	time_t tsec;
182611963SAfshin.Ardakani@Sun.COM 	int dd;
182711963SAfshin.Ardakani@Sun.COM 	int mm;
182811963SAfshin.Ardakani@Sun.COM 	int yy;
182911963SAfshin.Ardakani@Sun.COM 	int year;
183011963SAfshin.Ardakani@Sun.COM 
183111963SAfshin.Ardakani@Sun.COM 	if (tm == 0)
183211963SAfshin.Ardakani@Sun.COM 		return (-1);
183311963SAfshin.Ardakani@Sun.COM 
183411963SAfshin.Ardakani@Sun.COM 	year = tm->tm_year + TM_YEAR_BASE;
183511963SAfshin.Ardakani@Sun.COM 	tsec = tzh_leapcnt;
183611963SAfshin.Ardakani@Sun.COM 
183711963SAfshin.Ardakani@Sun.COM 	for (yy = EPOCH_YEAR; yy < year; ++yy) {
183811963SAfshin.Ardakani@Sun.COM 		if (isleap(yy))
183911963SAfshin.Ardakani@Sun.COM 			tsec += SECSPERDAY * DAYSPERLYEAR;
184011963SAfshin.Ardakani@Sun.COM 		else
184111963SAfshin.Ardakani@Sun.COM 			tsec += SECSPERDAY * DAYSPERNYEAR;
184211963SAfshin.Ardakani@Sun.COM 	}
184311963SAfshin.Ardakani@Sun.COM 
184411963SAfshin.Ardakani@Sun.COM 	for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) {
184511963SAfshin.Ardakani@Sun.COM 		dd = days_in_month[mm] * SECSPERDAY;
184611963SAfshin.Ardakani@Sun.COM 
184711963SAfshin.Ardakani@Sun.COM 		if (mm == TM_FEBRUARY && isleap(year))
184811963SAfshin.Ardakani@Sun.COM 			dd += SECSPERDAY;
184911963SAfshin.Ardakani@Sun.COM 
185011963SAfshin.Ardakani@Sun.COM 		tsec += dd;
185111963SAfshin.Ardakani@Sun.COM 	}
185211963SAfshin.Ardakani@Sun.COM 
185311963SAfshin.Ardakani@Sun.COM 	tsec += (tm->tm_mday - 1) * SECSPERDAY;
185411963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_sec;
185511963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_min * SECSPERMIN;
185611963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_hour * SECSPERHOUR;
185711963SAfshin.Ardakani@Sun.COM 
185811963SAfshin.Ardakani@Sun.COM 	tm->tm_isdst = 0;
185911963SAfshin.Ardakani@Sun.COM 	(void) smb_gmtime_r(&tsec, tm);
186011963SAfshin.Ardakani@Sun.COM 	return (tsec);
186111963SAfshin.Ardakani@Sun.COM }
186211963SAfshin.Ardakani@Sun.COM 
186311963SAfshin.Ardakani@Sun.COM /*
186411963SAfshin.Ardakani@Sun.COM  * smb_pad_align
186511963SAfshin.Ardakani@Sun.COM  *
186611963SAfshin.Ardakani@Sun.COM  * Returns the number of bytes required to pad an offset to the
186711963SAfshin.Ardakani@Sun.COM  * specified alignment.
186811963SAfshin.Ardakani@Sun.COM  */
186911963SAfshin.Ardakani@Sun.COM uint32_t
187011963SAfshin.Ardakani@Sun.COM smb_pad_align(uint32_t offset, uint32_t align)
187111963SAfshin.Ardakani@Sun.COM {
187211963SAfshin.Ardakani@Sun.COM 	uint32_t pad = offset % align;
187311963SAfshin.Ardakani@Sun.COM 
187411963SAfshin.Ardakani@Sun.COM 	if (pad != 0)
187511963SAfshin.Ardakani@Sun.COM 		pad = align - pad;
187611963SAfshin.Ardakani@Sun.COM 
187711963SAfshin.Ardakani@Sun.COM 	return (pad);
187811963SAfshin.Ardakani@Sun.COM }
187911963SAfshin.Ardakani@Sun.COM 
188011963SAfshin.Ardakani@Sun.COM /*
188111963SAfshin.Ardakani@Sun.COM  * smb_panic
188211963SAfshin.Ardakani@Sun.COM  *
188311963SAfshin.Ardakani@Sun.COM  * Logs the file name, function name and line number passed in and panics the
188411963SAfshin.Ardakani@Sun.COM  * system.
188511963SAfshin.Ardakani@Sun.COM  */
188611963SAfshin.Ardakani@Sun.COM void
188711963SAfshin.Ardakani@Sun.COM smb_panic(char *file, const char *func, int line)
188811963SAfshin.Ardakani@Sun.COM {
188911963SAfshin.Ardakani@Sun.COM 	cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line);
189011963SAfshin.Ardakani@Sun.COM }
1891*12508Samw@Sun.COM 
1892*12508Samw@Sun.COM /*
1893*12508Samw@Sun.COM  * Creates an AVL tree and initializes the given smb_avl_t
1894*12508Samw@Sun.COM  * structure using the passed args
1895*12508Samw@Sun.COM  */
1896*12508Samw@Sun.COM void
1897*12508Samw@Sun.COM smb_avl_create(smb_avl_t *avl, size_t size, size_t offset, smb_avl_nops_t *ops)
1898*12508Samw@Sun.COM {
1899*12508Samw@Sun.COM 	ASSERT(avl);
1900*12508Samw@Sun.COM 	ASSERT(ops);
1901*12508Samw@Sun.COM 
1902*12508Samw@Sun.COM 	rw_init(&avl->avl_lock, NULL, RW_DEFAULT, NULL);
1903*12508Samw@Sun.COM 	mutex_init(&avl->avl_mutex, NULL, MUTEX_DEFAULT, NULL);
1904*12508Samw@Sun.COM 
1905*12508Samw@Sun.COM 	avl->avl_nops = ops;
1906*12508Samw@Sun.COM 	avl->avl_state = SMB_AVL_STATE_READY;
1907*12508Samw@Sun.COM 	avl->avl_refcnt = 0;
1908*12508Samw@Sun.COM 	(void) random_get_pseudo_bytes((uint8_t *)&avl->avl_sequence,
1909*12508Samw@Sun.COM 	    sizeof (uint32_t));
1910*12508Samw@Sun.COM 
1911*12508Samw@Sun.COM 	avl_create(&avl->avl_tree, ops->avln_cmp, size, offset);
1912*12508Samw@Sun.COM }
1913*12508Samw@Sun.COM 
1914*12508Samw@Sun.COM /*
1915*12508Samw@Sun.COM  * Destroys the specified AVL tree.
1916*12508Samw@Sun.COM  * It waits for all the in-flight operations to finish
1917*12508Samw@Sun.COM  * before destroying the AVL.
1918*12508Samw@Sun.COM  */
1919*12508Samw@Sun.COM void
1920*12508Samw@Sun.COM smb_avl_destroy(smb_avl_t *avl)
1921*12508Samw@Sun.COM {
1922*12508Samw@Sun.COM 	void *cookie = NULL;
1923*12508Samw@Sun.COM 	void *node;
1924*12508Samw@Sun.COM 
1925*12508Samw@Sun.COM 	ASSERT(avl);
1926*12508Samw@Sun.COM 
1927*12508Samw@Sun.COM 	mutex_enter(&avl->avl_mutex);
1928*12508Samw@Sun.COM 	if (avl->avl_state != SMB_AVL_STATE_READY) {
1929*12508Samw@Sun.COM 		mutex_exit(&avl->avl_mutex);
1930*12508Samw@Sun.COM 		return;
1931*12508Samw@Sun.COM 	}
1932*12508Samw@Sun.COM 
1933*12508Samw@Sun.COM 	avl->avl_state = SMB_AVL_STATE_DESTROYING;
1934*12508Samw@Sun.COM 
1935*12508Samw@Sun.COM 	while (avl->avl_refcnt > 0)
1936*12508Samw@Sun.COM 		(void) cv_wait(&avl->avl_cv, &avl->avl_mutex);
1937*12508Samw@Sun.COM 	mutex_exit(&avl->avl_mutex);
1938*12508Samw@Sun.COM 
1939*12508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_WRITER);
1940*12508Samw@Sun.COM 	while ((node = avl_destroy_nodes(&avl->avl_tree, &cookie)) != NULL)
1941*12508Samw@Sun.COM 		avl->avl_nops->avln_destroy(node);
1942*12508Samw@Sun.COM 
1943*12508Samw@Sun.COM 	avl_destroy(&avl->avl_tree);
1944*12508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
1945*12508Samw@Sun.COM 
1946*12508Samw@Sun.COM 	rw_destroy(&avl->avl_lock);
1947*12508Samw@Sun.COM 
1948*12508Samw@Sun.COM 	mutex_destroy(&avl->avl_mutex);
1949*12508Samw@Sun.COM 	bzero(avl, sizeof (smb_avl_t));
1950*12508Samw@Sun.COM }
1951*12508Samw@Sun.COM 
1952*12508Samw@Sun.COM /*
1953*12508Samw@Sun.COM  * Adds the given item to the AVL if it's
1954*12508Samw@Sun.COM  * not already there.
1955*12508Samw@Sun.COM  *
1956*12508Samw@Sun.COM  * Returns:
1957*12508Samw@Sun.COM  *
1958*12508Samw@Sun.COM  * 	ENOTACTIVE	AVL is not in READY state
1959*12508Samw@Sun.COM  * 	EEXIST		The item is already in AVL
1960*12508Samw@Sun.COM  */
1961*12508Samw@Sun.COM int
1962*12508Samw@Sun.COM smb_avl_add(smb_avl_t *avl, void *item)
1963*12508Samw@Sun.COM {
1964*12508Samw@Sun.COM 	avl_index_t where;
1965*12508Samw@Sun.COM 
1966*12508Samw@Sun.COM 	ASSERT(avl);
1967*12508Samw@Sun.COM 	ASSERT(item);
1968*12508Samw@Sun.COM 
1969*12508Samw@Sun.COM 	if (!smb_avl_hold(avl))
1970*12508Samw@Sun.COM 		return (ENOTACTIVE);
1971*12508Samw@Sun.COM 
1972*12508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_WRITER);
1973*12508Samw@Sun.COM 	if (avl_find(&avl->avl_tree, item, &where) != NULL) {
1974*12508Samw@Sun.COM 		rw_exit(&avl->avl_lock);
1975*12508Samw@Sun.COM 		smb_avl_rele(avl);
1976*12508Samw@Sun.COM 		return (EEXIST);
1977*12508Samw@Sun.COM 	}
1978*12508Samw@Sun.COM 
1979*12508Samw@Sun.COM 	avl_insert(&avl->avl_tree, item, where);
1980*12508Samw@Sun.COM 	avl->avl_sequence++;
1981*12508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
1982*12508Samw@Sun.COM 
1983*12508Samw@Sun.COM 	smb_avl_rele(avl);
1984*12508Samw@Sun.COM 	return (0);
1985*12508Samw@Sun.COM }
1986*12508Samw@Sun.COM 
1987*12508Samw@Sun.COM /*
1988*12508Samw@Sun.COM  * Removes the given item from the AVL.
1989*12508Samw@Sun.COM  * If no reference is left on the item
1990*12508Samw@Sun.COM  * it will also be destroyed by calling the
1991*12508Samw@Sun.COM  * registered destroy operation.
1992*12508Samw@Sun.COM  */
1993*12508Samw@Sun.COM void
1994*12508Samw@Sun.COM smb_avl_remove(smb_avl_t *avl, void *item)
1995*12508Samw@Sun.COM {
1996*12508Samw@Sun.COM 	avl_index_t where;
1997*12508Samw@Sun.COM 	void *rm_item;
1998*12508Samw@Sun.COM 
1999*12508Samw@Sun.COM 	ASSERT(avl);
2000*12508Samw@Sun.COM 	ASSERT(item);
2001*12508Samw@Sun.COM 
2002*12508Samw@Sun.COM 	if (!smb_avl_hold(avl))
2003*12508Samw@Sun.COM 		return;
2004*12508Samw@Sun.COM 
2005*12508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_WRITER);
2006*12508Samw@Sun.COM 	if ((rm_item = avl_find(&avl->avl_tree, item, &where)) == NULL) {
2007*12508Samw@Sun.COM 		rw_exit(&avl->avl_lock);
2008*12508Samw@Sun.COM 		smb_avl_rele(avl);
2009*12508Samw@Sun.COM 		return;
2010*12508Samw@Sun.COM 	}
2011*12508Samw@Sun.COM 
2012*12508Samw@Sun.COM 	avl_remove(&avl->avl_tree, rm_item);
2013*12508Samw@Sun.COM 	if (avl->avl_nops->avln_rele(rm_item))
2014*12508Samw@Sun.COM 		avl->avl_nops->avln_destroy(rm_item);
2015*12508Samw@Sun.COM 	avl->avl_sequence++;
2016*12508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
2017*12508Samw@Sun.COM 
2018*12508Samw@Sun.COM 	smb_avl_rele(avl);
2019*12508Samw@Sun.COM }
2020*12508Samw@Sun.COM 
2021*12508Samw@Sun.COM /*
2022*12508Samw@Sun.COM  * Looks up the AVL for the given item.
2023*12508Samw@Sun.COM  * If the item is found a hold on the object
2024*12508Samw@Sun.COM  * is taken before the pointer to it is
2025*12508Samw@Sun.COM  * returned to the caller. The caller MUST
2026*12508Samw@Sun.COM  * always call smb_avl_release() after it's done
2027*12508Samw@Sun.COM  * using the returned object to release the hold
2028*12508Samw@Sun.COM  * taken on the object.
2029*12508Samw@Sun.COM  */
2030*12508Samw@Sun.COM void *
2031*12508Samw@Sun.COM smb_avl_lookup(smb_avl_t *avl, void *item)
2032*12508Samw@Sun.COM {
2033*12508Samw@Sun.COM 	void *node = NULL;
2034*12508Samw@Sun.COM 
2035*12508Samw@Sun.COM 	ASSERT(avl);
2036*12508Samw@Sun.COM 	ASSERT(item);
2037*12508Samw@Sun.COM 
2038*12508Samw@Sun.COM 	if (!smb_avl_hold(avl))
2039*12508Samw@Sun.COM 		return (NULL);
2040*12508Samw@Sun.COM 
2041*12508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_READER);
2042*12508Samw@Sun.COM 	node = avl_find(&avl->avl_tree, item, NULL);
2043*12508Samw@Sun.COM 	if (node != NULL)
2044*12508Samw@Sun.COM 		avl->avl_nops->avln_hold(node);
2045*12508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
2046*12508Samw@Sun.COM 
2047*12508Samw@Sun.COM 	if (node == NULL)
2048*12508Samw@Sun.COM 		smb_avl_rele(avl);
2049*12508Samw@Sun.COM 
2050*12508Samw@Sun.COM 	return (node);
2051*12508Samw@Sun.COM }
2052*12508Samw@Sun.COM 
2053*12508Samw@Sun.COM /*
2054*12508Samw@Sun.COM  * The hold on the given object is released.
2055*12508Samw@Sun.COM  * This function MUST always be called after
2056*12508Samw@Sun.COM  * smb_avl_lookup() and smb_avl_iterate() for
2057*12508Samw@Sun.COM  * the returned object.
2058*12508Samw@Sun.COM  *
2059*12508Samw@Sun.COM  * If AVL is in DESTROYING state, the destroying
2060*12508Samw@Sun.COM  * thread will be notified.
2061*12508Samw@Sun.COM  */
2062*12508Samw@Sun.COM void
2063*12508Samw@Sun.COM smb_avl_release(smb_avl_t *avl, void *item)
2064*12508Samw@Sun.COM {
2065*12508Samw@Sun.COM 	ASSERT(avl);
2066*12508Samw@Sun.COM 	ASSERT(item);
2067*12508Samw@Sun.COM 
2068*12508Samw@Sun.COM 	if (avl->avl_nops->avln_rele(item))
2069*12508Samw@Sun.COM 		avl->avl_nops->avln_destroy(item);
2070*12508Samw@Sun.COM 
2071*12508Samw@Sun.COM 	smb_avl_rele(avl);
2072*12508Samw@Sun.COM }
2073*12508Samw@Sun.COM 
2074*12508Samw@Sun.COM /*
2075*12508Samw@Sun.COM  * Initializes the given cursor for the AVL.
2076*12508Samw@Sun.COM  * The cursor will be used to iterate through the AVL
2077*12508Samw@Sun.COM  */
2078*12508Samw@Sun.COM void
2079*12508Samw@Sun.COM smb_avl_iterinit(smb_avl_t *avl, smb_avl_cursor_t *cursor)
2080*12508Samw@Sun.COM {
2081*12508Samw@Sun.COM 	ASSERT(avl);
2082*12508Samw@Sun.COM 	ASSERT(cursor);
2083*12508Samw@Sun.COM 
2084*12508Samw@Sun.COM 	cursor->avlc_next = NULL;
2085*12508Samw@Sun.COM 	cursor->avlc_sequence = avl->avl_sequence;
2086*12508Samw@Sun.COM }
2087*12508Samw@Sun.COM 
2088*12508Samw@Sun.COM /*
2089*12508Samw@Sun.COM  * Iterates through the AVL using the given cursor.
2090*12508Samw@Sun.COM  * It always starts at the beginning and then returns
2091*12508Samw@Sun.COM  * a pointer to the next object on each subsequent call.
2092*12508Samw@Sun.COM  *
2093*12508Samw@Sun.COM  * If a new object is added to or removed from the AVL
2094*12508Samw@Sun.COM  * between two calls to this function, the iteration
2095*12508Samw@Sun.COM  * will terminate prematurely.
2096*12508Samw@Sun.COM  *
2097*12508Samw@Sun.COM  * The caller MUST always call smb_avl_release() after it's
2098*12508Samw@Sun.COM  * done using the returned object to release the hold taken
2099*12508Samw@Sun.COM  * on the object.
2100*12508Samw@Sun.COM  */
2101*12508Samw@Sun.COM void *
2102*12508Samw@Sun.COM smb_avl_iterate(smb_avl_t *avl, smb_avl_cursor_t *cursor)
2103*12508Samw@Sun.COM {
2104*12508Samw@Sun.COM 	void *node;
2105*12508Samw@Sun.COM 
2106*12508Samw@Sun.COM 	ASSERT(avl);
2107*12508Samw@Sun.COM 	ASSERT(cursor);
2108*12508Samw@Sun.COM 
2109*12508Samw@Sun.COM 	if (!smb_avl_hold(avl))
2110*12508Samw@Sun.COM 		return (NULL);
2111*12508Samw@Sun.COM 
2112*12508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_READER);
2113*12508Samw@Sun.COM 	if (cursor->avlc_sequence != avl->avl_sequence) {
2114*12508Samw@Sun.COM 		rw_exit(&avl->avl_lock);
2115*12508Samw@Sun.COM 		smb_avl_rele(avl);
2116*12508Samw@Sun.COM 		return (NULL);
2117*12508Samw@Sun.COM 	}
2118*12508Samw@Sun.COM 
2119*12508Samw@Sun.COM 	if (cursor->avlc_next == NULL)
2120*12508Samw@Sun.COM 		node = avl_first(&avl->avl_tree);
2121*12508Samw@Sun.COM 	else
2122*12508Samw@Sun.COM 		node = AVL_NEXT(&avl->avl_tree, cursor->avlc_next);
2123*12508Samw@Sun.COM 
2124*12508Samw@Sun.COM 	if (node != NULL)
2125*12508Samw@Sun.COM 		avl->avl_nops->avln_hold(node);
2126*12508Samw@Sun.COM 
2127*12508Samw@Sun.COM 	cursor->avlc_next = node;
2128*12508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
2129*12508Samw@Sun.COM 
2130*12508Samw@Sun.COM 	if (node == NULL)
2131*12508Samw@Sun.COM 		smb_avl_rele(avl);
2132*12508Samw@Sun.COM 
2133*12508Samw@Sun.COM 	return (node);
2134*12508Samw@Sun.COM }
2135*12508Samw@Sun.COM 
2136*12508Samw@Sun.COM /*
2137*12508Samw@Sun.COM  * Increments the AVL reference count in order to
2138*12508Samw@Sun.COM  * prevent the avl from being destroyed while it's
2139*12508Samw@Sun.COM  * being accessed.
2140*12508Samw@Sun.COM  */
2141*12508Samw@Sun.COM static boolean_t
2142*12508Samw@Sun.COM smb_avl_hold(smb_avl_t *avl)
2143*12508Samw@Sun.COM {
2144*12508Samw@Sun.COM 	mutex_enter(&avl->avl_mutex);
2145*12508Samw@Sun.COM 	if (avl->avl_state != SMB_AVL_STATE_READY) {
2146*12508Samw@Sun.COM 		mutex_exit(&avl->avl_mutex);
2147*12508Samw@Sun.COM 		return (B_FALSE);
2148*12508Samw@Sun.COM 	}
2149*12508Samw@Sun.COM 	avl->avl_refcnt++;
2150*12508Samw@Sun.COM 	mutex_exit(&avl->avl_mutex);
2151*12508Samw@Sun.COM 
2152*12508Samw@Sun.COM 	return (B_TRUE);
2153*12508Samw@Sun.COM }
2154*12508Samw@Sun.COM 
2155*12508Samw@Sun.COM /*
2156*12508Samw@Sun.COM  * Decrements the AVL reference count to release the
2157*12508Samw@Sun.COM  * hold. If another thread is trying to destroy the
2158*12508Samw@Sun.COM  * AVL and is waiting for the reference count to become
2159*12508Samw@Sun.COM  * 0, it is signaled to wake up.
2160*12508Samw@Sun.COM  */
2161*12508Samw@Sun.COM static void
2162*12508Samw@Sun.COM smb_avl_rele(smb_avl_t *avl)
2163*12508Samw@Sun.COM {
2164*12508Samw@Sun.COM 	mutex_enter(&avl->avl_mutex);
2165*12508Samw@Sun.COM 	ASSERT(avl->avl_refcnt > 0);
2166*12508Samw@Sun.COM 	avl->avl_refcnt--;
2167*12508Samw@Sun.COM 	if (avl->avl_state == SMB_AVL_STATE_DESTROYING)
2168*12508Samw@Sun.COM 		cv_broadcast(&avl->avl_cv);
2169*12508Samw@Sun.COM 	mutex_exit(&avl->avl_mutex);
2170*12508Samw@Sun.COM }
2171*12508Samw@Sun.COM 
2172*12508Samw@Sun.COM /*
2173*12508Samw@Sun.COM  * smb_latency_init
2174*12508Samw@Sun.COM  */
2175*12508Samw@Sun.COM void
2176*12508Samw@Sun.COM smb_latency_init(smb_latency_t *lat)
2177*12508Samw@Sun.COM {
2178*12508Samw@Sun.COM 	bzero(lat, sizeof (*lat));
2179*12508Samw@Sun.COM 	mutex_init(&lat->ly_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7));
2180*12508Samw@Sun.COM }
2181*12508Samw@Sun.COM 
2182*12508Samw@Sun.COM /*
2183*12508Samw@Sun.COM  * smb_latency_destroy
2184*12508Samw@Sun.COM  */
2185*12508Samw@Sun.COM void
2186*12508Samw@Sun.COM smb_latency_destroy(smb_latency_t *lat)
2187*12508Samw@Sun.COM {
2188*12508Samw@Sun.COM 	mutex_destroy(&lat->ly_mutex);
2189*12508Samw@Sun.COM }
2190*12508Samw@Sun.COM 
2191*12508Samw@Sun.COM /*
2192*12508Samw@Sun.COM  * smb_latency_add_sample
2193*12508Samw@Sun.COM  *
2194*12508Samw@Sun.COM  * Uses the new sample to calculate the new mean and standard deviation. The
2195*12508Samw@Sun.COM  * sample must be a scaled value.
2196*12508Samw@Sun.COM  */
2197*12508Samw@Sun.COM void
2198*12508Samw@Sun.COM smb_latency_add_sample(smb_latency_t *lat, hrtime_t sample)
2199*12508Samw@Sun.COM {
2200*12508Samw@Sun.COM 	hrtime_t	a_mean;
2201*12508Samw@Sun.COM 	hrtime_t	d_mean;
2202*12508Samw@Sun.COM 
2203*12508Samw@Sun.COM 	mutex_enter(&lat->ly_mutex);
2204*12508Samw@Sun.COM 	lat->ly_a_nreq++;
2205*12508Samw@Sun.COM 	lat->ly_a_sum += sample;
2206*12508Samw@Sun.COM 	if (lat->ly_a_nreq != 0) {
2207*12508Samw@Sun.COM 		a_mean = lat->ly_a_sum / lat->ly_a_nreq;
2208*12508Samw@Sun.COM 		lat->ly_a_stddev =
2209*12508Samw@Sun.COM 		    (sample - a_mean) * (sample - lat->ly_a_mean);
2210*12508Samw@Sun.COM 		lat->ly_a_mean = a_mean;
2211*12508Samw@Sun.COM 	}
2212*12508Samw@Sun.COM 	lat->ly_d_nreq++;
2213*12508Samw@Sun.COM 	lat->ly_d_sum += sample;
2214*12508Samw@Sun.COM 	if (lat->ly_d_nreq != 0) {
2215*12508Samw@Sun.COM 		d_mean = lat->ly_d_sum / lat->ly_d_nreq;
2216*12508Samw@Sun.COM 		lat->ly_d_stddev =
2217*12508Samw@Sun.COM 		    (sample - d_mean) * (sample - lat->ly_d_mean);
2218*12508Samw@Sun.COM 		lat->ly_d_mean = d_mean;
2219*12508Samw@Sun.COM 	}
2220*12508Samw@Sun.COM 	mutex_exit(&lat->ly_mutex);
2221*12508Samw@Sun.COM }
2222*12508Samw@Sun.COM 
2223*12508Samw@Sun.COM /*
2224*12508Samw@Sun.COM  * smb_srqueue_init
2225*12508Samw@Sun.COM  */
2226*12508Samw@Sun.COM void
2227*12508Samw@Sun.COM smb_srqueue_init(smb_srqueue_t *srq)
2228*12508Samw@Sun.COM {
2229*12508Samw@Sun.COM 	bzero(srq, sizeof (*srq));
2230*12508Samw@Sun.COM 	mutex_init(&srq->srq_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7));
2231*12508Samw@Sun.COM 	srq->srq_wlastupdate = srq->srq_rlastupdate = gethrtime_unscaled();
2232*12508Samw@Sun.COM }
2233*12508Samw@Sun.COM 
2234*12508Samw@Sun.COM /*
2235*12508Samw@Sun.COM  * smb_srqueue_destroy
2236*12508Samw@Sun.COM  */
2237*12508Samw@Sun.COM void
2238*12508Samw@Sun.COM smb_srqueue_destroy(smb_srqueue_t *srq)
2239*12508Samw@Sun.COM {
2240*12508Samw@Sun.COM 	mutex_destroy(&srq->srq_mutex);
2241*12508Samw@Sun.COM }
2242*12508Samw@Sun.COM 
2243*12508Samw@Sun.COM /*
2244*12508Samw@Sun.COM  * smb_srqueue_waitq_enter
2245*12508Samw@Sun.COM  */
2246*12508Samw@Sun.COM void
2247*12508Samw@Sun.COM smb_srqueue_waitq_enter(smb_srqueue_t *srq)
2248*12508Samw@Sun.COM {
2249*12508Samw@Sun.COM 	hrtime_t	new;
2250*12508Samw@Sun.COM 	hrtime_t	delta;
2251*12508Samw@Sun.COM 	uint32_t	wcnt;
2252*12508Samw@Sun.COM 
2253*12508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
2254*12508Samw@Sun.COM 	new = gethrtime_unscaled();
2255*12508Samw@Sun.COM 	delta = new - srq->srq_wlastupdate;
2256*12508Samw@Sun.COM 	srq->srq_wlastupdate = new;
2257*12508Samw@Sun.COM 	wcnt = srq->srq_wcnt++;
2258*12508Samw@Sun.COM 	if (wcnt != 0) {
2259*12508Samw@Sun.COM 		srq->srq_wlentime += delta * wcnt;
2260*12508Samw@Sun.COM 		srq->srq_wtime += delta;
2261*12508Samw@Sun.COM 	}
2262*12508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
2263*12508Samw@Sun.COM }
2264*12508Samw@Sun.COM 
2265*12508Samw@Sun.COM /*
2266*12508Samw@Sun.COM  * smb_srqueue_runq_exit
2267*12508Samw@Sun.COM  */
2268*12508Samw@Sun.COM void
2269*12508Samw@Sun.COM smb_srqueue_runq_exit(smb_srqueue_t *srq)
2270*12508Samw@Sun.COM {
2271*12508Samw@Sun.COM 	hrtime_t	new;
2272*12508Samw@Sun.COM 	hrtime_t	delta;
2273*12508Samw@Sun.COM 	uint32_t	rcnt;
2274*12508Samw@Sun.COM 
2275*12508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
2276*12508Samw@Sun.COM 	new = gethrtime_unscaled();
2277*12508Samw@Sun.COM 	delta = new - srq->srq_rlastupdate;
2278*12508Samw@Sun.COM 	srq->srq_rlastupdate = new;
2279*12508Samw@Sun.COM 	rcnt = srq->srq_rcnt--;
2280*12508Samw@Sun.COM 	ASSERT(rcnt > 0);
2281*12508Samw@Sun.COM 	srq->srq_rlentime += delta * rcnt;
2282*12508Samw@Sun.COM 	srq->srq_rtime += delta;
2283*12508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
2284*12508Samw@Sun.COM }
2285*12508Samw@Sun.COM 
2286*12508Samw@Sun.COM /*
2287*12508Samw@Sun.COM  * smb_srqueue_waitq_to_runq
2288*12508Samw@Sun.COM  */
2289*12508Samw@Sun.COM void
2290*12508Samw@Sun.COM smb_srqueue_waitq_to_runq(smb_srqueue_t *srq)
2291*12508Samw@Sun.COM {
2292*12508Samw@Sun.COM 	hrtime_t	new;
2293*12508Samw@Sun.COM 	hrtime_t	delta;
2294*12508Samw@Sun.COM 	uint32_t	wcnt;
2295*12508Samw@Sun.COM 	uint32_t	rcnt;
2296*12508Samw@Sun.COM 
2297*12508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
2298*12508Samw@Sun.COM 	new = gethrtime_unscaled();
2299*12508Samw@Sun.COM 	delta = new - srq->srq_wlastupdate;
2300*12508Samw@Sun.COM 	srq->srq_wlastupdate = new;
2301*12508Samw@Sun.COM 	wcnt = srq->srq_wcnt--;
2302*12508Samw@Sun.COM 	ASSERT(wcnt > 0);
2303*12508Samw@Sun.COM 	srq->srq_wlentime += delta * wcnt;
2304*12508Samw@Sun.COM 	srq->srq_wtime += delta;
2305*12508Samw@Sun.COM 	delta = new - srq->srq_rlastupdate;
2306*12508Samw@Sun.COM 	srq->srq_rlastupdate = new;
2307*12508Samw@Sun.COM 	rcnt = srq->srq_rcnt++;
2308*12508Samw@Sun.COM 	if (rcnt != 0) {
2309*12508Samw@Sun.COM 		srq->srq_rlentime += delta * rcnt;
2310*12508Samw@Sun.COM 		srq->srq_rtime += delta;
2311*12508Samw@Sun.COM 	}
2312*12508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
2313*12508Samw@Sun.COM }
2314*12508Samw@Sun.COM 
2315*12508Samw@Sun.COM /*
2316*12508Samw@Sun.COM  * smb_srqueue_update
2317*12508Samw@Sun.COM  *
2318*12508Samw@Sun.COM  * Takes a snapshot of the smb_sr_stat_t structure passed in.
2319*12508Samw@Sun.COM  */
2320*12508Samw@Sun.COM void
2321*12508Samw@Sun.COM smb_srqueue_update(smb_srqueue_t *srq, smb_kstat_utilization_t *kd)
2322*12508Samw@Sun.COM {
2323*12508Samw@Sun.COM 	hrtime_t	delta;
2324*12508Samw@Sun.COM 	hrtime_t	snaptime;
2325*12508Samw@Sun.COM 
2326*12508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
2327*12508Samw@Sun.COM 	snaptime = gethrtime_unscaled();
2328*12508Samw@Sun.COM 	delta = snaptime - srq->srq_wlastupdate;
2329*12508Samw@Sun.COM 	srq->srq_wlastupdate = snaptime;
2330*12508Samw@Sun.COM 	if (srq->srq_wcnt != 0) {
2331*12508Samw@Sun.COM 		srq->srq_wlentime += delta * srq->srq_wcnt;
2332*12508Samw@Sun.COM 		srq->srq_wtime += delta;
2333*12508Samw@Sun.COM 	}
2334*12508Samw@Sun.COM 	delta = snaptime - srq->srq_rlastupdate;
2335*12508Samw@Sun.COM 	srq->srq_rlastupdate = snaptime;
2336*12508Samw@Sun.COM 	if (srq->srq_rcnt != 0) {
2337*12508Samw@Sun.COM 		srq->srq_rlentime += delta * srq->srq_rcnt;
2338*12508Samw@Sun.COM 		srq->srq_rtime += delta;
2339*12508Samw@Sun.COM 	}
2340*12508Samw@Sun.COM 	kd->ku_rlentime = srq->srq_rlentime;
2341*12508Samw@Sun.COM 	kd->ku_rtime = srq->srq_rtime;
2342*12508Samw@Sun.COM 	kd->ku_wlentime = srq->srq_wlentime;
2343*12508Samw@Sun.COM 	kd->ku_wtime = srq->srq_wtime;
2344*12508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
2345*12508Samw@Sun.COM 	scalehrtime(&kd->ku_rlentime);
2346*12508Samw@Sun.COM 	scalehrtime(&kd->ku_rtime);
2347*12508Samw@Sun.COM 	scalehrtime(&kd->ku_wlentime);
2348*12508Samw@Sun.COM 	scalehrtime(&kd->ku_wtime);
2349*12508Samw@Sun.COM }
2350