xref: /onnv-gate/usr/src/uts/common/io/sad_conf.c (revision 6220:3ed7e9c98b12)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53042Sedp  * Common Development and Distribution License (the "License").
63042Sedp  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*6220Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * Config dependent data structures for the Streams Administrative Driver
300Sstevel@tonic-gate  * (or "Ballad of the SAD Cafe").
310Sstevel@tonic-gate  */
320Sstevel@tonic-gate #include <sys/types.h>
330Sstevel@tonic-gate #include <sys/conf.h>
340Sstevel@tonic-gate #include <sys/stream.h>
353042Sedp #include <sys/strsubr.h>
360Sstevel@tonic-gate #include <sys/sad.h>
370Sstevel@tonic-gate #include <sys/kmem.h>
383042Sedp #include <sys/sysmacros.h>
390Sstevel@tonic-gate 
403042Sedp /*
413042Sedp  * Currently we store all the sad data in a hash table keyed by major
423042Sedp  * number.  This is far from ideal.  It means that if a single device
433042Sedp  * starts using lots of SAP_ONE entries all its entries will hash
443042Sedp  * to the same bucket and we'll get very long chains for that bucket.
453042Sedp  *
463042Sedp  * Unfortunately, it's not possible to hash by a different key or to easily
473042Sedp  * break up our one hash into seperate hashs.  The reason is because
483042Sedp  * the hash contains mixed data types.  Ie, it has three different
493042Sedp  * types of autopush nodes in it:  SAP_ALL, SAP_RANGE, SAP_ONE.  Not
503042Sedp  * only does the hash table contain nodes of different types, but we
513042Sedp  * have to be able to search the table with a node of one type that
523042Sedp  * might match another node with a different type.  (ie, we might search
533042Sedp  * for a SAP_ONE node with a value that matches a SAP_ALL node in the
543042Sedp  * hash, or vice versa.)
553042Sedp  *
563042Sedp  * An ideal solution would probably be an AVL tree sorted by major
573042Sedp  * numbers.  Each node in the AVL tree would have the following optional
583042Sedp  * data associated with it:
593042Sedp  *	- a single SAP_ALL autopush node
603042Sedp  *	- an or avl tree or hash table of SAP_RANGE and SAP_ONE autopush
613042Sedp  *	  nodes indexed by minor numbers.  perhaps two separate tables,
623042Sedp  *	  one for each type of autopush nodes.
633042Sedp  *
643042Sedp  * Note that regardless of how the data is stored there can't be any overlap
653042Sedp  * stored between autopush nodes.  For example, if there is a SAP_ALL node
663042Sedp  * for a given major number then there can't be any SAP_RANGE or SAP_ONE
673042Sedp  * nodes for that same major number.
683042Sedp  */
693042Sedp 
703042Sedp /*
713042Sedp  * Private Internal Interfaces
723042Sedp  */
733042Sedp /*ARGSUSED*/
743042Sedp static uint_t
sad_hash_alg(void * hash_data,mod_hash_key_t key)753042Sedp sad_hash_alg(void *hash_data, mod_hash_key_t key)
763042Sedp {
773042Sedp 	struct apcommon *apc = (struct apcommon *)key;
783042Sedp 
793042Sedp 	ASSERT(sad_apc_verify(apc) == 0);
803042Sedp 	return (apc->apc_major);
813042Sedp }
820Sstevel@tonic-gate 
833042Sedp /*
843042Sedp  * Compare hash keys based off of major, minor, lastminor, and type.
853042Sedp  */
863042Sedp static int
sad_hash_keycmp(mod_hash_key_t key1,mod_hash_key_t key2)873042Sedp sad_hash_keycmp(mod_hash_key_t key1, mod_hash_key_t key2)
883042Sedp {
893042Sedp 	struct apcommon *apc1 = (struct apcommon *)key1;
903042Sedp 	struct apcommon *apc2 = (struct apcommon *)key2;
913042Sedp 
923042Sedp 	ASSERT(sad_apc_verify(apc1) == 0);
933042Sedp 	ASSERT(sad_apc_verify(apc2) == 0);
943042Sedp 
953042Sedp 	/* Filter out cases where the major number doesn't match. */
963042Sedp 	if (apc1->apc_major != apc2->apc_major)
973042Sedp 		return (1);
983042Sedp 
993042Sedp 	/* If either type is SAP_ALL then we're done. */
1003042Sedp 	if ((apc1->apc_cmd == SAP_ALL) || (apc2->apc_cmd == SAP_ALL))
1013042Sedp 		return (0);
1023042Sedp 
1033042Sedp 	/* Deal with the case where both types are SAP_ONE. */
1043042Sedp 	if ((apc1->apc_cmd == SAP_ONE) && (apc2->apc_cmd == SAP_ONE)) {
1053042Sedp 		/* Check if the minor numbers match. */
1063042Sedp 		return (apc1->apc_minor != apc2->apc_minor);
1073042Sedp 	}
1083042Sedp 
1093042Sedp 	/* Deal with the case where both types are SAP_RANGE. */
1103042Sedp 	if ((apc1->apc_cmd == SAP_RANGE) && (apc2->apc_cmd == SAP_RANGE)) {
1113042Sedp 		/* Check for overlapping ranges. */
1123042Sedp 		if ((apc1->apc_lastminor < apc2->apc_minor) ||
1133042Sedp 		    (apc1->apc_minor > apc2->apc_lastminor))
1143042Sedp 			return (1);
1153042Sedp 		return (0);
1163042Sedp 	}
1173042Sedp 
1183042Sedp 	/*
1193042Sedp 	 * We know that one type is SAP_ONE and the other is SAP_RANGE.
1203042Sedp 	 * So now let's do range matching.
1213042Sedp 	 */
1223042Sedp 	if (apc1->apc_cmd == SAP_RANGE) {
1233042Sedp 		ASSERT(apc2->apc_cmd == SAP_ONE);
1243042Sedp 		if ((apc1->apc_lastminor < apc2->apc_minor) ||
1253042Sedp 		    (apc1->apc_minor > apc2->apc_minor))
1263042Sedp 			return (1);
1273042Sedp 	} else {
1283042Sedp 		ASSERT(apc1->apc_cmd == SAP_ONE);
1293042Sedp 		ASSERT(apc2->apc_cmd == SAP_RANGE);
1303042Sedp 		if ((apc1->apc_minor < apc2->apc_minor) ||
1313042Sedp 		    (apc1->apc_minor > apc2->apc_lastminor))
1323042Sedp 			return (1);
1333042Sedp 	}
1343042Sedp 	return (0);
1353042Sedp }
1360Sstevel@tonic-gate 
137*6220Syz147064 /*ARGSUSED*/
138*6220Syz147064 static uint_t
sad_hash_free_value(mod_hash_key_t key,mod_hash_val_t * val,void * arg)139*6220Syz147064 sad_hash_free_value(mod_hash_key_t key, mod_hash_val_t *val, void *arg)
140*6220Syz147064 {
141*6220Syz147064 	struct autopush *ap = (struct autopush *)val;
142*6220Syz147064 
143*6220Syz147064 	ASSERT(ap->ap_cnt > 0);
144*6220Syz147064 	if (--(ap->ap_cnt) == 0)
145*6220Syz147064 		kmem_free(ap, sizeof (struct autopush));
146*6220Syz147064 
147*6220Syz147064 	return (MH_WALK_CONTINUE);
148*6220Syz147064 }
149*6220Syz147064 
1500Sstevel@tonic-gate /*
1513042Sedp  * External Interfaces
1520Sstevel@tonic-gate  */
1533042Sedp int
sad_apc_verify(struct apcommon * apc)1543042Sedp sad_apc_verify(struct apcommon *apc)
1553042Sedp {
1563042Sedp 	/* sanity check the number of modules to push */
1573042Sedp 	if ((apc->apc_npush == 0) || (apc->apc_npush > MAXAPUSH) ||
1583042Sedp 	    (apc->apc_npush > nstrpush))
1593042Sedp 		return (EINVAL);
1603042Sedp 
1613042Sedp 	/* Check for NODEV major vaule */
1623042Sedp 	if (apc->apc_major == -1)
1633042Sedp 		return (EINVAL);
1643042Sedp 
1653042Sedp 	switch (apc->apc_cmd) {
1663042Sedp 	case SAP_ALL:
1673042Sedp 	case SAP_ONE:
1683215Sedp 		/*
1693215Sedp 		 * Really, we'd like to be strict here and make sure that
1703215Sedp 		 * apc_lastminor is 0 (since setting apc_lastminor for
1713215Sedp 		 * SAP_ALL and SAP_ONE commands doesn't make any sense),
1723215Sedp 		 * but we can't since historically apc_lastminor has been
1733215Sedp 		 * silently ignored for non-SAP_RANGE commands.
1743215Sedp 		 */
1753042Sedp 		break;
1763042Sedp 	case SAP_RANGE:
1773042Sedp 		if (apc->apc_lastminor <= apc->apc_minor)
1783042Sedp 			return (ERANGE);
1793042Sedp 		break;
1803042Sedp 	default:
1813042Sedp 		return (EINVAL);
1823042Sedp 	}
1833042Sedp 	return (0);
1843042Sedp }
1853042Sedp 
1863042Sedp int
sad_ap_verify(struct autopush * ap)1873042Sedp sad_ap_verify(struct autopush *ap)
1883042Sedp {
1893042Sedp 	int ret, i;
1903042Sedp 
1913042Sedp 	if ((ret = sad_apc_verify(&ap->ap_common)) != 0)
1923042Sedp 		return (ret);
1933042Sedp 
1943042Sedp 	/*
1953042Sedp 	 * Validate that the specified list of modules exist.  Note that
1963042Sedp 	 * ap_npush has already been sanity checked by sad_apc_verify().
1973042Sedp 	 */
1983042Sedp 	for (i = 0; i < ap->ap_npush; i++) {
1993042Sedp 		ap->ap_list[i][FMNAMESZ] = '\0';
2003042Sedp 		if (fmodsw_find(ap->ap_list[i], FMODSW_LOAD) == NULL)
2013042Sedp 			return (EINVAL);
2023042Sedp 	}
2033042Sedp 	return (0);
2043042Sedp }
2053042Sedp 
2063042Sedp struct autopush *
sad_ap_alloc(void)2073042Sedp sad_ap_alloc(void)
2083042Sedp {
2093042Sedp 	struct autopush *ap_new;
2103042Sedp 
2113042Sedp 	ap_new = kmem_zalloc(sizeof (struct autopush), KM_SLEEP);
2123042Sedp 	ap_new->ap_cnt = 1;
2133042Sedp 	return (ap_new);
2143042Sedp }
2153042Sedp 
2163042Sedp void
sad_ap_rele(struct autopush * ap,str_stack_t * ss)2173448Sdh155122 sad_ap_rele(struct autopush *ap, str_stack_t *ss)
2183042Sedp {
2193448Sdh155122 	mutex_enter(&ss->ss_sad_lock);
2203042Sedp 	ASSERT(ap->ap_cnt > 0);
2213042Sedp 	if (--(ap->ap_cnt) == 0) {
2223448Sdh155122 		mutex_exit(&ss->ss_sad_lock);
2233042Sedp 		kmem_free(ap, sizeof (struct autopush));
2243042Sedp 	} else {
2253448Sdh155122 		mutex_exit(&ss->ss_sad_lock);
2263042Sedp 	}
2273042Sedp }
2283042Sedp 
2293042Sedp void
sad_ap_insert(struct autopush * ap,str_stack_t * ss)2303448Sdh155122 sad_ap_insert(struct autopush *ap, str_stack_t *ss)
2313042Sedp {
2323448Sdh155122 	ASSERT(MUTEX_HELD(&ss->ss_sad_lock));
2333042Sedp 	ASSERT(sad_apc_verify(&ap->ap_common) == 0);
2343448Sdh155122 	ASSERT(sad_ap_find(&ap->ap_common, ss) == NULL);
2353448Sdh155122 	(void) mod_hash_insert(ss->ss_sad_hash, &ap->ap_common, ap);
2363042Sedp }
2373042Sedp 
2383042Sedp void
sad_ap_remove(struct autopush * ap,str_stack_t * ss)2393448Sdh155122 sad_ap_remove(struct autopush *ap, str_stack_t *ss)
2403042Sedp {
2413042Sedp 	struct autopush	*ap_removed = NULL;
2423042Sedp 
2433448Sdh155122 	ASSERT(MUTEX_HELD(&ss->ss_sad_lock));
2443448Sdh155122 	(void) mod_hash_remove(ss->ss_sad_hash, &ap->ap_common,
2453042Sedp 	    (mod_hash_val_t *)&ap_removed);
2463042Sedp 	ASSERT(ap == ap_removed);
2473042Sedp }
2483042Sedp 
2493042Sedp struct autopush *
sad_ap_find(struct apcommon * apc,str_stack_t * ss)2503448Sdh155122 sad_ap_find(struct apcommon *apc, str_stack_t *ss)
2513042Sedp {
2523042Sedp 	struct autopush	*ap_result = NULL;
2533042Sedp 
2543448Sdh155122 	ASSERT(MUTEX_HELD(&ss->ss_sad_lock));
2553042Sedp 	ASSERT(sad_apc_verify(apc) == 0);
2563042Sedp 
2573448Sdh155122 	(void) mod_hash_find(ss->ss_sad_hash, apc,
2583448Sdh155122 	    (mod_hash_val_t *)&ap_result);
2593042Sedp 	if (ap_result != NULL)
2603042Sedp 		ap_result->ap_cnt++;
2613042Sedp 	return (ap_result);
2623042Sedp }
2633042Sedp 
2643042Sedp struct autopush *
sad_ap_find_by_dev(dev_t dev,str_stack_t * ss)2653448Sdh155122 sad_ap_find_by_dev(dev_t dev, str_stack_t *ss)
2663042Sedp {
2673042Sedp 	struct apcommon	apc;
2683042Sedp 	struct autopush	*ap_result;
2693042Sedp 
2703448Sdh155122 	ASSERT(MUTEX_NOT_HELD(&ss->ss_sad_lock));
2713042Sedp 
2723042Sedp 	/* prepare an apcommon structure to search with */
2733042Sedp 	apc.apc_cmd = SAP_ONE;
2743042Sedp 	apc.apc_major = getmajor(dev);
2753042Sedp 	apc.apc_minor = getminor(dev);
2763042Sedp 
2773042Sedp 	/*
2783042Sedp 	 * the following values must be set but initialized to have a
2793042Sedp 	 * valid apcommon struct, but since we're only using this
2803042Sedp 	 * structure to do a query the values are never actually used.
2813042Sedp 	 */
2823042Sedp 	apc.apc_npush = 1;
2833042Sedp 	apc.apc_lastminor = 0;
2843042Sedp 
2853448Sdh155122 	mutex_enter(&ss->ss_sad_lock);
2863448Sdh155122 	ap_result = sad_ap_find(&apc, ss);
2873448Sdh155122 	mutex_exit(&ss->ss_sad_lock);
2883042Sedp 	return (ap_result);
2893042Sedp }
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate void
sad_initspace(str_stack_t * ss)2923448Sdh155122 sad_initspace(str_stack_t *ss)
2930Sstevel@tonic-gate {
2943448Sdh155122 	mutex_init(&ss->ss_sad_lock, NULL, MUTEX_DEFAULT, NULL);
2953448Sdh155122 	ss->ss_sad_hash_nchains = 127;
2963448Sdh155122 	ss->ss_sadcnt = 16;
2973448Sdh155122 
2983448Sdh155122 	ss->ss_saddev = kmem_zalloc(ss->ss_sadcnt * sizeof (struct saddev),
2993448Sdh155122 	    KM_SLEEP);
3003448Sdh155122 	ss->ss_sad_hash = mod_hash_create_extended("sad_hash",
3013448Sdh155122 	    ss->ss_sad_hash_nchains, mod_hash_null_keydtor,
3023448Sdh155122 	    mod_hash_null_valdtor,
3033042Sedp 	    sad_hash_alg, NULL, sad_hash_keycmp, KM_SLEEP);
3040Sstevel@tonic-gate }
3053448Sdh155122 
3063448Sdh155122 void
sad_freespace(str_stack_t * ss)3073448Sdh155122 sad_freespace(str_stack_t *ss)
3083448Sdh155122 {
3093448Sdh155122 	kmem_free(ss->ss_saddev, ss->ss_sadcnt * sizeof (struct saddev));
3103448Sdh155122 	ss->ss_saddev = NULL;
3113448Sdh155122 
312*6220Syz147064 	mutex_enter(&ss->ss_sad_lock);
313*6220Syz147064 	mod_hash_walk(ss->ss_sad_hash, sad_hash_free_value, NULL);
3143448Sdh155122 	mod_hash_destroy_hash(ss->ss_sad_hash);
3153448Sdh155122 	ss->ss_sad_hash = NULL;
316*6220Syz147064 	mutex_exit(&ss->ss_sad_lock);
3173448Sdh155122 
3183448Sdh155122 	mutex_destroy(&ss->ss_sad_lock);
3193448Sdh155122 }
320