xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kutil.c (revision 13138:89c014c50a5f)
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>
3112508Samw@Sun.COM #include <sys/spl.h>
3211963SAfshin.Ardakani@Sun.COM #include <sys/cpuvar.h>
3312508Samw@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 
4912508Samw@Sun.COM static boolean_t smb_avl_hold(smb_avl_t *);
5012508Samw@Sun.COM static void smb_avl_rele(smb_avl_t *);
5112508Samw@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
smb_ascii_or_unicode_strlen(struct smb_request * sr,char * str)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
smb_ascii_or_unicode_strlen_null(struct smb_request * sr,char * str)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
smb_ascii_or_unicode_null_len(struct smb_request * sr)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
smb_contains_wildcards(const char * pattern)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
smb_convert_wildcards(char * pattern)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
smb_sattr_check(uint16_t dosattr,uint16_t sattr)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
microtime(timestruc_t * tvp)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
clock_get_milli_uptime()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*/
smb_noop(void * p,size_t size,int foo)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
smb_idpool_increment(smb_idpool_t * pool)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
smb_idpool_constructor(smb_idpool_t * pool)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
smb_idpool_destructor(smb_idpool_t * pool)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
smb_idpool_alloc(smb_idpool_t * pool,uint16_t * id)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
smb_idpool_free(smb_idpool_t * pool,uint16_t id)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
smb_llist_init(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
smb_llist_fini(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
smb_llist_constructor(smb_llist_t * ll,size_t size,size_t offset)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;
50412890SJoyce.McIntosh@Sun.COM 	ll->ll_flushing = B_FALSE;
50511963SAfshin.Ardakani@Sun.COM }
50611963SAfshin.Ardakani@Sun.COM 
50711963SAfshin.Ardakani@Sun.COM /*
50811963SAfshin.Ardakani@Sun.COM  * Flush the delete queue and destroy a locked list.
50911963SAfshin.Ardakani@Sun.COM  */
51011963SAfshin.Ardakani@Sun.COM void
smb_llist_destructor(smb_llist_t * ll)51111963SAfshin.Ardakani@Sun.COM smb_llist_destructor(
51211963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll)
51311963SAfshin.Ardakani@Sun.COM {
51411963SAfshin.Ardakani@Sun.COM 	smb_llist_flush(ll);
51511963SAfshin.Ardakani@Sun.COM 
51611963SAfshin.Ardakani@Sun.COM 	ASSERT(ll->ll_count == 0);
51711963SAfshin.Ardakani@Sun.COM 	ASSERT(ll->ll_deleteq_count == 0);
51811963SAfshin.Ardakani@Sun.COM 
51911963SAfshin.Ardakani@Sun.COM 	rw_destroy(&ll->ll_lock);
52011963SAfshin.Ardakani@Sun.COM 	list_destroy(&ll->ll_list);
52111963SAfshin.Ardakani@Sun.COM 	list_destroy(&ll->ll_deleteq);
52211963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&ll->ll_mutex);
52311963SAfshin.Ardakani@Sun.COM }
52411963SAfshin.Ardakani@Sun.COM 
52511963SAfshin.Ardakani@Sun.COM /*
52611963SAfshin.Ardakani@Sun.COM  * Post an object to the delete queue.  The delete queue will be processed
52711963SAfshin.Ardakani@Sun.COM  * during list exit or list destruction.  Objects are often posted for
52811963SAfshin.Ardakani@Sun.COM  * deletion during list iteration (while the list is locked) but that is
52911963SAfshin.Ardakani@Sun.COM  * not required, and an object can be posted at any time.
53011963SAfshin.Ardakani@Sun.COM  */
53111963SAfshin.Ardakani@Sun.COM void
smb_llist_post(smb_llist_t * ll,void * object,smb_dtorproc_t dtorproc)53211963SAfshin.Ardakani@Sun.COM smb_llist_post(smb_llist_t *ll, void *object, smb_dtorproc_t dtorproc)
53311963SAfshin.Ardakani@Sun.COM {
53411963SAfshin.Ardakani@Sun.COM 	smb_dtor_t	*dtor;
53511963SAfshin.Ardakani@Sun.COM 
53611963SAfshin.Ardakani@Sun.COM 	ASSERT((object != NULL) && (dtorproc != NULL));
53711963SAfshin.Ardakani@Sun.COM 
53811963SAfshin.Ardakani@Sun.COM 	dtor = kmem_cache_alloc(smb_dtor_cache, KM_SLEEP);
53911963SAfshin.Ardakani@Sun.COM 	bzero(dtor, sizeof (smb_dtor_t));
54011963SAfshin.Ardakani@Sun.COM 	dtor->dt_magic = SMB_DTOR_MAGIC;
54111963SAfshin.Ardakani@Sun.COM 	dtor->dt_object = object;
54211963SAfshin.Ardakani@Sun.COM 	dtor->dt_proc = dtorproc;
54311963SAfshin.Ardakani@Sun.COM 
54411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&ll->ll_mutex);
54511963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&ll->ll_deleteq, dtor);
54611963SAfshin.Ardakani@Sun.COM 	++ll->ll_deleteq_count;
54711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&ll->ll_mutex);
54811963SAfshin.Ardakani@Sun.COM }
54911963SAfshin.Ardakani@Sun.COM 
55011963SAfshin.Ardakani@Sun.COM /*
55111963SAfshin.Ardakani@Sun.COM  * Exit the list lock and process the delete queue.
55211963SAfshin.Ardakani@Sun.COM  */
55311963SAfshin.Ardakani@Sun.COM void
smb_llist_exit(smb_llist_t * ll)55411963SAfshin.Ardakani@Sun.COM smb_llist_exit(smb_llist_t *ll)
55511963SAfshin.Ardakani@Sun.COM {
55611963SAfshin.Ardakani@Sun.COM 	rw_exit(&ll->ll_lock);
55711963SAfshin.Ardakani@Sun.COM 	smb_llist_flush(ll);
55811963SAfshin.Ardakani@Sun.COM }
55911963SAfshin.Ardakani@Sun.COM 
56011963SAfshin.Ardakani@Sun.COM /*
56111963SAfshin.Ardakani@Sun.COM  * Flush the list delete queue.  The mutex is dropped across the destructor
56211963SAfshin.Ardakani@Sun.COM  * call in case this leads to additional objects being posted to the delete
56311963SAfshin.Ardakani@Sun.COM  * queue.
56411963SAfshin.Ardakani@Sun.COM  */
56512065SKeyur.Desai@Sun.COM void
smb_llist_flush(smb_llist_t * ll)56611963SAfshin.Ardakani@Sun.COM smb_llist_flush(smb_llist_t *ll)
56711963SAfshin.Ardakani@Sun.COM {
56811963SAfshin.Ardakani@Sun.COM 	smb_dtor_t    *dtor;
56911963SAfshin.Ardakani@Sun.COM 
57011963SAfshin.Ardakani@Sun.COM 	mutex_enter(&ll->ll_mutex);
57112890SJoyce.McIntosh@Sun.COM 	if (ll->ll_flushing) {
57212890SJoyce.McIntosh@Sun.COM 		mutex_exit(&ll->ll_mutex);
57312890SJoyce.McIntosh@Sun.COM 		return;
57412890SJoyce.McIntosh@Sun.COM 	}
57512890SJoyce.McIntosh@Sun.COM 	ll->ll_flushing = B_TRUE;
57611963SAfshin.Ardakani@Sun.COM 
57711963SAfshin.Ardakani@Sun.COM 	dtor = list_head(&ll->ll_deleteq);
57811963SAfshin.Ardakani@Sun.COM 	while (dtor != NULL) {
57911963SAfshin.Ardakani@Sun.COM 		SMB_DTOR_VALID(dtor);
58011963SAfshin.Ardakani@Sun.COM 		ASSERT((dtor->dt_object != NULL) && (dtor->dt_proc != NULL));
58111963SAfshin.Ardakani@Sun.COM 		list_remove(&ll->ll_deleteq, dtor);
58211963SAfshin.Ardakani@Sun.COM 		--ll->ll_deleteq_count;
58311963SAfshin.Ardakani@Sun.COM 		mutex_exit(&ll->ll_mutex);
58411963SAfshin.Ardakani@Sun.COM 
58511963SAfshin.Ardakani@Sun.COM 		dtor->dt_proc(dtor->dt_object);
58611963SAfshin.Ardakani@Sun.COM 
58711963SAfshin.Ardakani@Sun.COM 		dtor->dt_magic = (uint32_t)~SMB_DTOR_MAGIC;
58811963SAfshin.Ardakani@Sun.COM 		kmem_cache_free(smb_dtor_cache, dtor);
58911963SAfshin.Ardakani@Sun.COM 		mutex_enter(&ll->ll_mutex);
59011963SAfshin.Ardakani@Sun.COM 		dtor = list_head(&ll->ll_deleteq);
59111963SAfshin.Ardakani@Sun.COM 	}
59212890SJoyce.McIntosh@Sun.COM 	ll->ll_flushing = B_FALSE;
59311963SAfshin.Ardakani@Sun.COM 
59411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&ll->ll_mutex);
59511963SAfshin.Ardakani@Sun.COM }
59611963SAfshin.Ardakani@Sun.COM 
59711963SAfshin.Ardakani@Sun.COM /*
59811963SAfshin.Ardakani@Sun.COM  * smb_llist_upgrade
59911963SAfshin.Ardakani@Sun.COM  *
60011963SAfshin.Ardakani@Sun.COM  * This function tries to upgrade the lock of the locked list. It assumes the
60111963SAfshin.Ardakani@Sun.COM  * locked has already been entered in RW_READER mode. It first tries using the
60211963SAfshin.Ardakani@Sun.COM  * Solaris function rw_tryupgrade(). If that call fails the lock is released
60311963SAfshin.Ardakani@Sun.COM  * and reentered in RW_WRITER mode. In that last case a window is opened during
60411963SAfshin.Ardakani@Sun.COM  * which the contents of the list may have changed. The return code indicates
60511963SAfshin.Ardakani@Sun.COM  * whether or not the list was modified when the lock was exited.
60611963SAfshin.Ardakani@Sun.COM  */
smb_llist_upgrade(smb_llist_t * ll)60711963SAfshin.Ardakani@Sun.COM int smb_llist_upgrade(
60811963SAfshin.Ardakani@Sun.COM     smb_llist_t *ll)
60911963SAfshin.Ardakani@Sun.COM {
61011963SAfshin.Ardakani@Sun.COM 	uint64_t	wrop;
61111963SAfshin.Ardakani@Sun.COM 
61211963SAfshin.Ardakani@Sun.COM 	if (rw_tryupgrade(&ll->ll_lock) != 0) {
61311963SAfshin.Ardakani@Sun.COM 		return (0);
61411963SAfshin.Ardakani@Sun.COM 	}
61511963SAfshin.Ardakani@Sun.COM 	wrop = ll->ll_wrop;
61611963SAfshin.Ardakani@Sun.COM 	rw_exit(&ll->ll_lock);
61711963SAfshin.Ardakani@Sun.COM 	rw_enter(&ll->ll_lock, RW_WRITER);
61811963SAfshin.Ardakani@Sun.COM 	return (wrop != ll->ll_wrop);
61911963SAfshin.Ardakani@Sun.COM }
62011963SAfshin.Ardakani@Sun.COM 
62111963SAfshin.Ardakani@Sun.COM /*
62211963SAfshin.Ardakani@Sun.COM  * smb_llist_insert_head
62311963SAfshin.Ardakani@Sun.COM  *
62411963SAfshin.Ardakani@Sun.COM  * This function inserts the object passed a the beginning of the list. This
62511963SAfshin.Ardakani@Sun.COM  * function assumes the lock of the list has already been entered.
62611963SAfshin.Ardakani@Sun.COM  */
62711963SAfshin.Ardakani@Sun.COM void
smb_llist_insert_head(smb_llist_t * ll,void * obj)62811963SAfshin.Ardakani@Sun.COM smb_llist_insert_head(
62911963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
63011963SAfshin.Ardakani@Sun.COM     void	*obj)
63111963SAfshin.Ardakani@Sun.COM {
63211963SAfshin.Ardakani@Sun.COM 	list_insert_head(&ll->ll_list, obj);
63311963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
63411963SAfshin.Ardakani@Sun.COM 	++ll->ll_count;
63511963SAfshin.Ardakani@Sun.COM }
63611963SAfshin.Ardakani@Sun.COM 
63711963SAfshin.Ardakani@Sun.COM /*
63811963SAfshin.Ardakani@Sun.COM  * smb_llist_insert_tail
63911963SAfshin.Ardakani@Sun.COM  *
64011963SAfshin.Ardakani@Sun.COM  * This function appends to the object passed to the list. This function assumes
64111963SAfshin.Ardakani@Sun.COM  * the lock of the list has already been entered.
64211963SAfshin.Ardakani@Sun.COM  *
64311963SAfshin.Ardakani@Sun.COM  */
64411963SAfshin.Ardakani@Sun.COM void
smb_llist_insert_tail(smb_llist_t * ll,void * obj)64511963SAfshin.Ardakani@Sun.COM smb_llist_insert_tail(
64611963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
64711963SAfshin.Ardakani@Sun.COM     void	*obj)
64811963SAfshin.Ardakani@Sun.COM {
64911963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&ll->ll_list, obj);
65011963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
65111963SAfshin.Ardakani@Sun.COM 	++ll->ll_count;
65211963SAfshin.Ardakani@Sun.COM }
65311963SAfshin.Ardakani@Sun.COM 
65411963SAfshin.Ardakani@Sun.COM /*
65511963SAfshin.Ardakani@Sun.COM  * smb_llist_remove
65611963SAfshin.Ardakani@Sun.COM  *
65711963SAfshin.Ardakani@Sun.COM  * This function removes the object passed from the list. This function assumes
65811963SAfshin.Ardakani@Sun.COM  * the lock of the list has already been entered.
65911963SAfshin.Ardakani@Sun.COM  */
66011963SAfshin.Ardakani@Sun.COM void
smb_llist_remove(smb_llist_t * ll,void * obj)66111963SAfshin.Ardakani@Sun.COM smb_llist_remove(
66211963SAfshin.Ardakani@Sun.COM     smb_llist_t	*ll,
66311963SAfshin.Ardakani@Sun.COM     void	*obj)
66411963SAfshin.Ardakani@Sun.COM {
66511963SAfshin.Ardakani@Sun.COM 	list_remove(&ll->ll_list, obj);
66611963SAfshin.Ardakani@Sun.COM 	++ll->ll_wrop;
66711963SAfshin.Ardakani@Sun.COM 	--ll->ll_count;
66811963SAfshin.Ardakani@Sun.COM }
66911963SAfshin.Ardakani@Sun.COM 
67011963SAfshin.Ardakani@Sun.COM /*
67111963SAfshin.Ardakani@Sun.COM  * smb_llist_get_count
67211963SAfshin.Ardakani@Sun.COM  *
67311963SAfshin.Ardakani@Sun.COM  * This function returns the number of elements in the specified list.
67411963SAfshin.Ardakani@Sun.COM  */
67511963SAfshin.Ardakani@Sun.COM uint32_t
smb_llist_get_count(smb_llist_t * ll)67611963SAfshin.Ardakani@Sun.COM smb_llist_get_count(
67711963SAfshin.Ardakani@Sun.COM     smb_llist_t *ll)
67811963SAfshin.Ardakani@Sun.COM {
67911963SAfshin.Ardakani@Sun.COM 	return (ll->ll_count);
68011963SAfshin.Ardakani@Sun.COM }
68111963SAfshin.Ardakani@Sun.COM 
68211963SAfshin.Ardakani@Sun.COM /*
68311963SAfshin.Ardakani@Sun.COM  * smb_slist_constructor
68411963SAfshin.Ardakani@Sun.COM  *
68511963SAfshin.Ardakani@Sun.COM  * Synchronized list constructor.
68611963SAfshin.Ardakani@Sun.COM  */
68711963SAfshin.Ardakani@Sun.COM void
smb_slist_constructor(smb_slist_t * sl,size_t size,size_t offset)68811963SAfshin.Ardakani@Sun.COM smb_slist_constructor(
68911963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
69011963SAfshin.Ardakani@Sun.COM     size_t	size,
69111963SAfshin.Ardakani@Sun.COM     size_t	offset)
69211963SAfshin.Ardakani@Sun.COM {
69311963SAfshin.Ardakani@Sun.COM 	mutex_init(&sl->sl_mutex, NULL, MUTEX_DEFAULT, NULL);
69411963SAfshin.Ardakani@Sun.COM 	cv_init(&sl->sl_cv, NULL, CV_DEFAULT, NULL);
69511963SAfshin.Ardakani@Sun.COM 	list_create(&sl->sl_list, size, offset);
69611963SAfshin.Ardakani@Sun.COM 	sl->sl_count = 0;
69711963SAfshin.Ardakani@Sun.COM 	sl->sl_waiting = B_FALSE;
69811963SAfshin.Ardakani@Sun.COM }
69911963SAfshin.Ardakani@Sun.COM 
70011963SAfshin.Ardakani@Sun.COM /*
70111963SAfshin.Ardakani@Sun.COM  * smb_slist_destructor
70211963SAfshin.Ardakani@Sun.COM  *
70311963SAfshin.Ardakani@Sun.COM  * Synchronized list destructor.
70411963SAfshin.Ardakani@Sun.COM  */
70511963SAfshin.Ardakani@Sun.COM void
smb_slist_destructor(smb_slist_t * sl)70611963SAfshin.Ardakani@Sun.COM smb_slist_destructor(
70711963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
70811963SAfshin.Ardakani@Sun.COM {
70912508Samw@Sun.COM 	VERIFY(sl->sl_count == 0);
71011963SAfshin.Ardakani@Sun.COM 
71111963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&sl->sl_mutex);
71211963SAfshin.Ardakani@Sun.COM 	cv_destroy(&sl->sl_cv);
71311963SAfshin.Ardakani@Sun.COM 	list_destroy(&sl->sl_list);
71411963SAfshin.Ardakani@Sun.COM }
71511963SAfshin.Ardakani@Sun.COM 
71611963SAfshin.Ardakani@Sun.COM /*
71711963SAfshin.Ardakani@Sun.COM  * smb_slist_insert_head
71811963SAfshin.Ardakani@Sun.COM  *
71911963SAfshin.Ardakani@Sun.COM  * This function inserts the object passed a the beginning of the list.
72011963SAfshin.Ardakani@Sun.COM  */
72111963SAfshin.Ardakani@Sun.COM void
smb_slist_insert_head(smb_slist_t * sl,void * obj)72211963SAfshin.Ardakani@Sun.COM smb_slist_insert_head(
72311963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
72411963SAfshin.Ardakani@Sun.COM     void	*obj)
72511963SAfshin.Ardakani@Sun.COM {
72611963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
72711963SAfshin.Ardakani@Sun.COM 	list_insert_head(&sl->sl_list, obj);
72811963SAfshin.Ardakani@Sun.COM 	++sl->sl_count;
72911963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
73011963SAfshin.Ardakani@Sun.COM }
73111963SAfshin.Ardakani@Sun.COM 
73211963SAfshin.Ardakani@Sun.COM /*
73311963SAfshin.Ardakani@Sun.COM  * smb_slist_insert_tail
73411963SAfshin.Ardakani@Sun.COM  *
73511963SAfshin.Ardakani@Sun.COM  * This function appends the object passed to the list.
73611963SAfshin.Ardakani@Sun.COM  */
73711963SAfshin.Ardakani@Sun.COM void
smb_slist_insert_tail(smb_slist_t * sl,void * obj)73811963SAfshin.Ardakani@Sun.COM smb_slist_insert_tail(
73911963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
74011963SAfshin.Ardakani@Sun.COM     void	*obj)
74111963SAfshin.Ardakani@Sun.COM {
74211963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
74311963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&sl->sl_list, obj);
74411963SAfshin.Ardakani@Sun.COM 	++sl->sl_count;
74511963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
74611963SAfshin.Ardakani@Sun.COM }
74711963SAfshin.Ardakani@Sun.COM 
74811963SAfshin.Ardakani@Sun.COM /*
74911963SAfshin.Ardakani@Sun.COM  * smb_llist_remove
75011963SAfshin.Ardakani@Sun.COM  *
75111963SAfshin.Ardakani@Sun.COM  * This function removes the object passed by the caller from the list.
75211963SAfshin.Ardakani@Sun.COM  */
75311963SAfshin.Ardakani@Sun.COM void
smb_slist_remove(smb_slist_t * sl,void * obj)75411963SAfshin.Ardakani@Sun.COM smb_slist_remove(
75511963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl,
75611963SAfshin.Ardakani@Sun.COM     void	*obj)
75711963SAfshin.Ardakani@Sun.COM {
75811963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
75911963SAfshin.Ardakani@Sun.COM 	list_remove(&sl->sl_list, obj);
76011963SAfshin.Ardakani@Sun.COM 	if ((--sl->sl_count == 0) && (sl->sl_waiting)) {
76111963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_FALSE;
76211963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&sl->sl_cv);
76311963SAfshin.Ardakani@Sun.COM 	}
76411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
76511963SAfshin.Ardakani@Sun.COM }
76611963SAfshin.Ardakani@Sun.COM 
76711963SAfshin.Ardakani@Sun.COM /*
76811963SAfshin.Ardakani@Sun.COM  * smb_slist_move_tail
76911963SAfshin.Ardakani@Sun.COM  *
77011963SAfshin.Ardakani@Sun.COM  * This function transfers all the contents of the synchronized list to the
77111963SAfshin.Ardakani@Sun.COM  * list_t provided. It returns the number of objects transferred.
77211963SAfshin.Ardakani@Sun.COM  */
77311963SAfshin.Ardakani@Sun.COM uint32_t
smb_slist_move_tail(list_t * lst,smb_slist_t * sl)77411963SAfshin.Ardakani@Sun.COM smb_slist_move_tail(
77511963SAfshin.Ardakani@Sun.COM     list_t	*lst,
77611963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
77711963SAfshin.Ardakani@Sun.COM {
77811963SAfshin.Ardakani@Sun.COM 	uint32_t	rv;
77911963SAfshin.Ardakani@Sun.COM 
78011963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
78111963SAfshin.Ardakani@Sun.COM 	rv = sl->sl_count;
78211963SAfshin.Ardakani@Sun.COM 	if (sl->sl_count) {
78311963SAfshin.Ardakani@Sun.COM 		list_move_tail(lst, &sl->sl_list);
78411963SAfshin.Ardakani@Sun.COM 		sl->sl_count = 0;
78511963SAfshin.Ardakani@Sun.COM 		if (sl->sl_waiting) {
78611963SAfshin.Ardakani@Sun.COM 			sl->sl_waiting = B_FALSE;
78711963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&sl->sl_cv);
78811963SAfshin.Ardakani@Sun.COM 		}
78911963SAfshin.Ardakani@Sun.COM 	}
79011963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
79111963SAfshin.Ardakani@Sun.COM 	return (rv);
79211963SAfshin.Ardakani@Sun.COM }
79311963SAfshin.Ardakani@Sun.COM 
79411963SAfshin.Ardakani@Sun.COM /*
79511963SAfshin.Ardakani@Sun.COM  * smb_slist_obj_move
79611963SAfshin.Ardakani@Sun.COM  *
79711963SAfshin.Ardakani@Sun.COM  * This function moves an object from one list to the end of the other list. It
79811963SAfshin.Ardakani@Sun.COM  * assumes the mutex of each list has been entered.
79911963SAfshin.Ardakani@Sun.COM  */
80011963SAfshin.Ardakani@Sun.COM void
smb_slist_obj_move(smb_slist_t * dst,smb_slist_t * src,void * obj)80111963SAfshin.Ardakani@Sun.COM smb_slist_obj_move(
80211963SAfshin.Ardakani@Sun.COM     smb_slist_t	*dst,
80311963SAfshin.Ardakani@Sun.COM     smb_slist_t	*src,
80411963SAfshin.Ardakani@Sun.COM     void	*obj)
80511963SAfshin.Ardakani@Sun.COM {
80611963SAfshin.Ardakani@Sun.COM 	ASSERT(dst->sl_list.list_offset == src->sl_list.list_offset);
80711963SAfshin.Ardakani@Sun.COM 	ASSERT(dst->sl_list.list_size == src->sl_list.list_size);
80811963SAfshin.Ardakani@Sun.COM 
80911963SAfshin.Ardakani@Sun.COM 	list_remove(&src->sl_list, obj);
81011963SAfshin.Ardakani@Sun.COM 	list_insert_tail(&dst->sl_list, obj);
81111963SAfshin.Ardakani@Sun.COM 	dst->sl_count++;
81211963SAfshin.Ardakani@Sun.COM 	src->sl_count--;
81311963SAfshin.Ardakani@Sun.COM 	if ((src->sl_count == 0) && (src->sl_waiting)) {
81411963SAfshin.Ardakani@Sun.COM 		src->sl_waiting = B_FALSE;
81511963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&src->sl_cv);
81611963SAfshin.Ardakani@Sun.COM 	}
81711963SAfshin.Ardakani@Sun.COM }
81811963SAfshin.Ardakani@Sun.COM 
81911963SAfshin.Ardakani@Sun.COM /*
82011963SAfshin.Ardakani@Sun.COM  * smb_slist_wait_for_empty
82111963SAfshin.Ardakani@Sun.COM  *
82211963SAfshin.Ardakani@Sun.COM  * This function waits for a list to be emptied.
82311963SAfshin.Ardakani@Sun.COM  */
82411963SAfshin.Ardakani@Sun.COM void
smb_slist_wait_for_empty(smb_slist_t * sl)82511963SAfshin.Ardakani@Sun.COM smb_slist_wait_for_empty(
82611963SAfshin.Ardakani@Sun.COM     smb_slist_t	*sl)
82711963SAfshin.Ardakani@Sun.COM {
82811963SAfshin.Ardakani@Sun.COM 	mutex_enter(&sl->sl_mutex);
82911963SAfshin.Ardakani@Sun.COM 	while (sl->sl_count) {
83011963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_TRUE;
83111963SAfshin.Ardakani@Sun.COM 		cv_wait(&sl->sl_cv, &sl->sl_mutex);
83211963SAfshin.Ardakani@Sun.COM 	}
83311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
83411963SAfshin.Ardakani@Sun.COM }
83511963SAfshin.Ardakani@Sun.COM 
83611963SAfshin.Ardakani@Sun.COM /*
83711963SAfshin.Ardakani@Sun.COM  * smb_slist_exit
83811963SAfshin.Ardakani@Sun.COM  *
83911963SAfshin.Ardakani@Sun.COM  * This function exits the muetx of the list and signal the condition variable
84011963SAfshin.Ardakani@Sun.COM  * if the list is empty.
84111963SAfshin.Ardakani@Sun.COM  */
84211963SAfshin.Ardakani@Sun.COM void
smb_slist_exit(smb_slist_t * sl)84311963SAfshin.Ardakani@Sun.COM smb_slist_exit(smb_slist_t *sl)
84411963SAfshin.Ardakani@Sun.COM {
84511963SAfshin.Ardakani@Sun.COM 	if ((sl->sl_count == 0) && (sl->sl_waiting)) {
84611963SAfshin.Ardakani@Sun.COM 		sl->sl_waiting = B_FALSE;
84711963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&sl->sl_cv);
84811963SAfshin.Ardakani@Sun.COM 	}
84911963SAfshin.Ardakani@Sun.COM 	mutex_exit(&sl->sl_mutex);
85011963SAfshin.Ardakani@Sun.COM }
85111963SAfshin.Ardakani@Sun.COM 
85211963SAfshin.Ardakani@Sun.COM /*
85311963SAfshin.Ardakani@Sun.COM  * smb_thread_entry_point
85411963SAfshin.Ardakani@Sun.COM  *
85511963SAfshin.Ardakani@Sun.COM  * Common entry point for all the threads created through smb_thread_start.
85611963SAfshin.Ardakani@Sun.COM  * The state of the thread is set to "running" at the beginning and moved to
85711963SAfshin.Ardakani@Sun.COM  * "exiting" just before calling thread_exit(). The condition variable is
85811963SAfshin.Ardakani@Sun.COM  *  also signaled.
85911963SAfshin.Ardakani@Sun.COM  */
86011963SAfshin.Ardakani@Sun.COM static void
smb_thread_entry_point(smb_thread_t * thread)86111963SAfshin.Ardakani@Sun.COM smb_thread_entry_point(
86211963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
86311963SAfshin.Ardakani@Sun.COM {
86411963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
86511963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
86611963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_state == SMB_THREAD_STATE_STARTING);
86711963SAfshin.Ardakani@Sun.COM 	thread->sth_th = curthread;
86811963SAfshin.Ardakani@Sun.COM 	thread->sth_did = thread->sth_th->t_did;
86911963SAfshin.Ardakani@Sun.COM 
87011963SAfshin.Ardakani@Sun.COM 	if (!thread->sth_kill) {
87111963SAfshin.Ardakani@Sun.COM 		thread->sth_state = SMB_THREAD_STATE_RUNNING;
87211963SAfshin.Ardakani@Sun.COM 		cv_signal(&thread->sth_cv);
87311963SAfshin.Ardakani@Sun.COM 		mutex_exit(&thread->sth_mtx);
87411963SAfshin.Ardakani@Sun.COM 		thread->sth_ep(thread, thread->sth_ep_arg);
87511963SAfshin.Ardakani@Sun.COM 		mutex_enter(&thread->sth_mtx);
87611963SAfshin.Ardakani@Sun.COM 	}
87711963SAfshin.Ardakani@Sun.COM 	thread->sth_th = NULL;
87811963SAfshin.Ardakani@Sun.COM 	thread->sth_state = SMB_THREAD_STATE_EXITING;
87911963SAfshin.Ardakani@Sun.COM 	cv_broadcast(&thread->sth_cv);
88011963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
88111963SAfshin.Ardakani@Sun.COM 	thread_exit();
88211963SAfshin.Ardakani@Sun.COM }
88311963SAfshin.Ardakani@Sun.COM 
88411963SAfshin.Ardakani@Sun.COM /*
88511963SAfshin.Ardakani@Sun.COM  * smb_thread_init
88611963SAfshin.Ardakani@Sun.COM  */
88711963SAfshin.Ardakani@Sun.COM void
smb_thread_init(smb_thread_t * thread,char * name,smb_thread_ep_t ep,void * ep_arg)88811963SAfshin.Ardakani@Sun.COM smb_thread_init(
88911963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread,
89011963SAfshin.Ardakani@Sun.COM     char		*name,
89111963SAfshin.Ardakani@Sun.COM     smb_thread_ep_t	ep,
892*13138SJose.Borrego@Sun.COM     void		*ep_arg)
89311963SAfshin.Ardakani@Sun.COM {
89411963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic != SMB_THREAD_MAGIC);
89511963SAfshin.Ardakani@Sun.COM 
89611963SAfshin.Ardakani@Sun.COM 	bzero(thread, sizeof (*thread));
89711963SAfshin.Ardakani@Sun.COM 
89811963SAfshin.Ardakani@Sun.COM 	(void) strlcpy(thread->sth_name, name, sizeof (thread->sth_name));
89911963SAfshin.Ardakani@Sun.COM 	thread->sth_ep = ep;
90011963SAfshin.Ardakani@Sun.COM 	thread->sth_ep_arg = ep_arg;
90111963SAfshin.Ardakani@Sun.COM 	thread->sth_state = SMB_THREAD_STATE_EXITED;
90211963SAfshin.Ardakani@Sun.COM 	mutex_init(&thread->sth_mtx, NULL, MUTEX_DEFAULT, NULL);
90311963SAfshin.Ardakani@Sun.COM 	cv_init(&thread->sth_cv, NULL, CV_DEFAULT, NULL);
90411963SAfshin.Ardakani@Sun.COM 	thread->sth_magic = SMB_THREAD_MAGIC;
90511963SAfshin.Ardakani@Sun.COM }
90611963SAfshin.Ardakani@Sun.COM 
90711963SAfshin.Ardakani@Sun.COM /*
90811963SAfshin.Ardakani@Sun.COM  * smb_thread_destroy
90911963SAfshin.Ardakani@Sun.COM  */
91011963SAfshin.Ardakani@Sun.COM void
smb_thread_destroy(smb_thread_t * thread)91111963SAfshin.Ardakani@Sun.COM smb_thread_destroy(
91211963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
91311963SAfshin.Ardakani@Sun.COM {
91411963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
91511963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_state == SMB_THREAD_STATE_EXITED);
91611963SAfshin.Ardakani@Sun.COM 	thread->sth_magic = 0;
91711963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&thread->sth_mtx);
91811963SAfshin.Ardakani@Sun.COM 	cv_destroy(&thread->sth_cv);
91911963SAfshin.Ardakani@Sun.COM }
92011963SAfshin.Ardakani@Sun.COM 
92111963SAfshin.Ardakani@Sun.COM /*
92211963SAfshin.Ardakani@Sun.COM  * smb_thread_start
92311963SAfshin.Ardakani@Sun.COM  *
92411963SAfshin.Ardakani@Sun.COM  * This function starts a thread with the parameters provided. It waits until
92511963SAfshin.Ardakani@Sun.COM  * the state of the thread has been moved to running.
92611963SAfshin.Ardakani@Sun.COM  */
92711963SAfshin.Ardakani@Sun.COM /*ARGSUSED*/
92811963SAfshin.Ardakani@Sun.COM int
smb_thread_start(smb_thread_t * thread)92911963SAfshin.Ardakani@Sun.COM smb_thread_start(
93011963SAfshin.Ardakani@Sun.COM     smb_thread_t	*thread)
93111963SAfshin.Ardakani@Sun.COM {
93211963SAfshin.Ardakani@Sun.COM 	int		rc = 0;
93311963SAfshin.Ardakani@Sun.COM 	kthread_t	*tmpthread;
93411963SAfshin.Ardakani@Sun.COM 
93511963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
93611963SAfshin.Ardakani@Sun.COM 
93711963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
93811963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
93911963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_EXITED:
94011963SAfshin.Ardakani@Sun.COM 		thread->sth_state = SMB_THREAD_STATE_STARTING;
94111963SAfshin.Ardakani@Sun.COM 		mutex_exit(&thread->sth_mtx);
94211963SAfshin.Ardakani@Sun.COM 		tmpthread = thread_create(NULL, 0, smb_thread_entry_point,
94311963SAfshin.Ardakani@Sun.COM 		    thread, 0, &p0, TS_RUN, minclsyspri);
94411963SAfshin.Ardakani@Sun.COM 		ASSERT(tmpthread != NULL);
94511963SAfshin.Ardakani@Sun.COM 		mutex_enter(&thread->sth_mtx);
94611963SAfshin.Ardakani@Sun.COM 		while (thread->sth_state == SMB_THREAD_STATE_STARTING)
94711963SAfshin.Ardakani@Sun.COM 			cv_wait(&thread->sth_cv, &thread->sth_mtx);
94811963SAfshin.Ardakani@Sun.COM 		if (thread->sth_state != SMB_THREAD_STATE_RUNNING)
94911963SAfshin.Ardakani@Sun.COM 			rc = -1;
95011963SAfshin.Ardakani@Sun.COM 		break;
95111963SAfshin.Ardakani@Sun.COM 	default:
95211963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
95311963SAfshin.Ardakani@Sun.COM 		rc = -1;
95411963SAfshin.Ardakani@Sun.COM 		break;
95511963SAfshin.Ardakani@Sun.COM 	}
95611963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
95711963SAfshin.Ardakani@Sun.COM 	return (rc);
95811963SAfshin.Ardakani@Sun.COM }
95911963SAfshin.Ardakani@Sun.COM 
96011963SAfshin.Ardakani@Sun.COM /*
96111963SAfshin.Ardakani@Sun.COM  * smb_thread_stop
96211963SAfshin.Ardakani@Sun.COM  *
96311963SAfshin.Ardakani@Sun.COM  * This function signals a thread to kill itself and waits until the "exiting"
96411963SAfshin.Ardakani@Sun.COM  * state has been reached.
96511963SAfshin.Ardakani@Sun.COM  */
96611963SAfshin.Ardakani@Sun.COM void
smb_thread_stop(smb_thread_t * thread)967*13138SJose.Borrego@Sun.COM smb_thread_stop(smb_thread_t *thread)
96811963SAfshin.Ardakani@Sun.COM {
96911963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
97011963SAfshin.Ardakani@Sun.COM 
97111963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
97211963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
97311963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_RUNNING:
97411963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_STARTING:
97511963SAfshin.Ardakani@Sun.COM 		if (!thread->sth_kill) {
97611963SAfshin.Ardakani@Sun.COM 			thread->sth_kill = B_TRUE;
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
smb_thread_signal(smb_thread_t * thread)1017*13138SJose.Borrego@Sun.COM smb_thread_signal(smb_thread_t *thread)
101811963SAfshin.Ardakani@Sun.COM {
101911963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
102011963SAfshin.Ardakani@Sun.COM 
102111963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
102211963SAfshin.Ardakani@Sun.COM 	switch (thread->sth_state) {
102311963SAfshin.Ardakani@Sun.COM 	case SMB_THREAD_STATE_RUNNING:
102411963SAfshin.Ardakani@Sun.COM 		cv_signal(&thread->sth_cv);
102511963SAfshin.Ardakani@Sun.COM 		break;
102611963SAfshin.Ardakani@Sun.COM 
102711963SAfshin.Ardakani@Sun.COM 	default:
102811963SAfshin.Ardakani@Sun.COM 		break;
102911963SAfshin.Ardakani@Sun.COM 	}
103011963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
103111963SAfshin.Ardakani@Sun.COM }
103211963SAfshin.Ardakani@Sun.COM 
103311963SAfshin.Ardakani@Sun.COM boolean_t
smb_thread_continue(smb_thread_t * thread)103411963SAfshin.Ardakani@Sun.COM smb_thread_continue(smb_thread_t *thread)
103511963SAfshin.Ardakani@Sun.COM {
103611963SAfshin.Ardakani@Sun.COM 	boolean_t result;
103711963SAfshin.Ardakani@Sun.COM 
103811963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
103911963SAfshin.Ardakani@Sun.COM 
104011963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
104111963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread, 0);
104211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
104311963SAfshin.Ardakani@Sun.COM 
104411963SAfshin.Ardakani@Sun.COM 	return (result);
104511963SAfshin.Ardakani@Sun.COM }
104611963SAfshin.Ardakani@Sun.COM 
104711963SAfshin.Ardakani@Sun.COM boolean_t
smb_thread_continue_nowait(smb_thread_t * thread)104811963SAfshin.Ardakani@Sun.COM smb_thread_continue_nowait(smb_thread_t *thread)
104911963SAfshin.Ardakani@Sun.COM {
105011963SAfshin.Ardakani@Sun.COM 	boolean_t result;
105111963SAfshin.Ardakani@Sun.COM 
105211963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
105311963SAfshin.Ardakani@Sun.COM 
105411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
105511963SAfshin.Ardakani@Sun.COM 	/*
105611963SAfshin.Ardakani@Sun.COM 	 * Setting ticks=-1 requests a non-blocking check.  We will
105711963SAfshin.Ardakani@Sun.COM 	 * still block if the thread is in "suspend" state.
105811963SAfshin.Ardakani@Sun.COM 	 */
105911963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread, -1);
106011963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
106111963SAfshin.Ardakani@Sun.COM 
106211963SAfshin.Ardakani@Sun.COM 	return (result);
106311963SAfshin.Ardakani@Sun.COM }
106411963SAfshin.Ardakani@Sun.COM 
106511963SAfshin.Ardakani@Sun.COM boolean_t
smb_thread_continue_timedwait(smb_thread_t * thread,int seconds)106611963SAfshin.Ardakani@Sun.COM smb_thread_continue_timedwait(smb_thread_t *thread, int seconds)
106711963SAfshin.Ardakani@Sun.COM {
106811963SAfshin.Ardakani@Sun.COM 	boolean_t result;
106911963SAfshin.Ardakani@Sun.COM 
107011963SAfshin.Ardakani@Sun.COM 	ASSERT(thread->sth_magic == SMB_THREAD_MAGIC);
107111963SAfshin.Ardakani@Sun.COM 
107211963SAfshin.Ardakani@Sun.COM 	mutex_enter(&thread->sth_mtx);
107311963SAfshin.Ardakani@Sun.COM 	result = smb_thread_continue_timedwait_locked(thread,
107411963SAfshin.Ardakani@Sun.COM 	    SEC_TO_TICK(seconds));
107511963SAfshin.Ardakani@Sun.COM 	mutex_exit(&thread->sth_mtx);
107611963SAfshin.Ardakani@Sun.COM 
107711963SAfshin.Ardakani@Sun.COM 	return (result);
107811963SAfshin.Ardakani@Sun.COM }
107911963SAfshin.Ardakani@Sun.COM 
108011963SAfshin.Ardakani@Sun.COM /*
108111963SAfshin.Ardakani@Sun.COM  * smb_thread_continue_timedwait_locked
108211963SAfshin.Ardakani@Sun.COM  *
108311963SAfshin.Ardakani@Sun.COM  * Internal only.  Ticks==-1 means don't block, Ticks == 0 means wait
108411963SAfshin.Ardakani@Sun.COM  * indefinitely
108511963SAfshin.Ardakani@Sun.COM  */
108611963SAfshin.Ardakani@Sun.COM static boolean_t
smb_thread_continue_timedwait_locked(smb_thread_t * thread,int ticks)108711963SAfshin.Ardakani@Sun.COM smb_thread_continue_timedwait_locked(smb_thread_t *thread, int ticks)
108811963SAfshin.Ardakani@Sun.COM {
108911963SAfshin.Ardakani@Sun.COM 	boolean_t	result;
109011963SAfshin.Ardakani@Sun.COM 
109111963SAfshin.Ardakani@Sun.COM 	/* -1 means don't block */
109211963SAfshin.Ardakani@Sun.COM 	if (ticks != -1 && !thread->sth_kill) {
109311963SAfshin.Ardakani@Sun.COM 		if (ticks == 0) {
109411963SAfshin.Ardakani@Sun.COM 			cv_wait(&thread->sth_cv, &thread->sth_mtx);
109511963SAfshin.Ardakani@Sun.COM 		} else {
109611963SAfshin.Ardakani@Sun.COM 			(void) cv_reltimedwait(&thread->sth_cv,
109711963SAfshin.Ardakani@Sun.COM 			    &thread->sth_mtx, (clock_t)ticks, TR_CLOCK_TICK);
109811963SAfshin.Ardakani@Sun.COM 		}
109911963SAfshin.Ardakani@Sun.COM 	}
110011963SAfshin.Ardakani@Sun.COM 	result = (thread->sth_kill == 0);
110111963SAfshin.Ardakani@Sun.COM 
110211963SAfshin.Ardakani@Sun.COM 	return (result);
110311963SAfshin.Ardakani@Sun.COM }
110411963SAfshin.Ardakani@Sun.COM 
110511963SAfshin.Ardakani@Sun.COM /*
110611963SAfshin.Ardakani@Sun.COM  * smb_rwx_init
110711963SAfshin.Ardakani@Sun.COM  */
110811963SAfshin.Ardakani@Sun.COM void
smb_rwx_init(smb_rwx_t * rwx)110911963SAfshin.Ardakani@Sun.COM smb_rwx_init(
111011963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
111111963SAfshin.Ardakani@Sun.COM {
111211963SAfshin.Ardakani@Sun.COM 	bzero(rwx, sizeof (smb_rwx_t));
111311963SAfshin.Ardakani@Sun.COM 	cv_init(&rwx->rwx_cv, NULL, CV_DEFAULT, NULL);
111411963SAfshin.Ardakani@Sun.COM 	mutex_init(&rwx->rwx_mutex, NULL, MUTEX_DEFAULT, NULL);
111511963SAfshin.Ardakani@Sun.COM 	rw_init(&rwx->rwx_lock, NULL, RW_DEFAULT, NULL);
111611963SAfshin.Ardakani@Sun.COM }
111711963SAfshin.Ardakani@Sun.COM 
111811963SAfshin.Ardakani@Sun.COM /*
111911963SAfshin.Ardakani@Sun.COM  * smb_rwx_destroy
112011963SAfshin.Ardakani@Sun.COM  */
112111963SAfshin.Ardakani@Sun.COM void
smb_rwx_destroy(smb_rwx_t * rwx)112211963SAfshin.Ardakani@Sun.COM smb_rwx_destroy(
112311963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
112411963SAfshin.Ardakani@Sun.COM {
112511963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&rwx->rwx_mutex);
112611963SAfshin.Ardakani@Sun.COM 	cv_destroy(&rwx->rwx_cv);
112711963SAfshin.Ardakani@Sun.COM 	rw_destroy(&rwx->rwx_lock);
112811963SAfshin.Ardakani@Sun.COM }
112911963SAfshin.Ardakani@Sun.COM 
113011963SAfshin.Ardakani@Sun.COM /*
113111963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwexit
113211963SAfshin.Ardakani@Sun.COM  */
113311963SAfshin.Ardakani@Sun.COM void
smb_rwx_rwexit(smb_rwx_t * rwx)113411963SAfshin.Ardakani@Sun.COM smb_rwx_rwexit(
113511963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
113611963SAfshin.Ardakani@Sun.COM {
113711963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
113811963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
113911963SAfshin.Ardakani@Sun.COM 		mutex_enter(&rwx->rwx_mutex);
114011963SAfshin.Ardakani@Sun.COM 		if (rwx->rwx_waiting) {
114111963SAfshin.Ardakani@Sun.COM 			rwx->rwx_waiting = B_FALSE;
114211963SAfshin.Ardakani@Sun.COM 			cv_broadcast(&rwx->rwx_cv);
114311963SAfshin.Ardakani@Sun.COM 		}
114411963SAfshin.Ardakani@Sun.COM 		mutex_exit(&rwx->rwx_mutex);
114511963SAfshin.Ardakani@Sun.COM 	}
114611963SAfshin.Ardakani@Sun.COM 	rw_exit(&rwx->rwx_lock);
114711963SAfshin.Ardakani@Sun.COM }
114811963SAfshin.Ardakani@Sun.COM 
114911963SAfshin.Ardakani@Sun.COM /*
115011963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwupgrade
115111963SAfshin.Ardakani@Sun.COM  */
115211963SAfshin.Ardakani@Sun.COM krw_t
smb_rwx_rwupgrade(smb_rwx_t * rwx)115311963SAfshin.Ardakani@Sun.COM smb_rwx_rwupgrade(
115411963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx)
115511963SAfshin.Ardakani@Sun.COM {
115611963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
115711963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
115811963SAfshin.Ardakani@Sun.COM 		return (RW_WRITER);
115911963SAfshin.Ardakani@Sun.COM 	}
116011963SAfshin.Ardakani@Sun.COM 	if (!rw_tryupgrade(&rwx->rwx_lock)) {
116111963SAfshin.Ardakani@Sun.COM 		rw_exit(&rwx->rwx_lock);
116211963SAfshin.Ardakani@Sun.COM 		rw_enter(&rwx->rwx_lock, RW_WRITER);
116311963SAfshin.Ardakani@Sun.COM 	}
116411963SAfshin.Ardakani@Sun.COM 	return (RW_READER);
116511963SAfshin.Ardakani@Sun.COM }
116611963SAfshin.Ardakani@Sun.COM 
116711963SAfshin.Ardakani@Sun.COM /*
116811963SAfshin.Ardakani@Sun.COM  * smb_rwx_rwrestore
116911963SAfshin.Ardakani@Sun.COM  */
117011963SAfshin.Ardakani@Sun.COM void
smb_rwx_rwdowngrade(smb_rwx_t * rwx,krw_t mode)117111963SAfshin.Ardakani@Sun.COM smb_rwx_rwdowngrade(
117211963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx,
117311963SAfshin.Ardakani@Sun.COM     krw_t	mode)
117411963SAfshin.Ardakani@Sun.COM {
117511963SAfshin.Ardakani@Sun.COM 	ASSERT(rw_write_held(&rwx->rwx_lock));
117611963SAfshin.Ardakani@Sun.COM 	ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
117711963SAfshin.Ardakani@Sun.COM 
117811963SAfshin.Ardakani@Sun.COM 	if (mode == RW_WRITER) {
117911963SAfshin.Ardakani@Sun.COM 		return;
118011963SAfshin.Ardakani@Sun.COM 	}
118111963SAfshin.Ardakani@Sun.COM 	ASSERT(mode == RW_READER);
118211963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
118311963SAfshin.Ardakani@Sun.COM 	if (rwx->rwx_waiting) {
118411963SAfshin.Ardakani@Sun.COM 		rwx->rwx_waiting = B_FALSE;
118511963SAfshin.Ardakani@Sun.COM 		cv_broadcast(&rwx->rwx_cv);
118611963SAfshin.Ardakani@Sun.COM 	}
118711963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
118811963SAfshin.Ardakani@Sun.COM 	rw_downgrade(&rwx->rwx_lock);
118911963SAfshin.Ardakani@Sun.COM }
119011963SAfshin.Ardakani@Sun.COM 
119111963SAfshin.Ardakani@Sun.COM /*
119211963SAfshin.Ardakani@Sun.COM  * smb_rwx_wait
119311963SAfshin.Ardakani@Sun.COM  *
119411963SAfshin.Ardakani@Sun.COM  * This function assumes the smb_rwx lock was enter in RW_READER or RW_WRITER
119511963SAfshin.Ardakani@Sun.COM  * mode. It will:
119611963SAfshin.Ardakani@Sun.COM  *
119711963SAfshin.Ardakani@Sun.COM  *	1) release the lock and save its current mode.
119811963SAfshin.Ardakani@Sun.COM  *	2) wait until the condition variable is signaled. This can happen for
119911963SAfshin.Ardakani@Sun.COM  *	   2 reasons: When a writer releases the lock or when the time out (if
120011963SAfshin.Ardakani@Sun.COM  *	   provided) expires.
120111963SAfshin.Ardakani@Sun.COM  *	3) re-acquire the lock in the mode saved in (1).
120211963SAfshin.Ardakani@Sun.COM  */
120311963SAfshin.Ardakani@Sun.COM int
smb_rwx_rwwait(smb_rwx_t * rwx,clock_t timeout)120411963SAfshin.Ardakani@Sun.COM smb_rwx_rwwait(
120511963SAfshin.Ardakani@Sun.COM     smb_rwx_t	*rwx,
120611963SAfshin.Ardakani@Sun.COM     clock_t	timeout)
120711963SAfshin.Ardakani@Sun.COM {
120811963SAfshin.Ardakani@Sun.COM 	int	rc;
120911963SAfshin.Ardakani@Sun.COM 	krw_t	mode;
121011963SAfshin.Ardakani@Sun.COM 
121111963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
121211963SAfshin.Ardakani@Sun.COM 	rwx->rwx_waiting = B_TRUE;
121311963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
121411963SAfshin.Ardakani@Sun.COM 
121511963SAfshin.Ardakani@Sun.COM 	if (rw_write_held(&rwx->rwx_lock)) {
121611963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_owner(&rwx->rwx_lock) == curthread);
121711963SAfshin.Ardakani@Sun.COM 		mode = RW_WRITER;
121811963SAfshin.Ardakani@Sun.COM 	} else {
121911963SAfshin.Ardakani@Sun.COM 		ASSERT(rw_read_held(&rwx->rwx_lock));
122011963SAfshin.Ardakani@Sun.COM 		mode = RW_READER;
122111963SAfshin.Ardakani@Sun.COM 	}
122211963SAfshin.Ardakani@Sun.COM 	rw_exit(&rwx->rwx_lock);
122311963SAfshin.Ardakani@Sun.COM 
122411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&rwx->rwx_mutex);
122511963SAfshin.Ardakani@Sun.COM 	if (rwx->rwx_waiting) {
122611963SAfshin.Ardakani@Sun.COM 		if (timeout == -1) {
122711963SAfshin.Ardakani@Sun.COM 			rc = 1;
122811963SAfshin.Ardakani@Sun.COM 			cv_wait(&rwx->rwx_cv, &rwx->rwx_mutex);
122911963SAfshin.Ardakani@Sun.COM 		} else {
123011963SAfshin.Ardakani@Sun.COM 			rc = cv_reltimedwait(&rwx->rwx_cv, &rwx->rwx_mutex,
123111963SAfshin.Ardakani@Sun.COM 			    timeout, TR_CLOCK_TICK);
123211963SAfshin.Ardakani@Sun.COM 		}
123311963SAfshin.Ardakani@Sun.COM 	}
123411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&rwx->rwx_mutex);
123511963SAfshin.Ardakani@Sun.COM 
123611963SAfshin.Ardakani@Sun.COM 	rw_enter(&rwx->rwx_lock, mode);
123711963SAfshin.Ardakani@Sun.COM 	return (rc);
123811963SAfshin.Ardakani@Sun.COM }
123911963SAfshin.Ardakani@Sun.COM 
124011963SAfshin.Ardakani@Sun.COM /*
124111963SAfshin.Ardakani@Sun.COM  * SMB ID mapping
124211963SAfshin.Ardakani@Sun.COM  *
124311963SAfshin.Ardakani@Sun.COM  * Solaris ID mapping service (aka Winchester) works with domain SIDs
124411963SAfshin.Ardakani@Sun.COM  * and RIDs where domain SIDs are in string format. CIFS service works
124511963SAfshin.Ardakani@Sun.COM  * with binary SIDs understandable by CIFS clients. A layer of SMB ID
124611963SAfshin.Ardakani@Sun.COM  * mapping functions are implemeted to hide the SID conversion details
124711963SAfshin.Ardakani@Sun.COM  * and also hide the handling of array of batch mapping requests.
124811963SAfshin.Ardakani@Sun.COM  *
124911963SAfshin.Ardakani@Sun.COM  * IMPORTANT NOTE The Winchester API requires a zone. Because CIFS server
125011963SAfshin.Ardakani@Sun.COM  * currently only runs in the global zone the global zone is specified.
125111963SAfshin.Ardakani@Sun.COM  * This needs to be fixed when the CIFS server supports zones.
125211963SAfshin.Ardakani@Sun.COM  */
125311963SAfshin.Ardakani@Sun.COM 
125411963SAfshin.Ardakani@Sun.COM static int smb_idmap_batch_binsid(smb_idmap_batch_t *sib);
125511963SAfshin.Ardakani@Sun.COM 
125611963SAfshin.Ardakani@Sun.COM /*
125711963SAfshin.Ardakani@Sun.COM  * smb_idmap_getid
125811963SAfshin.Ardakani@Sun.COM  *
125911963SAfshin.Ardakani@Sun.COM  * Maps the given Windows SID to a Solaris ID using the
126011963SAfshin.Ardakani@Sun.COM  * simple mapping API.
126111963SAfshin.Ardakani@Sun.COM  */
126211963SAfshin.Ardakani@Sun.COM idmap_stat
smb_idmap_getid(smb_sid_t * sid,uid_t * id,int * idtype)126311963SAfshin.Ardakani@Sun.COM smb_idmap_getid(smb_sid_t *sid, uid_t *id, int *idtype)
126411963SAfshin.Ardakani@Sun.COM {
126511963SAfshin.Ardakani@Sun.COM 	smb_idmap_t sim;
126611963SAfshin.Ardakani@Sun.COM 	char sidstr[SMB_SID_STRSZ];
126711963SAfshin.Ardakani@Sun.COM 
126811963SAfshin.Ardakani@Sun.COM 	smb_sid_tostr(sid, sidstr);
126911963SAfshin.Ardakani@Sun.COM 	if (smb_sid_splitstr(sidstr, &sim.sim_rid) != 0)
127011963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_SID);
127111963SAfshin.Ardakani@Sun.COM 	sim.sim_domsid = sidstr;
127211963SAfshin.Ardakani@Sun.COM 	sim.sim_id = id;
127311963SAfshin.Ardakani@Sun.COM 
127411963SAfshin.Ardakani@Sun.COM 	switch (*idtype) {
127511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
127611963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getuidbysid(global_zone, sim.sim_domsid,
127711963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id);
127811963SAfshin.Ardakani@Sun.COM 		break;
127911963SAfshin.Ardakani@Sun.COM 
128011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
128111963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getgidbysid(global_zone, sim.sim_domsid,
128211963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id);
128311963SAfshin.Ardakani@Sun.COM 		break;
128411963SAfshin.Ardakani@Sun.COM 
128511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_UNKNOWN:
128611963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getpidbysid(global_zone, sim.sim_domsid,
128711963SAfshin.Ardakani@Sun.COM 		    sim.sim_rid, sim.sim_id, &sim.sim_idtype);
128811963SAfshin.Ardakani@Sun.COM 		break;
128911963SAfshin.Ardakani@Sun.COM 
129011963SAfshin.Ardakani@Sun.COM 	default:
129111963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
129211963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
129311963SAfshin.Ardakani@Sun.COM 	}
129411963SAfshin.Ardakani@Sun.COM 
129511963SAfshin.Ardakani@Sun.COM 	*idtype = sim.sim_idtype;
129611963SAfshin.Ardakani@Sun.COM 
129711963SAfshin.Ardakani@Sun.COM 	return (sim.sim_stat);
129811963SAfshin.Ardakani@Sun.COM }
129911963SAfshin.Ardakani@Sun.COM 
130011963SAfshin.Ardakani@Sun.COM /*
130111963SAfshin.Ardakani@Sun.COM  * smb_idmap_getsid
130211963SAfshin.Ardakani@Sun.COM  *
130311963SAfshin.Ardakani@Sun.COM  * Maps the given Solaris ID to a Windows SID using the
130411963SAfshin.Ardakani@Sun.COM  * simple mapping API.
130511963SAfshin.Ardakani@Sun.COM  */
130611963SAfshin.Ardakani@Sun.COM idmap_stat
smb_idmap_getsid(uid_t id,int idtype,smb_sid_t ** sid)130711963SAfshin.Ardakani@Sun.COM smb_idmap_getsid(uid_t id, int idtype, smb_sid_t **sid)
130811963SAfshin.Ardakani@Sun.COM {
130911963SAfshin.Ardakani@Sun.COM 	smb_idmap_t sim;
131011963SAfshin.Ardakani@Sun.COM 
131111963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
131211963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
131311963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getsidbyuid(global_zone, id,
131411963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim.sim_domsid, &sim.sim_rid);
131511963SAfshin.Ardakani@Sun.COM 		break;
131611963SAfshin.Ardakani@Sun.COM 
131711963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
131811963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = kidmap_getsidbygid(global_zone, id,
131911963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim.sim_domsid, &sim.sim_rid);
132011963SAfshin.Ardakani@Sun.COM 		break;
132111963SAfshin.Ardakani@Sun.COM 
132211963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_EVERYONE:
132311963SAfshin.Ardakani@Sun.COM 		/* Everyone S-1-1-0 */
132411963SAfshin.Ardakani@Sun.COM 		sim.sim_domsid = "S-1-1";
132511963SAfshin.Ardakani@Sun.COM 		sim.sim_rid = 0;
132611963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = IDMAP_SUCCESS;
132711963SAfshin.Ardakani@Sun.COM 		break;
132811963SAfshin.Ardakani@Sun.COM 
132911963SAfshin.Ardakani@Sun.COM 	default:
133011963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
133111963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
133211963SAfshin.Ardakani@Sun.COM 	}
133311963SAfshin.Ardakani@Sun.COM 
133411963SAfshin.Ardakani@Sun.COM 	if (sim.sim_stat != IDMAP_SUCCESS)
133511963SAfshin.Ardakani@Sun.COM 		return (sim.sim_stat);
133611963SAfshin.Ardakani@Sun.COM 
133711963SAfshin.Ardakani@Sun.COM 	if (sim.sim_domsid == NULL)
133811963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_NOMAPPING);
133911963SAfshin.Ardakani@Sun.COM 
134011963SAfshin.Ardakani@Sun.COM 	sim.sim_sid = smb_sid_fromstr(sim.sim_domsid);
134111963SAfshin.Ardakani@Sun.COM 	if (sim.sim_sid == NULL)
134211963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_INTERNAL);
134311963SAfshin.Ardakani@Sun.COM 
134411963SAfshin.Ardakani@Sun.COM 	*sid = smb_sid_splice(sim.sim_sid, sim.sim_rid);
134511963SAfshin.Ardakani@Sun.COM 	smb_sid_free(sim.sim_sid);
134611963SAfshin.Ardakani@Sun.COM 	if (*sid == NULL)
134711963SAfshin.Ardakani@Sun.COM 		sim.sim_stat = IDMAP_ERR_INTERNAL;
134811963SAfshin.Ardakani@Sun.COM 
134911963SAfshin.Ardakani@Sun.COM 	return (sim.sim_stat);
135011963SAfshin.Ardakani@Sun.COM }
135111963SAfshin.Ardakani@Sun.COM 
135211963SAfshin.Ardakani@Sun.COM /*
135311963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_create
135411963SAfshin.Ardakani@Sun.COM  *
135511963SAfshin.Ardakani@Sun.COM  * Creates and initializes the context for batch ID mapping.
135611963SAfshin.Ardakani@Sun.COM  */
135711963SAfshin.Ardakani@Sun.COM idmap_stat
smb_idmap_batch_create(smb_idmap_batch_t * sib,uint16_t nmap,int flags)135811963SAfshin.Ardakani@Sun.COM smb_idmap_batch_create(smb_idmap_batch_t *sib, uint16_t nmap, int flags)
135911963SAfshin.Ardakani@Sun.COM {
136011963SAfshin.Ardakani@Sun.COM 	ASSERT(sib);
136111963SAfshin.Ardakani@Sun.COM 
136211963SAfshin.Ardakani@Sun.COM 	bzero(sib, sizeof (smb_idmap_batch_t));
136311963SAfshin.Ardakani@Sun.COM 
136411963SAfshin.Ardakani@Sun.COM 	sib->sib_idmaph = kidmap_get_create(global_zone);
136511963SAfshin.Ardakani@Sun.COM 
136611963SAfshin.Ardakani@Sun.COM 	sib->sib_flags = flags;
136711963SAfshin.Ardakani@Sun.COM 	sib->sib_nmap = nmap;
136811963SAfshin.Ardakani@Sun.COM 	sib->sib_size = nmap * sizeof (smb_idmap_t);
136911963SAfshin.Ardakani@Sun.COM 	sib->sib_maps = kmem_zalloc(sib->sib_size, KM_SLEEP);
137011963SAfshin.Ardakani@Sun.COM 
137111963SAfshin.Ardakani@Sun.COM 	return (IDMAP_SUCCESS);
137211963SAfshin.Ardakani@Sun.COM }
137311963SAfshin.Ardakani@Sun.COM 
137411963SAfshin.Ardakani@Sun.COM /*
137511963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_destroy
137611963SAfshin.Ardakani@Sun.COM  *
137711963SAfshin.Ardakani@Sun.COM  * Frees the batch ID mapping context.
137811963SAfshin.Ardakani@Sun.COM  * If ID mapping is Solaris -> Windows it frees memories
137911963SAfshin.Ardakani@Sun.COM  * allocated for binary SIDs.
138011963SAfshin.Ardakani@Sun.COM  */
138111963SAfshin.Ardakani@Sun.COM void
smb_idmap_batch_destroy(smb_idmap_batch_t * sib)138211963SAfshin.Ardakani@Sun.COM smb_idmap_batch_destroy(smb_idmap_batch_t *sib)
138311963SAfshin.Ardakani@Sun.COM {
138411963SAfshin.Ardakani@Sun.COM 	char *domsid;
138511963SAfshin.Ardakani@Sun.COM 	int i;
138611963SAfshin.Ardakani@Sun.COM 
138711963SAfshin.Ardakani@Sun.COM 	ASSERT(sib);
138811963SAfshin.Ardakani@Sun.COM 	ASSERT(sib->sib_maps);
138911963SAfshin.Ardakani@Sun.COM 
139011963SAfshin.Ardakani@Sun.COM 	if (sib->sib_idmaph)
139111963SAfshin.Ardakani@Sun.COM 		kidmap_get_destroy(sib->sib_idmaph);
139211963SAfshin.Ardakani@Sun.COM 
139311963SAfshin.Ardakani@Sun.COM 	if (sib->sib_flags & SMB_IDMAP_ID2SID) {
139411963SAfshin.Ardakani@Sun.COM 		/*
139511963SAfshin.Ardakani@Sun.COM 		 * SIDs are allocated only when mapping
139611963SAfshin.Ardakani@Sun.COM 		 * UID/GID to SIDs
139711963SAfshin.Ardakani@Sun.COM 		 */
139811963SAfshin.Ardakani@Sun.COM 		for (i = 0; i < sib->sib_nmap; i++)
139911963SAfshin.Ardakani@Sun.COM 			smb_sid_free(sib->sib_maps[i].sim_sid);
140011963SAfshin.Ardakani@Sun.COM 	} else if (sib->sib_flags & SMB_IDMAP_SID2ID) {
140111963SAfshin.Ardakani@Sun.COM 		/*
140211963SAfshin.Ardakani@Sun.COM 		 * SID prefixes are allocated only when mapping
140311963SAfshin.Ardakani@Sun.COM 		 * SIDs to UID/GID
140411963SAfshin.Ardakani@Sun.COM 		 */
140511963SAfshin.Ardakani@Sun.COM 		for (i = 0; i < sib->sib_nmap; i++) {
140611963SAfshin.Ardakani@Sun.COM 			domsid = sib->sib_maps[i].sim_domsid;
140711963SAfshin.Ardakani@Sun.COM 			if (domsid)
140811963SAfshin.Ardakani@Sun.COM 				smb_mem_free(domsid);
140911963SAfshin.Ardakani@Sun.COM 		}
141011963SAfshin.Ardakani@Sun.COM 	}
141111963SAfshin.Ardakani@Sun.COM 
141211963SAfshin.Ardakani@Sun.COM 	if (sib->sib_size && sib->sib_maps)
141311963SAfshin.Ardakani@Sun.COM 		kmem_free(sib->sib_maps, sib->sib_size);
141411963SAfshin.Ardakani@Sun.COM }
141511963SAfshin.Ardakani@Sun.COM 
141611963SAfshin.Ardakani@Sun.COM /*
141711963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getid
141811963SAfshin.Ardakani@Sun.COM  *
141911963SAfshin.Ardakani@Sun.COM  * Queue a request to map the given SID to a UID or GID.
142011963SAfshin.Ardakani@Sun.COM  *
142111963SAfshin.Ardakani@Sun.COM  * sim->sim_id should point to variable that's supposed to
142211963SAfshin.Ardakani@Sun.COM  * hold the returned UID/GID. This needs to be setup by caller
142311963SAfshin.Ardakani@Sun.COM  * of this function.
142411963SAfshin.Ardakani@Sun.COM  *
142511963SAfshin.Ardakani@Sun.COM  * If requested ID type is known, it's passed as 'idtype',
142611963SAfshin.Ardakani@Sun.COM  * if it's unknown it'll be returned in sim->sim_idtype.
142711963SAfshin.Ardakani@Sun.COM  */
142811963SAfshin.Ardakani@Sun.COM idmap_stat
smb_idmap_batch_getid(idmap_get_handle_t * idmaph,smb_idmap_t * sim,smb_sid_t * sid,int idtype)142911963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
143011963SAfshin.Ardakani@Sun.COM     smb_sid_t *sid, int idtype)
143111963SAfshin.Ardakani@Sun.COM {
143211963SAfshin.Ardakani@Sun.COM 	char strsid[SMB_SID_STRSZ];
143311963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat;
143411963SAfshin.Ardakani@Sun.COM 
143511963SAfshin.Ardakani@Sun.COM 	ASSERT(idmaph);
143611963SAfshin.Ardakani@Sun.COM 	ASSERT(sim);
143711963SAfshin.Ardakani@Sun.COM 	ASSERT(sid);
143811963SAfshin.Ardakani@Sun.COM 
143911963SAfshin.Ardakani@Sun.COM 	smb_sid_tostr(sid, strsid);
144011963SAfshin.Ardakani@Sun.COM 	if (smb_sid_splitstr(strsid, &sim->sim_rid) != 0)
144111963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_SID);
144211963SAfshin.Ardakani@Sun.COM 	sim->sim_domsid = smb_mem_strdup(strsid);
144311963SAfshin.Ardakani@Sun.COM 
144411963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
144511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
144611963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getuidbysid(idmaph, sim->sim_domsid,
144711963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_stat);
144811963SAfshin.Ardakani@Sun.COM 		break;
144911963SAfshin.Ardakani@Sun.COM 
145011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
145111963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getgidbysid(idmaph, sim->sim_domsid,
145211963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_stat);
145311963SAfshin.Ardakani@Sun.COM 		break;
145411963SAfshin.Ardakani@Sun.COM 
145511963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_UNKNOWN:
145611963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getpidbysid(idmaph, sim->sim_domsid,
145711963SAfshin.Ardakani@Sun.COM 		    sim->sim_rid, sim->sim_id, &sim->sim_idtype,
145811963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
145911963SAfshin.Ardakani@Sun.COM 		break;
146011963SAfshin.Ardakani@Sun.COM 
146111963SAfshin.Ardakani@Sun.COM 	default:
146211963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
146311963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
146411963SAfshin.Ardakani@Sun.COM 	}
146511963SAfshin.Ardakani@Sun.COM 
146611963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
146711963SAfshin.Ardakani@Sun.COM }
146811963SAfshin.Ardakani@Sun.COM 
146911963SAfshin.Ardakani@Sun.COM /*
147011963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getsid
147111963SAfshin.Ardakani@Sun.COM  *
147211963SAfshin.Ardakani@Sun.COM  * Queue a request to map the given UID/GID to a SID.
147311963SAfshin.Ardakani@Sun.COM  *
147411963SAfshin.Ardakani@Sun.COM  * sim->sim_domsid and sim->sim_rid will contain the mapping
147511963SAfshin.Ardakani@Sun.COM  * result upon successful process of the batched request.
147611963SAfshin.Ardakani@Sun.COM  */
147711963SAfshin.Ardakani@Sun.COM idmap_stat
smb_idmap_batch_getsid(idmap_get_handle_t * idmaph,smb_idmap_t * sim,uid_t id,int idtype)147811963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getsid(idmap_get_handle_t *idmaph, smb_idmap_t *sim,
147911963SAfshin.Ardakani@Sun.COM     uid_t id, int idtype)
148011963SAfshin.Ardakani@Sun.COM {
148111963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat;
148211963SAfshin.Ardakani@Sun.COM 
148311963SAfshin.Ardakani@Sun.COM 	switch (idtype) {
148411963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_USER:
148511963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getsidbyuid(idmaph, id,
148611963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim->sim_domsid, &sim->sim_rid,
148711963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
148811963SAfshin.Ardakani@Sun.COM 		break;
148911963SAfshin.Ardakani@Sun.COM 
149011963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUP:
149111963SAfshin.Ardakani@Sun.COM 		idm_stat = kidmap_batch_getsidbygid(idmaph, id,
149211963SAfshin.Ardakani@Sun.COM 		    (const char **)&sim->sim_domsid, &sim->sim_rid,
149311963SAfshin.Ardakani@Sun.COM 		    &sim->sim_stat);
149411963SAfshin.Ardakani@Sun.COM 		break;
149511963SAfshin.Ardakani@Sun.COM 
149611963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_OWNERAT:
149711963SAfshin.Ardakani@Sun.COM 		/* Current Owner S-1-5-32-766 */
149811963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
149911963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = SECURITY_CURRENT_OWNER_RID;
150011963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
150111963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
150211963SAfshin.Ardakani@Sun.COM 		break;
150311963SAfshin.Ardakani@Sun.COM 
150411963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_GROUPAT:
150511963SAfshin.Ardakani@Sun.COM 		/* Current Group S-1-5-32-767 */
150611963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_BUILTIN_DOMAIN_SIDSTR;
150711963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = SECURITY_CURRENT_GROUP_RID;
150811963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
150911963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
151011963SAfshin.Ardakani@Sun.COM 		break;
151111963SAfshin.Ardakani@Sun.COM 
151211963SAfshin.Ardakani@Sun.COM 	case SMB_IDMAP_EVERYONE:
151311963SAfshin.Ardakani@Sun.COM 		/* Everyone S-1-1-0 */
151411963SAfshin.Ardakani@Sun.COM 		sim->sim_domsid = NT_WORLD_AUTH_SIDSTR;
151511963SAfshin.Ardakani@Sun.COM 		sim->sim_rid = 0;
151611963SAfshin.Ardakani@Sun.COM 		sim->sim_stat = IDMAP_SUCCESS;
151711963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_SUCCESS;
151811963SAfshin.Ardakani@Sun.COM 		break;
151911963SAfshin.Ardakani@Sun.COM 
152011963SAfshin.Ardakani@Sun.COM 	default:
152111963SAfshin.Ardakani@Sun.COM 		ASSERT(0);
152211963SAfshin.Ardakani@Sun.COM 		return (IDMAP_ERR_ARG);
152311963SAfshin.Ardakani@Sun.COM 	}
152411963SAfshin.Ardakani@Sun.COM 
152511963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
152611963SAfshin.Ardakani@Sun.COM }
152711963SAfshin.Ardakani@Sun.COM 
152811963SAfshin.Ardakani@Sun.COM /*
152911963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_binsid
153011963SAfshin.Ardakani@Sun.COM  *
153111963SAfshin.Ardakani@Sun.COM  * Convert sidrids to binary sids
153211963SAfshin.Ardakani@Sun.COM  *
153311963SAfshin.Ardakani@Sun.COM  * Returns 0 if successful and non-zero upon failure.
153411963SAfshin.Ardakani@Sun.COM  */
153511963SAfshin.Ardakani@Sun.COM static int
smb_idmap_batch_binsid(smb_idmap_batch_t * sib)153611963SAfshin.Ardakani@Sun.COM smb_idmap_batch_binsid(smb_idmap_batch_t *sib)
153711963SAfshin.Ardakani@Sun.COM {
153811963SAfshin.Ardakani@Sun.COM 	smb_sid_t *sid;
153911963SAfshin.Ardakani@Sun.COM 	smb_idmap_t *sim;
154011963SAfshin.Ardakani@Sun.COM 	int i;
154111963SAfshin.Ardakani@Sun.COM 
154211963SAfshin.Ardakani@Sun.COM 	if (sib->sib_flags & SMB_IDMAP_SID2ID)
154311963SAfshin.Ardakani@Sun.COM 		/* This operation is not required */
154411963SAfshin.Ardakani@Sun.COM 		return (0);
154511963SAfshin.Ardakani@Sun.COM 
154611963SAfshin.Ardakani@Sun.COM 	sim = sib->sib_maps;
154711963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sib->sib_nmap; sim++, i++) {
154811963SAfshin.Ardakani@Sun.COM 		ASSERT(sim->sim_domsid);
154911963SAfshin.Ardakani@Sun.COM 		if (sim->sim_domsid == NULL)
155011963SAfshin.Ardakani@Sun.COM 			return (1);
155111963SAfshin.Ardakani@Sun.COM 
155211963SAfshin.Ardakani@Sun.COM 		if ((sid = smb_sid_fromstr(sim->sim_domsid)) == NULL)
155311963SAfshin.Ardakani@Sun.COM 			return (1);
155411963SAfshin.Ardakani@Sun.COM 
155511963SAfshin.Ardakani@Sun.COM 		sim->sim_sid = smb_sid_splice(sid, sim->sim_rid);
155611963SAfshin.Ardakani@Sun.COM 		smb_sid_free(sid);
155711963SAfshin.Ardakani@Sun.COM 	}
155811963SAfshin.Ardakani@Sun.COM 
155911963SAfshin.Ardakani@Sun.COM 	return (0);
156011963SAfshin.Ardakani@Sun.COM }
156111963SAfshin.Ardakani@Sun.COM 
156211963SAfshin.Ardakani@Sun.COM /*
156311963SAfshin.Ardakani@Sun.COM  * smb_idmap_batch_getmappings
156411963SAfshin.Ardakani@Sun.COM  *
156511963SAfshin.Ardakani@Sun.COM  * trigger ID mapping service to get the mappings for queued
156611963SAfshin.Ardakani@Sun.COM  * requests.
156711963SAfshin.Ardakani@Sun.COM  *
156811963SAfshin.Ardakani@Sun.COM  * Checks the result of all the queued requests.
156911963SAfshin.Ardakani@Sun.COM  * If this is a Solaris -> Windows mapping it generates
157011963SAfshin.Ardakani@Sun.COM  * binary SIDs from returned (domsid, rid) pairs.
157111963SAfshin.Ardakani@Sun.COM  */
157211963SAfshin.Ardakani@Sun.COM idmap_stat
smb_idmap_batch_getmappings(smb_idmap_batch_t * sib)157311963SAfshin.Ardakani@Sun.COM smb_idmap_batch_getmappings(smb_idmap_batch_t *sib)
157411963SAfshin.Ardakani@Sun.COM {
157511963SAfshin.Ardakani@Sun.COM 	idmap_stat idm_stat = IDMAP_SUCCESS;
157611963SAfshin.Ardakani@Sun.COM 	int i;
157711963SAfshin.Ardakani@Sun.COM 
157811963SAfshin.Ardakani@Sun.COM 	idm_stat = kidmap_get_mappings(sib->sib_idmaph);
157911963SAfshin.Ardakani@Sun.COM 	if (idm_stat != IDMAP_SUCCESS)
158011963SAfshin.Ardakani@Sun.COM 		return (idm_stat);
158111963SAfshin.Ardakani@Sun.COM 
158211963SAfshin.Ardakani@Sun.COM 	/*
158311963SAfshin.Ardakani@Sun.COM 	 * Check the status for all the queued requests
158411963SAfshin.Ardakani@Sun.COM 	 */
158511963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < sib->sib_nmap; i++) {
158611963SAfshin.Ardakani@Sun.COM 		if (sib->sib_maps[i].sim_stat != IDMAP_SUCCESS)
158711963SAfshin.Ardakani@Sun.COM 			return (sib->sib_maps[i].sim_stat);
158811963SAfshin.Ardakani@Sun.COM 	}
158911963SAfshin.Ardakani@Sun.COM 
159011963SAfshin.Ardakani@Sun.COM 	if (smb_idmap_batch_binsid(sib) != 0)
159111963SAfshin.Ardakani@Sun.COM 		idm_stat = IDMAP_ERR_OTHER;
159211963SAfshin.Ardakani@Sun.COM 
159311963SAfshin.Ardakani@Sun.COM 	return (idm_stat);
159411963SAfshin.Ardakani@Sun.COM }
159511963SAfshin.Ardakani@Sun.COM 
159611963SAfshin.Ardakani@Sun.COM uint64_t
smb_time_unix_to_nt(timestruc_t * unix_time)159711963SAfshin.Ardakani@Sun.COM smb_time_unix_to_nt(timestruc_t *unix_time)
159811963SAfshin.Ardakani@Sun.COM {
159911963SAfshin.Ardakani@Sun.COM 	uint64_t nt_time;
160011963SAfshin.Ardakani@Sun.COM 
160111963SAfshin.Ardakani@Sun.COM 	if ((unix_time->tv_sec == 0) && (unix_time->tv_nsec == 0))
160211963SAfshin.Ardakani@Sun.COM 		return (0);
160311963SAfshin.Ardakani@Sun.COM 
160411963SAfshin.Ardakani@Sun.COM 	nt_time = unix_time->tv_sec;
160511963SAfshin.Ardakani@Sun.COM 	nt_time *= 10000000;  /* seconds to 100ns */
160611963SAfshin.Ardakani@Sun.COM 	nt_time += unix_time->tv_nsec / 100;
160711963SAfshin.Ardakani@Sun.COM 	return (nt_time + NT_TIME_BIAS);
160811963SAfshin.Ardakani@Sun.COM }
160911963SAfshin.Ardakani@Sun.COM 
161011963SAfshin.Ardakani@Sun.COM void
smb_time_nt_to_unix(uint64_t nt_time,timestruc_t * unix_time)161111963SAfshin.Ardakani@Sun.COM smb_time_nt_to_unix(uint64_t nt_time, timestruc_t *unix_time)
161211963SAfshin.Ardakani@Sun.COM {
161311963SAfshin.Ardakani@Sun.COM 	uint32_t seconds;
161411963SAfshin.Ardakani@Sun.COM 
161511963SAfshin.Ardakani@Sun.COM 	ASSERT(unix_time);
161611963SAfshin.Ardakani@Sun.COM 
161711963SAfshin.Ardakani@Sun.COM 	if ((nt_time == 0) || (nt_time == -1)) {
161811963SAfshin.Ardakani@Sun.COM 		unix_time->tv_sec = 0;
161911963SAfshin.Ardakani@Sun.COM 		unix_time->tv_nsec = 0;
162011963SAfshin.Ardakani@Sun.COM 		return;
162111963SAfshin.Ardakani@Sun.COM 	}
162211963SAfshin.Ardakani@Sun.COM 
162311963SAfshin.Ardakani@Sun.COM 	nt_time -= NT_TIME_BIAS;
162411963SAfshin.Ardakani@Sun.COM 	seconds = nt_time / 10000000;
162511963SAfshin.Ardakani@Sun.COM 	unix_time->tv_sec = seconds;
162611963SAfshin.Ardakani@Sun.COM 	unix_time->tv_nsec = (nt_time  % 10000000) * 100;
162711963SAfshin.Ardakani@Sun.COM }
162811963SAfshin.Ardakani@Sun.COM 
162911963SAfshin.Ardakani@Sun.COM /*
163011963SAfshin.Ardakani@Sun.COM  * smb_time_gmt_to_local, smb_time_local_to_gmt
163111963SAfshin.Ardakani@Sun.COM  *
163211963SAfshin.Ardakani@Sun.COM  * Apply the gmt offset to convert between local time and gmt
163311963SAfshin.Ardakani@Sun.COM  */
163411963SAfshin.Ardakani@Sun.COM int32_t
smb_time_gmt_to_local(smb_request_t * sr,int32_t gmt)163511963SAfshin.Ardakani@Sun.COM smb_time_gmt_to_local(smb_request_t *sr, int32_t gmt)
163611963SAfshin.Ardakani@Sun.COM {
163711963SAfshin.Ardakani@Sun.COM 	if ((gmt == 0) || (gmt == -1))
163811963SAfshin.Ardakani@Sun.COM 		return (0);
163911963SAfshin.Ardakani@Sun.COM 
164011963SAfshin.Ardakani@Sun.COM 	return (gmt - sr->sr_gmtoff);
164111963SAfshin.Ardakani@Sun.COM }
164211963SAfshin.Ardakani@Sun.COM 
164311963SAfshin.Ardakani@Sun.COM int32_t
smb_time_local_to_gmt(smb_request_t * sr,int32_t local)164411963SAfshin.Ardakani@Sun.COM smb_time_local_to_gmt(smb_request_t *sr, int32_t local)
164511963SAfshin.Ardakani@Sun.COM {
164611963SAfshin.Ardakani@Sun.COM 	if ((local == 0) || (local == -1))
164711963SAfshin.Ardakani@Sun.COM 		return (0);
164811963SAfshin.Ardakani@Sun.COM 
164911963SAfshin.Ardakani@Sun.COM 	return (local + sr->sr_gmtoff);
165011963SAfshin.Ardakani@Sun.COM }
165111963SAfshin.Ardakani@Sun.COM 
165211963SAfshin.Ardakani@Sun.COM 
165311963SAfshin.Ardakani@Sun.COM /*
165411963SAfshin.Ardakani@Sun.COM  * smb_time_dos_to_unix
165511963SAfshin.Ardakani@Sun.COM  *
165611963SAfshin.Ardakani@Sun.COM  * Convert SMB_DATE & SMB_TIME values to a unix timestamp.
165711963SAfshin.Ardakani@Sun.COM  *
165811963SAfshin.Ardakani@Sun.COM  * A date/time field of 0 means that that server file system
165911963SAfshin.Ardakani@Sun.COM  * assigned value need not be changed. The behaviour when the
166011963SAfshin.Ardakani@Sun.COM  * date/time field is set to -1 is not documented but is
166111963SAfshin.Ardakani@Sun.COM  * generally treated like 0.
166211963SAfshin.Ardakani@Sun.COM  * If date or time is 0 or -1 the unix time is returned as 0
166311963SAfshin.Ardakani@Sun.COM  * so that the caller can identify and handle this special case.
166411963SAfshin.Ardakani@Sun.COM  */
166511963SAfshin.Ardakani@Sun.COM int32_t
smb_time_dos_to_unix(int16_t date,int16_t time)166611963SAfshin.Ardakani@Sun.COM smb_time_dos_to_unix(int16_t date, int16_t time)
166711963SAfshin.Ardakani@Sun.COM {
166811963SAfshin.Ardakani@Sun.COM 	struct tm	atm;
166911963SAfshin.Ardakani@Sun.COM 
167011963SAfshin.Ardakani@Sun.COM 	if (((date == 0) || (time == 0)) ||
167111963SAfshin.Ardakani@Sun.COM 	    ((date == -1) || (time == -1))) {
167211963SAfshin.Ardakani@Sun.COM 		return (0);
167311963SAfshin.Ardakani@Sun.COM 	}
167411963SAfshin.Ardakani@Sun.COM 
167511963SAfshin.Ardakani@Sun.COM 	atm.tm_year = ((date >>  9) & 0x3F) + 80;
167611963SAfshin.Ardakani@Sun.COM 	atm.tm_mon  = ((date >>  5) & 0x0F) - 1;
167711963SAfshin.Ardakani@Sun.COM 	atm.tm_mday = ((date >>  0) & 0x1F);
167811963SAfshin.Ardakani@Sun.COM 	atm.tm_hour = ((time >> 11) & 0x1F);
167911963SAfshin.Ardakani@Sun.COM 	atm.tm_min  = ((time >>  5) & 0x3F);
168011963SAfshin.Ardakani@Sun.COM 	atm.tm_sec  = ((time >>  0) & 0x1F) << 1;
168111963SAfshin.Ardakani@Sun.COM 
168211963SAfshin.Ardakani@Sun.COM 	return (smb_timegm(&atm));
168311963SAfshin.Ardakani@Sun.COM }
168411963SAfshin.Ardakani@Sun.COM 
168511963SAfshin.Ardakani@Sun.COM void
smb_time_unix_to_dos(int32_t ux_time,int16_t * date_p,int16_t * time_p)168611963SAfshin.Ardakani@Sun.COM smb_time_unix_to_dos(int32_t ux_time, int16_t *date_p, int16_t *time_p)
168711963SAfshin.Ardakani@Sun.COM {
168811963SAfshin.Ardakani@Sun.COM 	struct tm	atm;
168911963SAfshin.Ardakani@Sun.COM 	int		i;
169011963SAfshin.Ardakani@Sun.COM 	time_t		tmp_time;
169111963SAfshin.Ardakani@Sun.COM 
169211963SAfshin.Ardakani@Sun.COM 	if (ux_time == 0) {
169311963SAfshin.Ardakani@Sun.COM 		*date_p = 0;
169411963SAfshin.Ardakani@Sun.COM 		*time_p = 0;
169511963SAfshin.Ardakani@Sun.COM 		return;
169611963SAfshin.Ardakani@Sun.COM 	}
169711963SAfshin.Ardakani@Sun.COM 
169811963SAfshin.Ardakani@Sun.COM 	tmp_time = (time_t)ux_time;
169911963SAfshin.Ardakani@Sun.COM 	(void) smb_gmtime_r(&tmp_time, &atm);
170011963SAfshin.Ardakani@Sun.COM 
170111963SAfshin.Ardakani@Sun.COM 	if (date_p) {
170211963SAfshin.Ardakani@Sun.COM 		i = 0;
170311963SAfshin.Ardakani@Sun.COM 		i += atm.tm_year - 80;
170411963SAfshin.Ardakani@Sun.COM 		i <<= 4;
170511963SAfshin.Ardakani@Sun.COM 		i += atm.tm_mon + 1;
170611963SAfshin.Ardakani@Sun.COM 		i <<= 5;
170711963SAfshin.Ardakani@Sun.COM 		i += atm.tm_mday;
170811963SAfshin.Ardakani@Sun.COM 
170911963SAfshin.Ardakani@Sun.COM 		*date_p = (short)i;
171011963SAfshin.Ardakani@Sun.COM 	}
171111963SAfshin.Ardakani@Sun.COM 	if (time_p) {
171211963SAfshin.Ardakani@Sun.COM 		i = 0;
171311963SAfshin.Ardakani@Sun.COM 		i += atm.tm_hour;
171411963SAfshin.Ardakani@Sun.COM 		i <<= 6;
171511963SAfshin.Ardakani@Sun.COM 		i += atm.tm_min;
171611963SAfshin.Ardakani@Sun.COM 		i <<= 5;
171711963SAfshin.Ardakani@Sun.COM 		i += atm.tm_sec >> 1;
171811963SAfshin.Ardakani@Sun.COM 
171911963SAfshin.Ardakani@Sun.COM 		*time_p = (short)i;
172011963SAfshin.Ardakani@Sun.COM 	}
172111963SAfshin.Ardakani@Sun.COM }
172211963SAfshin.Ardakani@Sun.COM 
172311963SAfshin.Ardakani@Sun.COM 
172411963SAfshin.Ardakani@Sun.COM /*
172511963SAfshin.Ardakani@Sun.COM  * smb_gmtime_r
172611963SAfshin.Ardakani@Sun.COM  *
172711963SAfshin.Ardakani@Sun.COM  * Thread-safe version of smb_gmtime. Returns a null pointer if either
172811963SAfshin.Ardakani@Sun.COM  * input parameter is a null pointer. Otherwise returns a pointer
172911963SAfshin.Ardakani@Sun.COM  * to result.
173011963SAfshin.Ardakani@Sun.COM  *
173111963SAfshin.Ardakani@Sun.COM  * Day of the week calculation: the Epoch was a thursday.
173211963SAfshin.Ardakani@Sun.COM  *
173311963SAfshin.Ardakani@Sun.COM  * There are no timezone corrections so tm_isdst and tm_gmtoff are
173411963SAfshin.Ardakani@Sun.COM  * always zero, and the zone is always WET.
173511963SAfshin.Ardakani@Sun.COM  */
173611963SAfshin.Ardakani@Sun.COM struct tm *
smb_gmtime_r(time_t * clock,struct tm * result)173711963SAfshin.Ardakani@Sun.COM smb_gmtime_r(time_t *clock, struct tm *result)
173811963SAfshin.Ardakani@Sun.COM {
173911963SAfshin.Ardakani@Sun.COM 	time_t tsec;
174011963SAfshin.Ardakani@Sun.COM 	int year;
174111963SAfshin.Ardakani@Sun.COM 	int month;
174211963SAfshin.Ardakani@Sun.COM 	int sec_per_month;
174311963SAfshin.Ardakani@Sun.COM 
174411963SAfshin.Ardakani@Sun.COM 	if (clock == 0 || result == 0)
174511963SAfshin.Ardakani@Sun.COM 		return (0);
174611963SAfshin.Ardakani@Sun.COM 
174711963SAfshin.Ardakani@Sun.COM 	bzero(result, sizeof (struct tm));
174811963SAfshin.Ardakani@Sun.COM 	tsec = *clock;
174911963SAfshin.Ardakani@Sun.COM 	tsec -= tzh_leapcnt;
175011963SAfshin.Ardakani@Sun.COM 
175111963SAfshin.Ardakani@Sun.COM 	result->tm_wday = tsec / SECSPERDAY;
175211963SAfshin.Ardakani@Sun.COM 	result->tm_wday = (result->tm_wday + TM_THURSDAY) % DAYSPERWEEK;
175311963SAfshin.Ardakani@Sun.COM 
175411963SAfshin.Ardakani@Sun.COM 	year = EPOCH_YEAR;
175511963SAfshin.Ardakani@Sun.COM 	while (tsec >= (isleap(year) ? (SECSPERDAY * DAYSPERLYEAR) :
175611963SAfshin.Ardakani@Sun.COM 	    (SECSPERDAY * DAYSPERNYEAR))) {
175711963SAfshin.Ardakani@Sun.COM 		if (isleap(year))
175811963SAfshin.Ardakani@Sun.COM 			tsec -= SECSPERDAY * DAYSPERLYEAR;
175911963SAfshin.Ardakani@Sun.COM 		else
176011963SAfshin.Ardakani@Sun.COM 			tsec -= SECSPERDAY * DAYSPERNYEAR;
176111963SAfshin.Ardakani@Sun.COM 
176211963SAfshin.Ardakani@Sun.COM 		++year;
176311963SAfshin.Ardakani@Sun.COM 	}
176411963SAfshin.Ardakani@Sun.COM 
176511963SAfshin.Ardakani@Sun.COM 	result->tm_year = year - TM_YEAR_BASE;
176611963SAfshin.Ardakani@Sun.COM 	result->tm_yday = tsec / SECSPERDAY;
176711963SAfshin.Ardakani@Sun.COM 
176811963SAfshin.Ardakani@Sun.COM 	for (month = TM_JANUARY; month <= TM_DECEMBER; ++month) {
176911963SAfshin.Ardakani@Sun.COM 		sec_per_month = days_in_month[month] * SECSPERDAY;
177011963SAfshin.Ardakani@Sun.COM 
177111963SAfshin.Ardakani@Sun.COM 		if (month == TM_FEBRUARY && isleap(year))
177211963SAfshin.Ardakani@Sun.COM 			sec_per_month += SECSPERDAY;
177311963SAfshin.Ardakani@Sun.COM 
177411963SAfshin.Ardakani@Sun.COM 		if (tsec < sec_per_month)
177511963SAfshin.Ardakani@Sun.COM 			break;
177611963SAfshin.Ardakani@Sun.COM 
177711963SAfshin.Ardakani@Sun.COM 		tsec -= sec_per_month;
177811963SAfshin.Ardakani@Sun.COM 	}
177911963SAfshin.Ardakani@Sun.COM 
178011963SAfshin.Ardakani@Sun.COM 	result->tm_mon = month;
178111963SAfshin.Ardakani@Sun.COM 	result->tm_mday = (tsec / SECSPERDAY) + 1;
178211963SAfshin.Ardakani@Sun.COM 	tsec %= SECSPERDAY;
178311963SAfshin.Ardakani@Sun.COM 	result->tm_sec = tsec % 60;
178411963SAfshin.Ardakani@Sun.COM 	tsec /= 60;
178511963SAfshin.Ardakani@Sun.COM 	result->tm_min = tsec % 60;
178611963SAfshin.Ardakani@Sun.COM 	tsec /= 60;
178711963SAfshin.Ardakani@Sun.COM 	result->tm_hour = (int)tsec;
178811963SAfshin.Ardakani@Sun.COM 
178911963SAfshin.Ardakani@Sun.COM 	return (result);
179011963SAfshin.Ardakani@Sun.COM }
179111963SAfshin.Ardakani@Sun.COM 
179211963SAfshin.Ardakani@Sun.COM 
179311963SAfshin.Ardakani@Sun.COM /*
179411963SAfshin.Ardakani@Sun.COM  * smb_timegm
179511963SAfshin.Ardakani@Sun.COM  *
179611963SAfshin.Ardakani@Sun.COM  * Converts the broken-down time in tm to a time value, i.e. the number
179711963SAfshin.Ardakani@Sun.COM  * of seconds since the Epoch (00:00:00 UTC, January 1, 1970). This is
179811963SAfshin.Ardakani@Sun.COM  * not a POSIX or ANSI function. Per the man page, the input values of
179911963SAfshin.Ardakani@Sun.COM  * tm_wday and tm_yday are ignored and, as the input data is assumed to
180011963SAfshin.Ardakani@Sun.COM  * represent GMT, we force tm_isdst and tm_gmtoff to 0.
180111963SAfshin.Ardakani@Sun.COM  *
180211963SAfshin.Ardakani@Sun.COM  * Before returning the clock time, we use smb_gmtime_r to set up tm_wday
180311963SAfshin.Ardakani@Sun.COM  * and tm_yday, and bring the other fields within normal range. I don't
180411963SAfshin.Ardakani@Sun.COM  * think this is really how it should be done but it's convenient for
180511963SAfshin.Ardakani@Sun.COM  * now.
180611963SAfshin.Ardakani@Sun.COM  */
180711963SAfshin.Ardakani@Sun.COM time_t
smb_timegm(struct tm * tm)180811963SAfshin.Ardakani@Sun.COM smb_timegm(struct tm *tm)
180911963SAfshin.Ardakani@Sun.COM {
181011963SAfshin.Ardakani@Sun.COM 	time_t tsec;
181111963SAfshin.Ardakani@Sun.COM 	int dd;
181211963SAfshin.Ardakani@Sun.COM 	int mm;
181311963SAfshin.Ardakani@Sun.COM 	int yy;
181411963SAfshin.Ardakani@Sun.COM 	int year;
181511963SAfshin.Ardakani@Sun.COM 
181611963SAfshin.Ardakani@Sun.COM 	if (tm == 0)
181711963SAfshin.Ardakani@Sun.COM 		return (-1);
181811963SAfshin.Ardakani@Sun.COM 
181911963SAfshin.Ardakani@Sun.COM 	year = tm->tm_year + TM_YEAR_BASE;
182011963SAfshin.Ardakani@Sun.COM 	tsec = tzh_leapcnt;
182111963SAfshin.Ardakani@Sun.COM 
182211963SAfshin.Ardakani@Sun.COM 	for (yy = EPOCH_YEAR; yy < year; ++yy) {
182311963SAfshin.Ardakani@Sun.COM 		if (isleap(yy))
182411963SAfshin.Ardakani@Sun.COM 			tsec += SECSPERDAY * DAYSPERLYEAR;
182511963SAfshin.Ardakani@Sun.COM 		else
182611963SAfshin.Ardakani@Sun.COM 			tsec += SECSPERDAY * DAYSPERNYEAR;
182711963SAfshin.Ardakani@Sun.COM 	}
182811963SAfshin.Ardakani@Sun.COM 
182911963SAfshin.Ardakani@Sun.COM 	for (mm = TM_JANUARY; mm < tm->tm_mon; ++mm) {
183011963SAfshin.Ardakani@Sun.COM 		dd = days_in_month[mm] * SECSPERDAY;
183111963SAfshin.Ardakani@Sun.COM 
183211963SAfshin.Ardakani@Sun.COM 		if (mm == TM_FEBRUARY && isleap(year))
183311963SAfshin.Ardakani@Sun.COM 			dd += SECSPERDAY;
183411963SAfshin.Ardakani@Sun.COM 
183511963SAfshin.Ardakani@Sun.COM 		tsec += dd;
183611963SAfshin.Ardakani@Sun.COM 	}
183711963SAfshin.Ardakani@Sun.COM 
183811963SAfshin.Ardakani@Sun.COM 	tsec += (tm->tm_mday - 1) * SECSPERDAY;
183911963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_sec;
184011963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_min * SECSPERMIN;
184111963SAfshin.Ardakani@Sun.COM 	tsec += tm->tm_hour * SECSPERHOUR;
184211963SAfshin.Ardakani@Sun.COM 
184311963SAfshin.Ardakani@Sun.COM 	tm->tm_isdst = 0;
184411963SAfshin.Ardakani@Sun.COM 	(void) smb_gmtime_r(&tsec, tm);
184511963SAfshin.Ardakani@Sun.COM 	return (tsec);
184611963SAfshin.Ardakani@Sun.COM }
184711963SAfshin.Ardakani@Sun.COM 
184811963SAfshin.Ardakani@Sun.COM /*
184911963SAfshin.Ardakani@Sun.COM  * smb_pad_align
185011963SAfshin.Ardakani@Sun.COM  *
185111963SAfshin.Ardakani@Sun.COM  * Returns the number of bytes required to pad an offset to the
185211963SAfshin.Ardakani@Sun.COM  * specified alignment.
185311963SAfshin.Ardakani@Sun.COM  */
185411963SAfshin.Ardakani@Sun.COM uint32_t
smb_pad_align(uint32_t offset,uint32_t align)185511963SAfshin.Ardakani@Sun.COM smb_pad_align(uint32_t offset, uint32_t align)
185611963SAfshin.Ardakani@Sun.COM {
185711963SAfshin.Ardakani@Sun.COM 	uint32_t pad = offset % align;
185811963SAfshin.Ardakani@Sun.COM 
185911963SAfshin.Ardakani@Sun.COM 	if (pad != 0)
186011963SAfshin.Ardakani@Sun.COM 		pad = align - pad;
186111963SAfshin.Ardakani@Sun.COM 
186211963SAfshin.Ardakani@Sun.COM 	return (pad);
186311963SAfshin.Ardakani@Sun.COM }
186411963SAfshin.Ardakani@Sun.COM 
186511963SAfshin.Ardakani@Sun.COM /*
186611963SAfshin.Ardakani@Sun.COM  * smb_panic
186711963SAfshin.Ardakani@Sun.COM  *
186811963SAfshin.Ardakani@Sun.COM  * Logs the file name, function name and line number passed in and panics the
186911963SAfshin.Ardakani@Sun.COM  * system.
187011963SAfshin.Ardakani@Sun.COM  */
187111963SAfshin.Ardakani@Sun.COM void
smb_panic(char * file,const char * func,int line)187211963SAfshin.Ardakani@Sun.COM smb_panic(char *file, const char *func, int line)
187311963SAfshin.Ardakani@Sun.COM {
187411963SAfshin.Ardakani@Sun.COM 	cmn_err(CE_PANIC, "%s:%s:%d\n", file, func, line);
187511963SAfshin.Ardakani@Sun.COM }
187612508Samw@Sun.COM 
187712508Samw@Sun.COM /*
187812508Samw@Sun.COM  * Creates an AVL tree and initializes the given smb_avl_t
187912508Samw@Sun.COM  * structure using the passed args
188012508Samw@Sun.COM  */
188112508Samw@Sun.COM void
smb_avl_create(smb_avl_t * avl,size_t size,size_t offset,smb_avl_nops_t * ops)188212508Samw@Sun.COM smb_avl_create(smb_avl_t *avl, size_t size, size_t offset, smb_avl_nops_t *ops)
188312508Samw@Sun.COM {
188412508Samw@Sun.COM 	ASSERT(avl);
188512508Samw@Sun.COM 	ASSERT(ops);
188612508Samw@Sun.COM 
188712508Samw@Sun.COM 	rw_init(&avl->avl_lock, NULL, RW_DEFAULT, NULL);
188812508Samw@Sun.COM 	mutex_init(&avl->avl_mutex, NULL, MUTEX_DEFAULT, NULL);
188912508Samw@Sun.COM 
189012508Samw@Sun.COM 	avl->avl_nops = ops;
189112508Samw@Sun.COM 	avl->avl_state = SMB_AVL_STATE_READY;
189212508Samw@Sun.COM 	avl->avl_refcnt = 0;
189312508Samw@Sun.COM 	(void) random_get_pseudo_bytes((uint8_t *)&avl->avl_sequence,
189412508Samw@Sun.COM 	    sizeof (uint32_t));
189512508Samw@Sun.COM 
189612508Samw@Sun.COM 	avl_create(&avl->avl_tree, ops->avln_cmp, size, offset);
189712508Samw@Sun.COM }
189812508Samw@Sun.COM 
189912508Samw@Sun.COM /*
190012508Samw@Sun.COM  * Destroys the specified AVL tree.
190112508Samw@Sun.COM  * It waits for all the in-flight operations to finish
190212508Samw@Sun.COM  * before destroying the AVL.
190312508Samw@Sun.COM  */
190412508Samw@Sun.COM void
smb_avl_destroy(smb_avl_t * avl)190512508Samw@Sun.COM smb_avl_destroy(smb_avl_t *avl)
190612508Samw@Sun.COM {
190712508Samw@Sun.COM 	void *cookie = NULL;
190812508Samw@Sun.COM 	void *node;
190912508Samw@Sun.COM 
191012508Samw@Sun.COM 	ASSERT(avl);
191112508Samw@Sun.COM 
191212508Samw@Sun.COM 	mutex_enter(&avl->avl_mutex);
191312508Samw@Sun.COM 	if (avl->avl_state != SMB_AVL_STATE_READY) {
191412508Samw@Sun.COM 		mutex_exit(&avl->avl_mutex);
191512508Samw@Sun.COM 		return;
191612508Samw@Sun.COM 	}
191712508Samw@Sun.COM 
191812508Samw@Sun.COM 	avl->avl_state = SMB_AVL_STATE_DESTROYING;
191912508Samw@Sun.COM 
192012508Samw@Sun.COM 	while (avl->avl_refcnt > 0)
192112508Samw@Sun.COM 		(void) cv_wait(&avl->avl_cv, &avl->avl_mutex);
192212508Samw@Sun.COM 	mutex_exit(&avl->avl_mutex);
192312508Samw@Sun.COM 
192412508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_WRITER);
192512508Samw@Sun.COM 	while ((node = avl_destroy_nodes(&avl->avl_tree, &cookie)) != NULL)
192612508Samw@Sun.COM 		avl->avl_nops->avln_destroy(node);
192712508Samw@Sun.COM 
192812508Samw@Sun.COM 	avl_destroy(&avl->avl_tree);
192912508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
193012508Samw@Sun.COM 
193112508Samw@Sun.COM 	rw_destroy(&avl->avl_lock);
193212508Samw@Sun.COM 
193312508Samw@Sun.COM 	mutex_destroy(&avl->avl_mutex);
193412508Samw@Sun.COM 	bzero(avl, sizeof (smb_avl_t));
193512508Samw@Sun.COM }
193612508Samw@Sun.COM 
193712508Samw@Sun.COM /*
193812508Samw@Sun.COM  * Adds the given item to the AVL if it's
193912508Samw@Sun.COM  * not already there.
194012508Samw@Sun.COM  *
194112508Samw@Sun.COM  * Returns:
194212508Samw@Sun.COM  *
194312508Samw@Sun.COM  * 	ENOTACTIVE	AVL is not in READY state
194412508Samw@Sun.COM  * 	EEXIST		The item is already in AVL
194512508Samw@Sun.COM  */
194612508Samw@Sun.COM int
smb_avl_add(smb_avl_t * avl,void * item)194712508Samw@Sun.COM smb_avl_add(smb_avl_t *avl, void *item)
194812508Samw@Sun.COM {
194912508Samw@Sun.COM 	avl_index_t where;
195012508Samw@Sun.COM 
195112508Samw@Sun.COM 	ASSERT(avl);
195212508Samw@Sun.COM 	ASSERT(item);
195312508Samw@Sun.COM 
195412508Samw@Sun.COM 	if (!smb_avl_hold(avl))
195512508Samw@Sun.COM 		return (ENOTACTIVE);
195612508Samw@Sun.COM 
195712508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_WRITER);
195812508Samw@Sun.COM 	if (avl_find(&avl->avl_tree, item, &where) != NULL) {
195912508Samw@Sun.COM 		rw_exit(&avl->avl_lock);
196012508Samw@Sun.COM 		smb_avl_rele(avl);
196112508Samw@Sun.COM 		return (EEXIST);
196212508Samw@Sun.COM 	}
196312508Samw@Sun.COM 
196412508Samw@Sun.COM 	avl_insert(&avl->avl_tree, item, where);
196512508Samw@Sun.COM 	avl->avl_sequence++;
196612508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
196712508Samw@Sun.COM 
196812508Samw@Sun.COM 	smb_avl_rele(avl);
196912508Samw@Sun.COM 	return (0);
197012508Samw@Sun.COM }
197112508Samw@Sun.COM 
197212508Samw@Sun.COM /*
197312508Samw@Sun.COM  * Removes the given item from the AVL.
197412508Samw@Sun.COM  * If no reference is left on the item
197512508Samw@Sun.COM  * it will also be destroyed by calling the
197612508Samw@Sun.COM  * registered destroy operation.
197712508Samw@Sun.COM  */
197812508Samw@Sun.COM void
smb_avl_remove(smb_avl_t * avl,void * item)197912508Samw@Sun.COM smb_avl_remove(smb_avl_t *avl, void *item)
198012508Samw@Sun.COM {
198112508Samw@Sun.COM 	avl_index_t where;
198212508Samw@Sun.COM 	void *rm_item;
198312508Samw@Sun.COM 
198412508Samw@Sun.COM 	ASSERT(avl);
198512508Samw@Sun.COM 	ASSERT(item);
198612508Samw@Sun.COM 
198712508Samw@Sun.COM 	if (!smb_avl_hold(avl))
198812508Samw@Sun.COM 		return;
198912508Samw@Sun.COM 
199012508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_WRITER);
199112508Samw@Sun.COM 	if ((rm_item = avl_find(&avl->avl_tree, item, &where)) == NULL) {
199212508Samw@Sun.COM 		rw_exit(&avl->avl_lock);
199312508Samw@Sun.COM 		smb_avl_rele(avl);
199412508Samw@Sun.COM 		return;
199512508Samw@Sun.COM 	}
199612508Samw@Sun.COM 
199712508Samw@Sun.COM 	avl_remove(&avl->avl_tree, rm_item);
199812508Samw@Sun.COM 	if (avl->avl_nops->avln_rele(rm_item))
199912508Samw@Sun.COM 		avl->avl_nops->avln_destroy(rm_item);
200012508Samw@Sun.COM 	avl->avl_sequence++;
200112508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
200212508Samw@Sun.COM 
200312508Samw@Sun.COM 	smb_avl_rele(avl);
200412508Samw@Sun.COM }
200512508Samw@Sun.COM 
200612508Samw@Sun.COM /*
200712508Samw@Sun.COM  * Looks up the AVL for the given item.
200812508Samw@Sun.COM  * If the item is found a hold on the object
200912508Samw@Sun.COM  * is taken before the pointer to it is
201012508Samw@Sun.COM  * returned to the caller. The caller MUST
201112508Samw@Sun.COM  * always call smb_avl_release() after it's done
201212508Samw@Sun.COM  * using the returned object to release the hold
201312508Samw@Sun.COM  * taken on the object.
201412508Samw@Sun.COM  */
201512508Samw@Sun.COM void *
smb_avl_lookup(smb_avl_t * avl,void * item)201612508Samw@Sun.COM smb_avl_lookup(smb_avl_t *avl, void *item)
201712508Samw@Sun.COM {
201812508Samw@Sun.COM 	void *node = NULL;
201912508Samw@Sun.COM 
202012508Samw@Sun.COM 	ASSERT(avl);
202112508Samw@Sun.COM 	ASSERT(item);
202212508Samw@Sun.COM 
202312508Samw@Sun.COM 	if (!smb_avl_hold(avl))
202412508Samw@Sun.COM 		return (NULL);
202512508Samw@Sun.COM 
202612508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_READER);
202712508Samw@Sun.COM 	node = avl_find(&avl->avl_tree, item, NULL);
202812508Samw@Sun.COM 	if (node != NULL)
202912508Samw@Sun.COM 		avl->avl_nops->avln_hold(node);
203012508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
203112508Samw@Sun.COM 
203212508Samw@Sun.COM 	if (node == NULL)
203312508Samw@Sun.COM 		smb_avl_rele(avl);
203412508Samw@Sun.COM 
203512508Samw@Sun.COM 	return (node);
203612508Samw@Sun.COM }
203712508Samw@Sun.COM 
203812508Samw@Sun.COM /*
203912508Samw@Sun.COM  * The hold on the given object is released.
204012508Samw@Sun.COM  * This function MUST always be called after
204112508Samw@Sun.COM  * smb_avl_lookup() and smb_avl_iterate() for
204212508Samw@Sun.COM  * the returned object.
204312508Samw@Sun.COM  *
204412508Samw@Sun.COM  * If AVL is in DESTROYING state, the destroying
204512508Samw@Sun.COM  * thread will be notified.
204612508Samw@Sun.COM  */
204712508Samw@Sun.COM void
smb_avl_release(smb_avl_t * avl,void * item)204812508Samw@Sun.COM smb_avl_release(smb_avl_t *avl, void *item)
204912508Samw@Sun.COM {
205012508Samw@Sun.COM 	ASSERT(avl);
205112508Samw@Sun.COM 	ASSERT(item);
205212508Samw@Sun.COM 
205312508Samw@Sun.COM 	if (avl->avl_nops->avln_rele(item))
205412508Samw@Sun.COM 		avl->avl_nops->avln_destroy(item);
205512508Samw@Sun.COM 
205612508Samw@Sun.COM 	smb_avl_rele(avl);
205712508Samw@Sun.COM }
205812508Samw@Sun.COM 
205912508Samw@Sun.COM /*
206012508Samw@Sun.COM  * Initializes the given cursor for the AVL.
206112508Samw@Sun.COM  * The cursor will be used to iterate through the AVL
206212508Samw@Sun.COM  */
206312508Samw@Sun.COM void
smb_avl_iterinit(smb_avl_t * avl,smb_avl_cursor_t * cursor)206412508Samw@Sun.COM smb_avl_iterinit(smb_avl_t *avl, smb_avl_cursor_t *cursor)
206512508Samw@Sun.COM {
206612508Samw@Sun.COM 	ASSERT(avl);
206712508Samw@Sun.COM 	ASSERT(cursor);
206812508Samw@Sun.COM 
206912508Samw@Sun.COM 	cursor->avlc_next = NULL;
207012508Samw@Sun.COM 	cursor->avlc_sequence = avl->avl_sequence;
207112508Samw@Sun.COM }
207212508Samw@Sun.COM 
207312508Samw@Sun.COM /*
207412508Samw@Sun.COM  * Iterates through the AVL using the given cursor.
207512508Samw@Sun.COM  * It always starts at the beginning and then returns
207612508Samw@Sun.COM  * a pointer to the next object on each subsequent call.
207712508Samw@Sun.COM  *
207812508Samw@Sun.COM  * If a new object is added to or removed from the AVL
207912508Samw@Sun.COM  * between two calls to this function, the iteration
208012508Samw@Sun.COM  * will terminate prematurely.
208112508Samw@Sun.COM  *
208212508Samw@Sun.COM  * The caller MUST always call smb_avl_release() after it's
208312508Samw@Sun.COM  * done using the returned object to release the hold taken
208412508Samw@Sun.COM  * on the object.
208512508Samw@Sun.COM  */
208612508Samw@Sun.COM void *
smb_avl_iterate(smb_avl_t * avl,smb_avl_cursor_t * cursor)208712508Samw@Sun.COM smb_avl_iterate(smb_avl_t *avl, smb_avl_cursor_t *cursor)
208812508Samw@Sun.COM {
208912508Samw@Sun.COM 	void *node;
209012508Samw@Sun.COM 
209112508Samw@Sun.COM 	ASSERT(avl);
209212508Samw@Sun.COM 	ASSERT(cursor);
209312508Samw@Sun.COM 
209412508Samw@Sun.COM 	if (!smb_avl_hold(avl))
209512508Samw@Sun.COM 		return (NULL);
209612508Samw@Sun.COM 
209712508Samw@Sun.COM 	rw_enter(&avl->avl_lock, RW_READER);
209812508Samw@Sun.COM 	if (cursor->avlc_sequence != avl->avl_sequence) {
209912508Samw@Sun.COM 		rw_exit(&avl->avl_lock);
210012508Samw@Sun.COM 		smb_avl_rele(avl);
210112508Samw@Sun.COM 		return (NULL);
210212508Samw@Sun.COM 	}
210312508Samw@Sun.COM 
210412508Samw@Sun.COM 	if (cursor->avlc_next == NULL)
210512508Samw@Sun.COM 		node = avl_first(&avl->avl_tree);
210612508Samw@Sun.COM 	else
210712508Samw@Sun.COM 		node = AVL_NEXT(&avl->avl_tree, cursor->avlc_next);
210812508Samw@Sun.COM 
210912508Samw@Sun.COM 	if (node != NULL)
211012508Samw@Sun.COM 		avl->avl_nops->avln_hold(node);
211112508Samw@Sun.COM 
211212508Samw@Sun.COM 	cursor->avlc_next = node;
211312508Samw@Sun.COM 	rw_exit(&avl->avl_lock);
211412508Samw@Sun.COM 
211512508Samw@Sun.COM 	if (node == NULL)
211612508Samw@Sun.COM 		smb_avl_rele(avl);
211712508Samw@Sun.COM 
211812508Samw@Sun.COM 	return (node);
211912508Samw@Sun.COM }
212012508Samw@Sun.COM 
212112508Samw@Sun.COM /*
212212508Samw@Sun.COM  * Increments the AVL reference count in order to
212312508Samw@Sun.COM  * prevent the avl from being destroyed while it's
212412508Samw@Sun.COM  * being accessed.
212512508Samw@Sun.COM  */
212612508Samw@Sun.COM static boolean_t
smb_avl_hold(smb_avl_t * avl)212712508Samw@Sun.COM smb_avl_hold(smb_avl_t *avl)
212812508Samw@Sun.COM {
212912508Samw@Sun.COM 	mutex_enter(&avl->avl_mutex);
213012508Samw@Sun.COM 	if (avl->avl_state != SMB_AVL_STATE_READY) {
213112508Samw@Sun.COM 		mutex_exit(&avl->avl_mutex);
213212508Samw@Sun.COM 		return (B_FALSE);
213312508Samw@Sun.COM 	}
213412508Samw@Sun.COM 	avl->avl_refcnt++;
213512508Samw@Sun.COM 	mutex_exit(&avl->avl_mutex);
213612508Samw@Sun.COM 
213712508Samw@Sun.COM 	return (B_TRUE);
213812508Samw@Sun.COM }
213912508Samw@Sun.COM 
214012508Samw@Sun.COM /*
214112508Samw@Sun.COM  * Decrements the AVL reference count to release the
214212508Samw@Sun.COM  * hold. If another thread is trying to destroy the
214312508Samw@Sun.COM  * AVL and is waiting for the reference count to become
214412508Samw@Sun.COM  * 0, it is signaled to wake up.
214512508Samw@Sun.COM  */
214612508Samw@Sun.COM static void
smb_avl_rele(smb_avl_t * avl)214712508Samw@Sun.COM smb_avl_rele(smb_avl_t *avl)
214812508Samw@Sun.COM {
214912508Samw@Sun.COM 	mutex_enter(&avl->avl_mutex);
215012508Samw@Sun.COM 	ASSERT(avl->avl_refcnt > 0);
215112508Samw@Sun.COM 	avl->avl_refcnt--;
215212508Samw@Sun.COM 	if (avl->avl_state == SMB_AVL_STATE_DESTROYING)
215312508Samw@Sun.COM 		cv_broadcast(&avl->avl_cv);
215412508Samw@Sun.COM 	mutex_exit(&avl->avl_mutex);
215512508Samw@Sun.COM }
215612508Samw@Sun.COM 
215712508Samw@Sun.COM /*
215812508Samw@Sun.COM  * smb_latency_init
215912508Samw@Sun.COM  */
216012508Samw@Sun.COM void
smb_latency_init(smb_latency_t * lat)216112508Samw@Sun.COM smb_latency_init(smb_latency_t *lat)
216212508Samw@Sun.COM {
216312508Samw@Sun.COM 	bzero(lat, sizeof (*lat));
216412508Samw@Sun.COM 	mutex_init(&lat->ly_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7));
216512508Samw@Sun.COM }
216612508Samw@Sun.COM 
216712508Samw@Sun.COM /*
216812508Samw@Sun.COM  * smb_latency_destroy
216912508Samw@Sun.COM  */
217012508Samw@Sun.COM void
smb_latency_destroy(smb_latency_t * lat)217112508Samw@Sun.COM smb_latency_destroy(smb_latency_t *lat)
217212508Samw@Sun.COM {
217312508Samw@Sun.COM 	mutex_destroy(&lat->ly_mutex);
217412508Samw@Sun.COM }
217512508Samw@Sun.COM 
217612508Samw@Sun.COM /*
217712508Samw@Sun.COM  * smb_latency_add_sample
217812508Samw@Sun.COM  *
217912508Samw@Sun.COM  * Uses the new sample to calculate the new mean and standard deviation. The
218012508Samw@Sun.COM  * sample must be a scaled value.
218112508Samw@Sun.COM  */
218212508Samw@Sun.COM void
smb_latency_add_sample(smb_latency_t * lat,hrtime_t sample)218312508Samw@Sun.COM smb_latency_add_sample(smb_latency_t *lat, hrtime_t sample)
218412508Samw@Sun.COM {
218512508Samw@Sun.COM 	hrtime_t	a_mean;
218612508Samw@Sun.COM 	hrtime_t	d_mean;
218712508Samw@Sun.COM 
218812508Samw@Sun.COM 	mutex_enter(&lat->ly_mutex);
218912508Samw@Sun.COM 	lat->ly_a_nreq++;
219012508Samw@Sun.COM 	lat->ly_a_sum += sample;
219112508Samw@Sun.COM 	if (lat->ly_a_nreq != 0) {
219212508Samw@Sun.COM 		a_mean = lat->ly_a_sum / lat->ly_a_nreq;
219312508Samw@Sun.COM 		lat->ly_a_stddev =
219412508Samw@Sun.COM 		    (sample - a_mean) * (sample - lat->ly_a_mean);
219512508Samw@Sun.COM 		lat->ly_a_mean = a_mean;
219612508Samw@Sun.COM 	}
219712508Samw@Sun.COM 	lat->ly_d_nreq++;
219812508Samw@Sun.COM 	lat->ly_d_sum += sample;
219912508Samw@Sun.COM 	if (lat->ly_d_nreq != 0) {
220012508Samw@Sun.COM 		d_mean = lat->ly_d_sum / lat->ly_d_nreq;
220112508Samw@Sun.COM 		lat->ly_d_stddev =
220212508Samw@Sun.COM 		    (sample - d_mean) * (sample - lat->ly_d_mean);
220312508Samw@Sun.COM 		lat->ly_d_mean = d_mean;
220412508Samw@Sun.COM 	}
220512508Samw@Sun.COM 	mutex_exit(&lat->ly_mutex);
220612508Samw@Sun.COM }
220712508Samw@Sun.COM 
220812508Samw@Sun.COM /*
220912508Samw@Sun.COM  * smb_srqueue_init
221012508Samw@Sun.COM  */
221112508Samw@Sun.COM void
smb_srqueue_init(smb_srqueue_t * srq)221212508Samw@Sun.COM smb_srqueue_init(smb_srqueue_t *srq)
221312508Samw@Sun.COM {
221412508Samw@Sun.COM 	bzero(srq, sizeof (*srq));
221512508Samw@Sun.COM 	mutex_init(&srq->srq_mutex, NULL, MUTEX_SPIN, (void *)ipltospl(SPL7));
221612508Samw@Sun.COM 	srq->srq_wlastupdate = srq->srq_rlastupdate = gethrtime_unscaled();
221712508Samw@Sun.COM }
221812508Samw@Sun.COM 
221912508Samw@Sun.COM /*
222012508Samw@Sun.COM  * smb_srqueue_destroy
222112508Samw@Sun.COM  */
222212508Samw@Sun.COM void
smb_srqueue_destroy(smb_srqueue_t * srq)222312508Samw@Sun.COM smb_srqueue_destroy(smb_srqueue_t *srq)
222412508Samw@Sun.COM {
222512508Samw@Sun.COM 	mutex_destroy(&srq->srq_mutex);
222612508Samw@Sun.COM }
222712508Samw@Sun.COM 
222812508Samw@Sun.COM /*
222912508Samw@Sun.COM  * smb_srqueue_waitq_enter
223012508Samw@Sun.COM  */
223112508Samw@Sun.COM void
smb_srqueue_waitq_enter(smb_srqueue_t * srq)223212508Samw@Sun.COM smb_srqueue_waitq_enter(smb_srqueue_t *srq)
223312508Samw@Sun.COM {
223412508Samw@Sun.COM 	hrtime_t	new;
223512508Samw@Sun.COM 	hrtime_t	delta;
223612508Samw@Sun.COM 	uint32_t	wcnt;
223712508Samw@Sun.COM 
223812508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
223912508Samw@Sun.COM 	new = gethrtime_unscaled();
224012508Samw@Sun.COM 	delta = new - srq->srq_wlastupdate;
224112508Samw@Sun.COM 	srq->srq_wlastupdate = new;
224212508Samw@Sun.COM 	wcnt = srq->srq_wcnt++;
224312508Samw@Sun.COM 	if (wcnt != 0) {
224412508Samw@Sun.COM 		srq->srq_wlentime += delta * wcnt;
224512508Samw@Sun.COM 		srq->srq_wtime += delta;
224612508Samw@Sun.COM 	}
224712508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
224812508Samw@Sun.COM }
224912508Samw@Sun.COM 
225012508Samw@Sun.COM /*
225112508Samw@Sun.COM  * smb_srqueue_runq_exit
225212508Samw@Sun.COM  */
225312508Samw@Sun.COM void
smb_srqueue_runq_exit(smb_srqueue_t * srq)225412508Samw@Sun.COM smb_srqueue_runq_exit(smb_srqueue_t *srq)
225512508Samw@Sun.COM {
225612508Samw@Sun.COM 	hrtime_t	new;
225712508Samw@Sun.COM 	hrtime_t	delta;
225812508Samw@Sun.COM 	uint32_t	rcnt;
225912508Samw@Sun.COM 
226012508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
226112508Samw@Sun.COM 	new = gethrtime_unscaled();
226212508Samw@Sun.COM 	delta = new - srq->srq_rlastupdate;
226312508Samw@Sun.COM 	srq->srq_rlastupdate = new;
226412508Samw@Sun.COM 	rcnt = srq->srq_rcnt--;
226512508Samw@Sun.COM 	ASSERT(rcnt > 0);
226612508Samw@Sun.COM 	srq->srq_rlentime += delta * rcnt;
226712508Samw@Sun.COM 	srq->srq_rtime += delta;
226812508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
226912508Samw@Sun.COM }
227012508Samw@Sun.COM 
227112508Samw@Sun.COM /*
227212508Samw@Sun.COM  * smb_srqueue_waitq_to_runq
227312508Samw@Sun.COM  */
227412508Samw@Sun.COM void
smb_srqueue_waitq_to_runq(smb_srqueue_t * srq)227512508Samw@Sun.COM smb_srqueue_waitq_to_runq(smb_srqueue_t *srq)
227612508Samw@Sun.COM {
227712508Samw@Sun.COM 	hrtime_t	new;
227812508Samw@Sun.COM 	hrtime_t	delta;
227912508Samw@Sun.COM 	uint32_t	wcnt;
228012508Samw@Sun.COM 	uint32_t	rcnt;
228112508Samw@Sun.COM 
228212508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
228312508Samw@Sun.COM 	new = gethrtime_unscaled();
228412508Samw@Sun.COM 	delta = new - srq->srq_wlastupdate;
228512508Samw@Sun.COM 	srq->srq_wlastupdate = new;
228612508Samw@Sun.COM 	wcnt = srq->srq_wcnt--;
228712508Samw@Sun.COM 	ASSERT(wcnt > 0);
228812508Samw@Sun.COM 	srq->srq_wlentime += delta * wcnt;
228912508Samw@Sun.COM 	srq->srq_wtime += delta;
229012508Samw@Sun.COM 	delta = new - srq->srq_rlastupdate;
229112508Samw@Sun.COM 	srq->srq_rlastupdate = new;
229212508Samw@Sun.COM 	rcnt = srq->srq_rcnt++;
229312508Samw@Sun.COM 	if (rcnt != 0) {
229412508Samw@Sun.COM 		srq->srq_rlentime += delta * rcnt;
229512508Samw@Sun.COM 		srq->srq_rtime += delta;
229612508Samw@Sun.COM 	}
229712508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
229812508Samw@Sun.COM }
229912508Samw@Sun.COM 
230012508Samw@Sun.COM /*
230112508Samw@Sun.COM  * smb_srqueue_update
230212508Samw@Sun.COM  *
230312508Samw@Sun.COM  * Takes a snapshot of the smb_sr_stat_t structure passed in.
230412508Samw@Sun.COM  */
230512508Samw@Sun.COM void
smb_srqueue_update(smb_srqueue_t * srq,smb_kstat_utilization_t * kd)230612508Samw@Sun.COM smb_srqueue_update(smb_srqueue_t *srq, smb_kstat_utilization_t *kd)
230712508Samw@Sun.COM {
230812508Samw@Sun.COM 	hrtime_t	delta;
230912508Samw@Sun.COM 	hrtime_t	snaptime;
231012508Samw@Sun.COM 
231112508Samw@Sun.COM 	mutex_enter(&srq->srq_mutex);
231212508Samw@Sun.COM 	snaptime = gethrtime_unscaled();
231312508Samw@Sun.COM 	delta = snaptime - srq->srq_wlastupdate;
231412508Samw@Sun.COM 	srq->srq_wlastupdate = snaptime;
231512508Samw@Sun.COM 	if (srq->srq_wcnt != 0) {
231612508Samw@Sun.COM 		srq->srq_wlentime += delta * srq->srq_wcnt;
231712508Samw@Sun.COM 		srq->srq_wtime += delta;
231812508Samw@Sun.COM 	}
231912508Samw@Sun.COM 	delta = snaptime - srq->srq_rlastupdate;
232012508Samw@Sun.COM 	srq->srq_rlastupdate = snaptime;
232112508Samw@Sun.COM 	if (srq->srq_rcnt != 0) {
232212508Samw@Sun.COM 		srq->srq_rlentime += delta * srq->srq_rcnt;
232312508Samw@Sun.COM 		srq->srq_rtime += delta;
232412508Samw@Sun.COM 	}
232512508Samw@Sun.COM 	kd->ku_rlentime = srq->srq_rlentime;
232612508Samw@Sun.COM 	kd->ku_rtime = srq->srq_rtime;
232712508Samw@Sun.COM 	kd->ku_wlentime = srq->srq_wlentime;
232812508Samw@Sun.COM 	kd->ku_wtime = srq->srq_wtime;
232912508Samw@Sun.COM 	mutex_exit(&srq->srq_mutex);
233012508Samw@Sun.COM 	scalehrtime(&kd->ku_rlentime);
233112508Samw@Sun.COM 	scalehrtime(&kd->ku_rtime);
233212508Samw@Sun.COM 	scalehrtime(&kd->ku_wlentime);
233312508Samw@Sun.COM 	scalehrtime(&kd->ku_wtime);
233412508Samw@Sun.COM }
233512890SJoyce.McIntosh@Sun.COM 
233612890SJoyce.McIntosh@Sun.COM void
smb_threshold_init(smb_cmd_threshold_t * ct,char * cmd,int threshold,int timeout)233712890SJoyce.McIntosh@Sun.COM smb_threshold_init(smb_cmd_threshold_t *ct, char *cmd, int threshold,
233812890SJoyce.McIntosh@Sun.COM     int timeout)
233912890SJoyce.McIntosh@Sun.COM {
234012890SJoyce.McIntosh@Sun.COM 	bzero(ct, sizeof (smb_cmd_threshold_t));
234112890SJoyce.McIntosh@Sun.COM 	mutex_init(&ct->ct_mutex, NULL, MUTEX_DEFAULT, NULL);
234212890SJoyce.McIntosh@Sun.COM 	ct->ct_cmd = cmd;
234312890SJoyce.McIntosh@Sun.COM 	ct->ct_threshold = threshold;
234412890SJoyce.McIntosh@Sun.COM 	ct->ct_event = smb_event_create(timeout);
234512890SJoyce.McIntosh@Sun.COM 	ct->ct_event_id = smb_event_txid(ct->ct_event);
234612890SJoyce.McIntosh@Sun.COM 
234712890SJoyce.McIntosh@Sun.COM 	if (smb_threshold_debug) {
234812890SJoyce.McIntosh@Sun.COM 		cmn_err(CE_NOTE, "smb_threshold_init[%s]: threshold (%d), "
234912890SJoyce.McIntosh@Sun.COM 		    "timeout (%d)", cmd, threshold, timeout);
235012890SJoyce.McIntosh@Sun.COM 	}
235112890SJoyce.McIntosh@Sun.COM }
235212890SJoyce.McIntosh@Sun.COM 
235312890SJoyce.McIntosh@Sun.COM /*
235412890SJoyce.McIntosh@Sun.COM  * This function must be called prior to SMB_SERVER_STATE_STOPPING state
235512890SJoyce.McIntosh@Sun.COM  * so that ct_event can be successfully removed from the event list.
235612890SJoyce.McIntosh@Sun.COM  * It should not be called when the server mutex is held or when the
235712890SJoyce.McIntosh@Sun.COM  * server is removed from the server list.
235812890SJoyce.McIntosh@Sun.COM  */
235912890SJoyce.McIntosh@Sun.COM void
smb_threshold_fini(smb_cmd_threshold_t * ct)236012890SJoyce.McIntosh@Sun.COM smb_threshold_fini(smb_cmd_threshold_t *ct)
236112890SJoyce.McIntosh@Sun.COM {
236212890SJoyce.McIntosh@Sun.COM 	smb_event_destroy(ct->ct_event);
236312890SJoyce.McIntosh@Sun.COM 	mutex_destroy(&ct->ct_mutex);
236412890SJoyce.McIntosh@Sun.COM 	bzero(ct, sizeof (smb_cmd_threshold_t));
236512890SJoyce.McIntosh@Sun.COM }
236612890SJoyce.McIntosh@Sun.COM 
236712890SJoyce.McIntosh@Sun.COM /*
236812890SJoyce.McIntosh@Sun.COM  * This threshold mechanism can be used to limit the number of simultaneous
236912890SJoyce.McIntosh@Sun.COM  * requests, which serves to limit the stress that can be applied to the
237012890SJoyce.McIntosh@Sun.COM  * service and also allows the service to respond to requests before the
237112890SJoyce.McIntosh@Sun.COM  * client times out and reports that the server is not responding,
237212890SJoyce.McIntosh@Sun.COM  *
237312890SJoyce.McIntosh@Sun.COM  * If the number of requests exceeds the threshold, new requests will be
237412890SJoyce.McIntosh@Sun.COM  * stalled until the number drops back to the threshold.  Stalled requests
237512890SJoyce.McIntosh@Sun.COM  * will be notified as appropriate, in which case 0 will be returned.
237612890SJoyce.McIntosh@Sun.COM  * If the timeout expires before the request is notified, a non-zero errno
237712890SJoyce.McIntosh@Sun.COM  * value will be returned.
237812890SJoyce.McIntosh@Sun.COM  *
237912890SJoyce.McIntosh@Sun.COM  * To avoid a flood of messages, the message rate is throttled as well.
238012890SJoyce.McIntosh@Sun.COM  */
238112890SJoyce.McIntosh@Sun.COM int
smb_threshold_enter(smb_cmd_threshold_t * ct)238212890SJoyce.McIntosh@Sun.COM smb_threshold_enter(smb_cmd_threshold_t *ct)
238312890SJoyce.McIntosh@Sun.COM {
238412890SJoyce.McIntosh@Sun.COM 	int	rc;
238512890SJoyce.McIntosh@Sun.COM 
238612890SJoyce.McIntosh@Sun.COM 	mutex_enter(&ct->ct_mutex);
238712890SJoyce.McIntosh@Sun.COM 	if (ct->ct_active_cnt >= ct->ct_threshold && ct->ct_event != NULL) {
238812890SJoyce.McIntosh@Sun.COM 		atomic_inc_32(&ct->ct_blocked_cnt);
238912890SJoyce.McIntosh@Sun.COM 
239012890SJoyce.McIntosh@Sun.COM 		if (smb_threshold_debug) {
239112890SJoyce.McIntosh@Sun.COM 			cmn_err(CE_NOTE, "smb_threshold_enter[%s]: blocked "
239212890SJoyce.McIntosh@Sun.COM 			    "(blocked ops: %u, inflight ops: %u)",
239312890SJoyce.McIntosh@Sun.COM 			    ct->ct_cmd, ct->ct_blocked_cnt, ct->ct_active_cnt);
239412890SJoyce.McIntosh@Sun.COM 		}
239512890SJoyce.McIntosh@Sun.COM 
239612890SJoyce.McIntosh@Sun.COM 		mutex_exit(&ct->ct_mutex);
239712890SJoyce.McIntosh@Sun.COM 
239812890SJoyce.McIntosh@Sun.COM 		if ((rc = smb_event_wait(ct->ct_event)) != 0) {
239912890SJoyce.McIntosh@Sun.COM 			if (rc == ECANCELED)
240012890SJoyce.McIntosh@Sun.COM 				return (rc);
240112890SJoyce.McIntosh@Sun.COM 
240212890SJoyce.McIntosh@Sun.COM 			mutex_enter(&ct->ct_mutex);
240312890SJoyce.McIntosh@Sun.COM 			if (ct->ct_active_cnt >= ct->ct_threshold) {
240412890SJoyce.McIntosh@Sun.COM 
240512890SJoyce.McIntosh@Sun.COM 				if ((ct->ct_error_cnt %
240612890SJoyce.McIntosh@Sun.COM 				    SMB_THRESHOLD_REPORT_THROTTLE) == 0) {
240712890SJoyce.McIntosh@Sun.COM 					cmn_err(CE_NOTE, "%s: server busy: "
240812890SJoyce.McIntosh@Sun.COM 					    "threshold %d exceeded)",
240912890SJoyce.McIntosh@Sun.COM 					    ct->ct_cmd, ct->ct_threshold);
241012890SJoyce.McIntosh@Sun.COM 				}
241112890SJoyce.McIntosh@Sun.COM 
241212890SJoyce.McIntosh@Sun.COM 				atomic_inc_32(&ct->ct_error_cnt);
241312890SJoyce.McIntosh@Sun.COM 				mutex_exit(&ct->ct_mutex);
241412890SJoyce.McIntosh@Sun.COM 				return (rc);
241512890SJoyce.McIntosh@Sun.COM 			}
241612890SJoyce.McIntosh@Sun.COM 
241712890SJoyce.McIntosh@Sun.COM 			mutex_exit(&ct->ct_mutex);
241812890SJoyce.McIntosh@Sun.COM 
241912890SJoyce.McIntosh@Sun.COM 		}
242012890SJoyce.McIntosh@Sun.COM 
242112890SJoyce.McIntosh@Sun.COM 		mutex_enter(&ct->ct_mutex);
242212890SJoyce.McIntosh@Sun.COM 		atomic_dec_32(&ct->ct_blocked_cnt);
242312890SJoyce.McIntosh@Sun.COM 		if (smb_threshold_debug) {
242412890SJoyce.McIntosh@Sun.COM 			cmn_err(CE_NOTE, "smb_threshold_enter[%s]: resumed "
242512890SJoyce.McIntosh@Sun.COM 			    "(blocked ops: %u, inflight ops: %u)", ct->ct_cmd,
242612890SJoyce.McIntosh@Sun.COM 			    ct->ct_blocked_cnt, ct->ct_active_cnt);
242712890SJoyce.McIntosh@Sun.COM 		}
242812890SJoyce.McIntosh@Sun.COM 	}
242912890SJoyce.McIntosh@Sun.COM 
243012890SJoyce.McIntosh@Sun.COM 	atomic_inc_32(&ct->ct_active_cnt);
243112890SJoyce.McIntosh@Sun.COM 	mutex_exit(&ct->ct_mutex);
243212890SJoyce.McIntosh@Sun.COM 	return (0);
243312890SJoyce.McIntosh@Sun.COM }
243412890SJoyce.McIntosh@Sun.COM 
243512890SJoyce.McIntosh@Sun.COM void
smb_threshold_exit(smb_cmd_threshold_t * ct,smb_server_t * sv)243612890SJoyce.McIntosh@Sun.COM smb_threshold_exit(smb_cmd_threshold_t *ct, smb_server_t *sv)
243712890SJoyce.McIntosh@Sun.COM {
243812890SJoyce.McIntosh@Sun.COM 	mutex_enter(&ct->ct_mutex);
243912890SJoyce.McIntosh@Sun.COM 	atomic_dec_32(&ct->ct_active_cnt);
244012890SJoyce.McIntosh@Sun.COM 	mutex_exit(&ct->ct_mutex);
244112890SJoyce.McIntosh@Sun.COM 	smb_event_notify(sv, ct->ct_event_id);
244212890SJoyce.McIntosh@Sun.COM }
2443