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