1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Config dependent data structures for the Streams Administrative Driver 30 * (or "Ballad of the SAD Cafe"). 31 */ 32 #include <sys/types.h> 33 #include <sys/conf.h> 34 #include <sys/stream.h> 35 #include <sys/strsubr.h> 36 #include <sys/sad.h> 37 #include <sys/kmem.h> 38 #include <sys/sysmacros.h> 39 40 struct saddev *saddev; /* sad device array */ 41 int sadcnt = 16; /* number of sad devices */ 42 43 /* 44 * Currently we store all the sad data in a hash table keyed by major 45 * number. This is far from ideal. It means that if a single device 46 * starts using lots of SAP_ONE entries all its entries will hash 47 * to the same bucket and we'll get very long chains for that bucket. 48 * 49 * Unfortunately, it's not possible to hash by a different key or to easily 50 * break up our one hash into seperate hashs. The reason is because 51 * the hash contains mixed data types. Ie, it has three different 52 * types of autopush nodes in it: SAP_ALL, SAP_RANGE, SAP_ONE. Not 53 * only does the hash table contain nodes of different types, but we 54 * have to be able to search the table with a node of one type that 55 * might match another node with a different type. (ie, we might search 56 * for a SAP_ONE node with a value that matches a SAP_ALL node in the 57 * hash, or vice versa.) 58 * 59 * An ideal solution would probably be an AVL tree sorted by major 60 * numbers. Each node in the AVL tree would have the following optional 61 * data associated with it: 62 * - a single SAP_ALL autopush node 63 * - an or avl tree or hash table of SAP_RANGE and SAP_ONE autopush 64 * nodes indexed by minor numbers. perhaps two separate tables, 65 * one for each type of autopush nodes. 66 * 67 * Note that regardless of how the data is stored there can't be any overlap 68 * stored between autopush nodes. For example, if there is a SAP_ALL node 69 * for a given major number then there can't be any SAP_RANGE or SAP_ONE 70 * nodes for that same major number. 71 */ 72 kmutex_t sad_lock; /* protects sad_hash */ 73 static mod_hash_t *sad_hash; 74 static size_t sad_hash_nchains = 127; 75 76 /* 77 * Private Internal Interfaces 78 */ 79 /*ARGSUSED*/ 80 static uint_t 81 sad_hash_alg(void *hash_data, mod_hash_key_t key) 82 { 83 struct apcommon *apc = (struct apcommon *)key; 84 85 ASSERT(sad_apc_verify(apc) == 0); 86 return (apc->apc_major); 87 } 88 89 /* 90 * Compare hash keys based off of major, minor, lastminor, and type. 91 */ 92 static int 93 sad_hash_keycmp(mod_hash_key_t key1, mod_hash_key_t key2) 94 { 95 struct apcommon *apc1 = (struct apcommon *)key1; 96 struct apcommon *apc2 = (struct apcommon *)key2; 97 98 ASSERT(sad_apc_verify(apc1) == 0); 99 ASSERT(sad_apc_verify(apc2) == 0); 100 101 /* Filter out cases where the major number doesn't match. */ 102 if (apc1->apc_major != apc2->apc_major) 103 return (1); 104 105 /* If either type is SAP_ALL then we're done. */ 106 if ((apc1->apc_cmd == SAP_ALL) || (apc2->apc_cmd == SAP_ALL)) 107 return (0); 108 109 /* Deal with the case where both types are SAP_ONE. */ 110 if ((apc1->apc_cmd == SAP_ONE) && (apc2->apc_cmd == SAP_ONE)) { 111 /* Check if the minor numbers match. */ 112 return (apc1->apc_minor != apc2->apc_minor); 113 } 114 115 /* Deal with the case where both types are SAP_RANGE. */ 116 if ((apc1->apc_cmd == SAP_RANGE) && (apc2->apc_cmd == SAP_RANGE)) { 117 /* Check for overlapping ranges. */ 118 if ((apc1->apc_lastminor < apc2->apc_minor) || 119 (apc1->apc_minor > apc2->apc_lastminor)) 120 return (1); 121 return (0); 122 } 123 124 /* 125 * We know that one type is SAP_ONE and the other is SAP_RANGE. 126 * So now let's do range matching. 127 */ 128 if (apc1->apc_cmd == SAP_RANGE) { 129 ASSERT(apc2->apc_cmd == SAP_ONE); 130 if ((apc1->apc_lastminor < apc2->apc_minor) || 131 (apc1->apc_minor > apc2->apc_minor)) 132 return (1); 133 } else { 134 ASSERT(apc1->apc_cmd == SAP_ONE); 135 ASSERT(apc2->apc_cmd == SAP_RANGE); 136 if ((apc1->apc_minor < apc2->apc_minor) || 137 (apc1->apc_minor > apc2->apc_lastminor)) 138 return (1); 139 } 140 return (0); 141 } 142 143 /* 144 * External Interfaces 145 */ 146 int 147 sad_apc_verify(struct apcommon *apc) 148 { 149 /* sanity check the number of modules to push */ 150 if ((apc->apc_npush == 0) || (apc->apc_npush > MAXAPUSH) || 151 (apc->apc_npush > nstrpush)) 152 return (EINVAL); 153 154 /* Check for NODEV major vaule */ 155 if (apc->apc_major == -1) 156 return (EINVAL); 157 158 switch (apc->apc_cmd) { 159 case SAP_ALL: 160 case SAP_ONE: 161 /* 162 * Really, we'd like to be strict here and make sure that 163 * apc_lastminor is 0 (since setting apc_lastminor for 164 * SAP_ALL and SAP_ONE commands doesn't make any sense), 165 * but we can't since historically apc_lastminor has been 166 * silently ignored for non-SAP_RANGE commands. 167 */ 168 break; 169 case SAP_RANGE: 170 if (apc->apc_lastminor <= apc->apc_minor) 171 return (ERANGE); 172 break; 173 default: 174 return (EINVAL); 175 } 176 return (0); 177 } 178 179 int 180 sad_ap_verify(struct autopush *ap) 181 { 182 int ret, i; 183 184 if ((ret = sad_apc_verify(&ap->ap_common)) != 0) 185 return (ret); 186 187 /* 188 * Validate that the specified list of modules exist. Note that 189 * ap_npush has already been sanity checked by sad_apc_verify(). 190 */ 191 for (i = 0; i < ap->ap_npush; i++) { 192 ap->ap_list[i][FMNAMESZ] = '\0'; 193 if (fmodsw_find(ap->ap_list[i], FMODSW_LOAD) == NULL) 194 return (EINVAL); 195 } 196 return (0); 197 } 198 199 struct autopush * 200 sad_ap_alloc(void) 201 { 202 struct autopush *ap_new; 203 204 ap_new = kmem_zalloc(sizeof (struct autopush), KM_SLEEP); 205 ap_new->ap_cnt = 1; 206 return (ap_new); 207 } 208 209 void 210 sad_ap_rele(struct autopush *ap) 211 { 212 mutex_enter(&sad_lock); 213 ASSERT(ap->ap_cnt > 0); 214 if (--(ap->ap_cnt) == 0) { 215 mutex_exit(&sad_lock); 216 kmem_free(ap, sizeof (struct autopush)); 217 } else { 218 mutex_exit(&sad_lock); 219 } 220 } 221 222 void 223 sad_ap_insert(struct autopush *ap) 224 { 225 ASSERT(MUTEX_HELD(&sad_lock)); 226 ASSERT(sad_apc_verify(&ap->ap_common) == 0); 227 ASSERT(sad_ap_find(&ap->ap_common) == NULL); 228 (void) mod_hash_insert(sad_hash, &ap->ap_common, ap); 229 } 230 231 void 232 sad_ap_remove(struct autopush *ap) 233 { 234 struct autopush *ap_removed = NULL; 235 236 ASSERT(MUTEX_HELD(&sad_lock)); 237 (void) mod_hash_remove(sad_hash, &ap->ap_common, 238 (mod_hash_val_t *)&ap_removed); 239 ASSERT(ap == ap_removed); 240 } 241 242 struct autopush * 243 sad_ap_find(struct apcommon *apc) 244 { 245 struct autopush *ap_result = NULL; 246 247 ASSERT(MUTEX_HELD(&sad_lock)); 248 ASSERT(sad_apc_verify(apc) == 0); 249 250 (void) mod_hash_find(sad_hash, apc, (mod_hash_val_t *)&ap_result); 251 if (ap_result != NULL) 252 ap_result->ap_cnt++; 253 return (ap_result); 254 } 255 256 struct autopush * 257 sad_ap_find_by_dev(dev_t dev) 258 { 259 struct apcommon apc; 260 struct autopush *ap_result; 261 262 ASSERT(MUTEX_NOT_HELD(&sad_lock)); 263 264 /* prepare an apcommon structure to search with */ 265 apc.apc_cmd = SAP_ONE; 266 apc.apc_major = getmajor(dev); 267 apc.apc_minor = getminor(dev); 268 269 /* 270 * the following values must be set but initialized to have a 271 * valid apcommon struct, but since we're only using this 272 * structure to do a query the values are never actually used. 273 */ 274 apc.apc_npush = 1; 275 apc.apc_lastminor = 0; 276 277 mutex_enter(&sad_lock); 278 ap_result = sad_ap_find(&apc); 279 mutex_exit(&sad_lock); 280 return (ap_result); 281 } 282 283 void 284 sad_initspace(void) 285 { 286 saddev = kmem_zalloc(sadcnt * sizeof (struct saddev), KM_SLEEP); 287 sad_hash = mod_hash_create_extended("sad_hash", 288 sad_hash_nchains, mod_hash_null_keydtor, mod_hash_null_valdtor, 289 sad_hash_alg, NULL, sad_hash_keycmp, KM_SLEEP); 290 } 291