17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51110f384Sedp * Common Development and Distribution License (the "License"). 61110f384Sedp * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*2ea701aaSyz147064 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * Config dependent data structures for the Streams Administrative Driver 307c478bd9Sstevel@tonic-gate * (or "Ballad of the SAD Cafe"). 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate #include <sys/types.h> 337c478bd9Sstevel@tonic-gate #include <sys/conf.h> 347c478bd9Sstevel@tonic-gate #include <sys/stream.h> 351110f384Sedp #include <sys/strsubr.h> 367c478bd9Sstevel@tonic-gate #include <sys/sad.h> 377c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 381110f384Sedp #include <sys/sysmacros.h> 397c478bd9Sstevel@tonic-gate 407c478bd9Sstevel@tonic-gate /* 411110f384Sedp * Currently we store all the sad data in a hash table keyed by major 421110f384Sedp * number. This is far from ideal. It means that if a single device 431110f384Sedp * starts using lots of SAP_ONE entries all its entries will hash 441110f384Sedp * to the same bucket and we'll get very long chains for that bucket. 451110f384Sedp * 461110f384Sedp * Unfortunately, it's not possible to hash by a different key or to easily 471110f384Sedp * break up our one hash into seperate hashs. The reason is because 481110f384Sedp * the hash contains mixed data types. Ie, it has three different 491110f384Sedp * types of autopush nodes in it: SAP_ALL, SAP_RANGE, SAP_ONE. Not 501110f384Sedp * only does the hash table contain nodes of different types, but we 511110f384Sedp * have to be able to search the table with a node of one type that 521110f384Sedp * might match another node with a different type. (ie, we might search 531110f384Sedp * for a SAP_ONE node with a value that matches a SAP_ALL node in the 541110f384Sedp * hash, or vice versa.) 551110f384Sedp * 561110f384Sedp * An ideal solution would probably be an AVL tree sorted by major 571110f384Sedp * numbers. Each node in the AVL tree would have the following optional 581110f384Sedp * data associated with it: 591110f384Sedp * - a single SAP_ALL autopush node 601110f384Sedp * - an or avl tree or hash table of SAP_RANGE and SAP_ONE autopush 611110f384Sedp * nodes indexed by minor numbers. perhaps two separate tables, 621110f384Sedp * one for each type of autopush nodes. 631110f384Sedp * 641110f384Sedp * Note that regardless of how the data is stored there can't be any overlap 651110f384Sedp * stored between autopush nodes. For example, if there is a SAP_ALL node 661110f384Sedp * for a given major number then there can't be any SAP_RANGE or SAP_ONE 671110f384Sedp * nodes for that same major number. 687c478bd9Sstevel@tonic-gate */ 691110f384Sedp 701110f384Sedp /* 711110f384Sedp * Private Internal Interfaces 721110f384Sedp */ 731110f384Sedp /*ARGSUSED*/ 741110f384Sedp static uint_t 751110f384Sedp sad_hash_alg(void *hash_data, mod_hash_key_t key) 761110f384Sedp { 771110f384Sedp struct apcommon *apc = (struct apcommon *)key; 781110f384Sedp 791110f384Sedp ASSERT(sad_apc_verify(apc) == 0); 801110f384Sedp return (apc->apc_major); 811110f384Sedp } 821110f384Sedp 831110f384Sedp /* 841110f384Sedp * Compare hash keys based off of major, minor, lastminor, and type. 851110f384Sedp */ 861110f384Sedp static int 871110f384Sedp sad_hash_keycmp(mod_hash_key_t key1, mod_hash_key_t key2) 881110f384Sedp { 891110f384Sedp struct apcommon *apc1 = (struct apcommon *)key1; 901110f384Sedp struct apcommon *apc2 = (struct apcommon *)key2; 911110f384Sedp 921110f384Sedp ASSERT(sad_apc_verify(apc1) == 0); 931110f384Sedp ASSERT(sad_apc_verify(apc2) == 0); 941110f384Sedp 951110f384Sedp /* Filter out cases where the major number doesn't match. */ 961110f384Sedp if (apc1->apc_major != apc2->apc_major) 971110f384Sedp return (1); 981110f384Sedp 991110f384Sedp /* If either type is SAP_ALL then we're done. */ 1001110f384Sedp if ((apc1->apc_cmd == SAP_ALL) || (apc2->apc_cmd == SAP_ALL)) 1011110f384Sedp return (0); 1021110f384Sedp 1031110f384Sedp /* Deal with the case where both types are SAP_ONE. */ 1041110f384Sedp if ((apc1->apc_cmd == SAP_ONE) && (apc2->apc_cmd == SAP_ONE)) { 1051110f384Sedp /* Check if the minor numbers match. */ 1061110f384Sedp return (apc1->apc_minor != apc2->apc_minor); 1071110f384Sedp } 1081110f384Sedp 1091110f384Sedp /* Deal with the case where both types are SAP_RANGE. */ 1101110f384Sedp if ((apc1->apc_cmd == SAP_RANGE) && (apc2->apc_cmd == SAP_RANGE)) { 1111110f384Sedp /* Check for overlapping ranges. */ 1121110f384Sedp if ((apc1->apc_lastminor < apc2->apc_minor) || 1131110f384Sedp (apc1->apc_minor > apc2->apc_lastminor)) 1141110f384Sedp return (1); 1151110f384Sedp return (0); 1161110f384Sedp } 1171110f384Sedp 1181110f384Sedp /* 1191110f384Sedp * We know that one type is SAP_ONE and the other is SAP_RANGE. 1201110f384Sedp * So now let's do range matching. 1211110f384Sedp */ 1221110f384Sedp if (apc1->apc_cmd == SAP_RANGE) { 1231110f384Sedp ASSERT(apc2->apc_cmd == SAP_ONE); 1241110f384Sedp if ((apc1->apc_lastminor < apc2->apc_minor) || 1251110f384Sedp (apc1->apc_minor > apc2->apc_minor)) 1261110f384Sedp return (1); 1271110f384Sedp } else { 1281110f384Sedp ASSERT(apc1->apc_cmd == SAP_ONE); 1291110f384Sedp ASSERT(apc2->apc_cmd == SAP_RANGE); 1301110f384Sedp if ((apc1->apc_minor < apc2->apc_minor) || 1311110f384Sedp (apc1->apc_minor > apc2->apc_lastminor)) 1321110f384Sedp return (1); 1331110f384Sedp } 1341110f384Sedp return (0); 1351110f384Sedp } 1361110f384Sedp 137*2ea701aaSyz147064 /*ARGSUSED*/ 138*2ea701aaSyz147064 static uint_t 139*2ea701aaSyz147064 sad_hash_free_value(mod_hash_key_t key, mod_hash_val_t *val, void *arg) 140*2ea701aaSyz147064 { 141*2ea701aaSyz147064 struct autopush *ap = (struct autopush *)val; 142*2ea701aaSyz147064 143*2ea701aaSyz147064 ASSERT(ap->ap_cnt > 0); 144*2ea701aaSyz147064 if (--(ap->ap_cnt) == 0) 145*2ea701aaSyz147064 kmem_free(ap, sizeof (struct autopush)); 146*2ea701aaSyz147064 147*2ea701aaSyz147064 return (MH_WALK_CONTINUE); 148*2ea701aaSyz147064 } 149*2ea701aaSyz147064 1501110f384Sedp /* 1511110f384Sedp * External Interfaces 1521110f384Sedp */ 1531110f384Sedp int 1541110f384Sedp sad_apc_verify(struct apcommon *apc) 1551110f384Sedp { 1561110f384Sedp /* sanity check the number of modules to push */ 1571110f384Sedp if ((apc->apc_npush == 0) || (apc->apc_npush > MAXAPUSH) || 1581110f384Sedp (apc->apc_npush > nstrpush)) 1591110f384Sedp return (EINVAL); 1601110f384Sedp 1611110f384Sedp /* Check for NODEV major vaule */ 1621110f384Sedp if (apc->apc_major == -1) 1631110f384Sedp return (EINVAL); 1641110f384Sedp 1651110f384Sedp switch (apc->apc_cmd) { 1661110f384Sedp case SAP_ALL: 1671110f384Sedp case SAP_ONE: 16850110644Sedp /* 16950110644Sedp * Really, we'd like to be strict here and make sure that 17050110644Sedp * apc_lastminor is 0 (since setting apc_lastminor for 17150110644Sedp * SAP_ALL and SAP_ONE commands doesn't make any sense), 17250110644Sedp * but we can't since historically apc_lastminor has been 17350110644Sedp * silently ignored for non-SAP_RANGE commands. 17450110644Sedp */ 1751110f384Sedp break; 1761110f384Sedp case SAP_RANGE: 1771110f384Sedp if (apc->apc_lastminor <= apc->apc_minor) 1781110f384Sedp return (ERANGE); 1791110f384Sedp break; 1801110f384Sedp default: 1811110f384Sedp return (EINVAL); 1821110f384Sedp } 1831110f384Sedp return (0); 1841110f384Sedp } 1851110f384Sedp 1861110f384Sedp int 1871110f384Sedp sad_ap_verify(struct autopush *ap) 1881110f384Sedp { 1891110f384Sedp int ret, i; 1901110f384Sedp 1911110f384Sedp if ((ret = sad_apc_verify(&ap->ap_common)) != 0) 1921110f384Sedp return (ret); 1931110f384Sedp 1941110f384Sedp /* 1951110f384Sedp * Validate that the specified list of modules exist. Note that 1961110f384Sedp * ap_npush has already been sanity checked by sad_apc_verify(). 1971110f384Sedp */ 1981110f384Sedp for (i = 0; i < ap->ap_npush; i++) { 1991110f384Sedp ap->ap_list[i][FMNAMESZ] = '\0'; 2001110f384Sedp if (fmodsw_find(ap->ap_list[i], FMODSW_LOAD) == NULL) 2011110f384Sedp return (EINVAL); 2021110f384Sedp } 2031110f384Sedp return (0); 2041110f384Sedp } 2051110f384Sedp 2061110f384Sedp struct autopush * 2071110f384Sedp sad_ap_alloc(void) 2081110f384Sedp { 2091110f384Sedp struct autopush *ap_new; 2101110f384Sedp 2111110f384Sedp ap_new = kmem_zalloc(sizeof (struct autopush), KM_SLEEP); 2121110f384Sedp ap_new->ap_cnt = 1; 2131110f384Sedp return (ap_new); 2141110f384Sedp } 2151110f384Sedp 2161110f384Sedp void 217f4b3ec61Sdh155122 sad_ap_rele(struct autopush *ap, str_stack_t *ss) 2181110f384Sedp { 219f4b3ec61Sdh155122 mutex_enter(&ss->ss_sad_lock); 2201110f384Sedp ASSERT(ap->ap_cnt > 0); 2211110f384Sedp if (--(ap->ap_cnt) == 0) { 222f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 2231110f384Sedp kmem_free(ap, sizeof (struct autopush)); 2241110f384Sedp } else { 225f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 2261110f384Sedp } 2271110f384Sedp } 2281110f384Sedp 2291110f384Sedp void 230f4b3ec61Sdh155122 sad_ap_insert(struct autopush *ap, str_stack_t *ss) 2311110f384Sedp { 232f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(&ss->ss_sad_lock)); 2331110f384Sedp ASSERT(sad_apc_verify(&ap->ap_common) == 0); 234f4b3ec61Sdh155122 ASSERT(sad_ap_find(&ap->ap_common, ss) == NULL); 235f4b3ec61Sdh155122 (void) mod_hash_insert(ss->ss_sad_hash, &ap->ap_common, ap); 2361110f384Sedp } 2371110f384Sedp 2381110f384Sedp void 239f4b3ec61Sdh155122 sad_ap_remove(struct autopush *ap, str_stack_t *ss) 2401110f384Sedp { 2411110f384Sedp struct autopush *ap_removed = NULL; 2421110f384Sedp 243f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(&ss->ss_sad_lock)); 244f4b3ec61Sdh155122 (void) mod_hash_remove(ss->ss_sad_hash, &ap->ap_common, 2451110f384Sedp (mod_hash_val_t *)&ap_removed); 2461110f384Sedp ASSERT(ap == ap_removed); 2471110f384Sedp } 2481110f384Sedp 2491110f384Sedp struct autopush * 250f4b3ec61Sdh155122 sad_ap_find(struct apcommon *apc, str_stack_t *ss) 2511110f384Sedp { 2521110f384Sedp struct autopush *ap_result = NULL; 2531110f384Sedp 254f4b3ec61Sdh155122 ASSERT(MUTEX_HELD(&ss->ss_sad_lock)); 2551110f384Sedp ASSERT(sad_apc_verify(apc) == 0); 2561110f384Sedp 257f4b3ec61Sdh155122 (void) mod_hash_find(ss->ss_sad_hash, apc, 258f4b3ec61Sdh155122 (mod_hash_val_t *)&ap_result); 2591110f384Sedp if (ap_result != NULL) 2601110f384Sedp ap_result->ap_cnt++; 2611110f384Sedp return (ap_result); 2621110f384Sedp } 2631110f384Sedp 2641110f384Sedp struct autopush * 265f4b3ec61Sdh155122 sad_ap_find_by_dev(dev_t dev, str_stack_t *ss) 2661110f384Sedp { 2671110f384Sedp struct apcommon apc; 2681110f384Sedp struct autopush *ap_result; 2691110f384Sedp 270f4b3ec61Sdh155122 ASSERT(MUTEX_NOT_HELD(&ss->ss_sad_lock)); 2711110f384Sedp 2721110f384Sedp /* prepare an apcommon structure to search with */ 2731110f384Sedp apc.apc_cmd = SAP_ONE; 2741110f384Sedp apc.apc_major = getmajor(dev); 2751110f384Sedp apc.apc_minor = getminor(dev); 2761110f384Sedp 2771110f384Sedp /* 2781110f384Sedp * the following values must be set but initialized to have a 2791110f384Sedp * valid apcommon struct, but since we're only using this 2801110f384Sedp * structure to do a query the values are never actually used. 2811110f384Sedp */ 2821110f384Sedp apc.apc_npush = 1; 2831110f384Sedp apc.apc_lastminor = 0; 2841110f384Sedp 285f4b3ec61Sdh155122 mutex_enter(&ss->ss_sad_lock); 286f4b3ec61Sdh155122 ap_result = sad_ap_find(&apc, ss); 287f4b3ec61Sdh155122 mutex_exit(&ss->ss_sad_lock); 2881110f384Sedp return (ap_result); 2891110f384Sedp } 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate void 292f4b3ec61Sdh155122 sad_initspace(str_stack_t *ss) 2937c478bd9Sstevel@tonic-gate { 294f4b3ec61Sdh155122 mutex_init(&ss->ss_sad_lock, NULL, MUTEX_DEFAULT, NULL); 295f4b3ec61Sdh155122 ss->ss_sad_hash_nchains = 127; 296f4b3ec61Sdh155122 ss->ss_sadcnt = 16; 297f4b3ec61Sdh155122 298f4b3ec61Sdh155122 ss->ss_saddev = kmem_zalloc(ss->ss_sadcnt * sizeof (struct saddev), 299f4b3ec61Sdh155122 KM_SLEEP); 300f4b3ec61Sdh155122 ss->ss_sad_hash = mod_hash_create_extended("sad_hash", 301f4b3ec61Sdh155122 ss->ss_sad_hash_nchains, mod_hash_null_keydtor, 302f4b3ec61Sdh155122 mod_hash_null_valdtor, 3031110f384Sedp sad_hash_alg, NULL, sad_hash_keycmp, KM_SLEEP); 3047c478bd9Sstevel@tonic-gate } 305f4b3ec61Sdh155122 306f4b3ec61Sdh155122 void 307f4b3ec61Sdh155122 sad_freespace(str_stack_t *ss) 308f4b3ec61Sdh155122 { 309f4b3ec61Sdh155122 kmem_free(ss->ss_saddev, ss->ss_sadcnt * sizeof (struct saddev)); 310f4b3ec61Sdh155122 ss->ss_saddev = NULL; 311f4b3ec61Sdh155122 312*2ea701aaSyz147064 mutex_enter(&ss->ss_sad_lock); 313*2ea701aaSyz147064 mod_hash_walk(ss->ss_sad_hash, sad_hash_free_value, NULL); 314f4b3ec61Sdh155122 mod_hash_destroy_hash(ss->ss_sad_hash); 315f4b3ec61Sdh155122 ss->ss_sad_hash = NULL; 316*2ea701aaSyz147064 mutex_exit(&ss->ss_sad_lock); 317f4b3ec61Sdh155122 318f4b3ec61Sdh155122 mutex_destroy(&ss->ss_sad_lock); 319f4b3ec61Sdh155122 } 320