xref: /titanic_44/usr/src/uts/common/io/sad_conf.c (revision 39c23413b8df94a95f67b34cfd4a4dfc3fd0b48d)
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