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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #pragma ident "%Z%%M% %I% %E% SMI"
29 * Config dependent data structures for the Streams Administrative Driver
30 * (or "Ballad of the SAD Cafe").
32 #include <sys/types.h>
34 #include <sys/stream.h>
35 #include <sys/strsubr.h>
38 #include <sys/sysmacros.h>
41 * Currently we store all the sad data in a hash table keyed by major
42 * number. This is far from ideal. It means that if a single device
43 * starts using lots of SAP_ONE entries all its entries will hash
44 * to the same bucket and we'll get very long chains for that bucket.
46 * Unfortunately, it's not possible to hash by a different key or to easily
47 * break up our one hash into seperate hashs. The reason is because
48 * the hash contains mixed data types. Ie, it has three different
49 * types of autopush nodes in it: SAP_ALL, SAP_RANGE, SAP_ONE. Not
50 * only does the hash table contain nodes of different types, but we
51 * have to be able to search the table with a node of one type that
52 * might match another node with a different type. (ie, we might search
53 * for a SAP_ONE node with a value that matches a SAP_ALL node in the
54 * hash, or vice versa.)
56 * An ideal solution would probably be an AVL tree sorted by major
57 * numbers. Each node in the AVL tree would have the following optional
58 * data associated with it:
59 * - a single SAP_ALL autopush node
60 * - an or avl tree or hash table of SAP_RANGE and SAP_ONE autopush
61 * nodes indexed by minor numbers. perhaps two separate tables,
62 * one for each type of autopush nodes.
64 * Note that regardless of how the data is stored there can't be any overlap
65 * stored between autopush nodes. For example, if there is a SAP_ALL node
66 * for a given major number then there can't be any SAP_RANGE or SAP_ONE
67 * nodes for that same major number.
71 * Private Internal Interfaces
75 sad_hash_alg(void *hash_data
, mod_hash_key_t key
)
77 struct apcommon
*apc
= (struct apcommon
*)key
;
79 ASSERT(sad_apc_verify(apc
) == 0);
80 return (apc
->apc_major
);
84 * Compare hash keys based off of major, minor, lastminor, and type.
87 sad_hash_keycmp(mod_hash_key_t key1
, mod_hash_key_t key2
)
89 struct apcommon
*apc1
= (struct apcommon
*)key1
;
90 struct apcommon
*apc2
= (struct apcommon
*)key2
;
92 ASSERT(sad_apc_verify(apc1
) == 0);
93 ASSERT(sad_apc_verify(apc2
) == 0);
95 /* Filter out cases where the major number doesn't match. */
96 if (apc1
->apc_major
!= apc2
->apc_major
)
99 /* If either type is SAP_ALL then we're done. */
100 if ((apc1
->apc_cmd
== SAP_ALL
) || (apc2
->apc_cmd
== SAP_ALL
))
103 /* Deal with the case where both types are SAP_ONE. */
104 if ((apc1
->apc_cmd
== SAP_ONE
) && (apc2
->apc_cmd
== SAP_ONE
)) {
105 /* Check if the minor numbers match. */
106 return (apc1
->apc_minor
!= apc2
->apc_minor
);
109 /* Deal with the case where both types are SAP_RANGE. */
110 if ((apc1
->apc_cmd
== SAP_RANGE
) && (apc2
->apc_cmd
== SAP_RANGE
)) {
111 /* Check for overlapping ranges. */
112 if ((apc1
->apc_lastminor
< apc2
->apc_minor
) ||
113 (apc1
->apc_minor
> apc2
->apc_lastminor
))
119 * We know that one type is SAP_ONE and the other is SAP_RANGE.
120 * So now let's do range matching.
122 if (apc1
->apc_cmd
== SAP_RANGE
) {
123 ASSERT(apc2
->apc_cmd
== SAP_ONE
);
124 if ((apc1
->apc_lastminor
< apc2
->apc_minor
) ||
125 (apc1
->apc_minor
> apc2
->apc_minor
))
128 ASSERT(apc1
->apc_cmd
== SAP_ONE
);
129 ASSERT(apc2
->apc_cmd
== SAP_RANGE
);
130 if ((apc1
->apc_minor
< apc2
->apc_minor
) ||
131 (apc1
->apc_minor
> apc2
->apc_lastminor
))
139 sad_hash_free_value(mod_hash_key_t key
, mod_hash_val_t
*val
, void *arg
)
141 struct autopush
*ap
= (struct autopush
*)val
;
143 ASSERT(ap
->ap_cnt
> 0);
144 if (--(ap
->ap_cnt
) == 0)
145 kmem_free(ap
, sizeof (struct autopush
));
147 return (MH_WALK_CONTINUE
);
151 * External Interfaces
154 sad_apc_verify(struct apcommon
*apc
)
156 /* sanity check the number of modules to push */
157 if ((apc
->apc_npush
== 0) || (apc
->apc_npush
> MAXAPUSH
) ||
158 (apc
->apc_npush
> nstrpush
))
161 /* Check for NODEV major vaule */
162 if (apc
->apc_major
== -1)
165 switch (apc
->apc_cmd
) {
169 * Really, we'd like to be strict here and make sure that
170 * apc_lastminor is 0 (since setting apc_lastminor for
171 * SAP_ALL and SAP_ONE commands doesn't make any sense),
172 * but we can't since historically apc_lastminor has been
173 * silently ignored for non-SAP_RANGE commands.
177 if (apc
->apc_lastminor
<= apc
->apc_minor
)
187 sad_ap_verify(struct autopush
*ap
)
191 if ((ret
= sad_apc_verify(&ap
->ap_common
)) != 0)
195 * Validate that the specified list of modules exist. Note that
196 * ap_npush has already been sanity checked by sad_apc_verify().
198 for (i
= 0; i
< ap
->ap_npush
; i
++) {
199 ap
->ap_list
[i
][FMNAMESZ
] = '\0';
200 if (fmodsw_find(ap
->ap_list
[i
], FMODSW_LOAD
) == NULL
)
209 struct autopush
*ap_new
;
211 ap_new
= kmem_zalloc(sizeof (struct autopush
), KM_SLEEP
);
217 sad_ap_rele(struct autopush
*ap
, str_stack_t
*ss
)
219 mutex_enter(&ss
->ss_sad_lock
);
220 ASSERT(ap
->ap_cnt
> 0);
221 if (--(ap
->ap_cnt
) == 0) {
222 mutex_exit(&ss
->ss_sad_lock
);
223 kmem_free(ap
, sizeof (struct autopush
));
225 mutex_exit(&ss
->ss_sad_lock
);
230 sad_ap_insert(struct autopush
*ap
, str_stack_t
*ss
)
232 ASSERT(MUTEX_HELD(&ss
->ss_sad_lock
));
233 ASSERT(sad_apc_verify(&ap
->ap_common
) == 0);
234 ASSERT(sad_ap_find(&ap
->ap_common
, ss
) == NULL
);
235 (void) mod_hash_insert(ss
->ss_sad_hash
, &ap
->ap_common
, ap
);
239 sad_ap_remove(struct autopush
*ap
, str_stack_t
*ss
)
241 struct autopush
*ap_removed
= NULL
;
243 ASSERT(MUTEX_HELD(&ss
->ss_sad_lock
));
244 (void) mod_hash_remove(ss
->ss_sad_hash
, &ap
->ap_common
,
245 (mod_hash_val_t
*)&ap_removed
);
246 ASSERT(ap
== ap_removed
);
250 sad_ap_find(struct apcommon
*apc
, str_stack_t
*ss
)
252 struct autopush
*ap_result
= NULL
;
254 ASSERT(MUTEX_HELD(&ss
->ss_sad_lock
));
255 ASSERT(sad_apc_verify(apc
) == 0);
257 (void) mod_hash_find(ss
->ss_sad_hash
, apc
,
258 (mod_hash_val_t
*)&ap_result
);
259 if (ap_result
!= NULL
)
265 sad_ap_find_by_dev(dev_t dev
, str_stack_t
*ss
)
268 struct autopush
*ap_result
;
270 ASSERT(MUTEX_NOT_HELD(&ss
->ss_sad_lock
));
272 /* prepare an apcommon structure to search with */
273 apc
.apc_cmd
= SAP_ONE
;
274 apc
.apc_major
= getmajor(dev
);
275 apc
.apc_minor
= getminor(dev
);
278 * the following values must be set but initialized to have a
279 * valid apcommon struct, but since we're only using this
280 * structure to do a query the values are never actually used.
283 apc
.apc_lastminor
= 0;
285 mutex_enter(&ss
->ss_sad_lock
);
286 ap_result
= sad_ap_find(&apc
, ss
);
287 mutex_exit(&ss
->ss_sad_lock
);
292 sad_initspace(str_stack_t
*ss
)
294 mutex_init(&ss
->ss_sad_lock
, NULL
, MUTEX_DEFAULT
, NULL
);
295 ss
->ss_sad_hash_nchains
= 127;
298 ss
->ss_saddev
= kmem_zalloc(ss
->ss_sadcnt
* sizeof (struct saddev
),
300 ss
->ss_sad_hash
= mod_hash_create_extended("sad_hash",
301 ss
->ss_sad_hash_nchains
, mod_hash_null_keydtor
,
302 mod_hash_null_valdtor
,
303 sad_hash_alg
, NULL
, sad_hash_keycmp
, KM_SLEEP
);
307 sad_freespace(str_stack_t
*ss
)
309 kmem_free(ss
->ss_saddev
, ss
->ss_sadcnt
* sizeof (struct saddev
));
310 ss
->ss_saddev
= NULL
;
312 mutex_enter(&ss
->ss_sad_lock
);
313 mod_hash_walk(ss
->ss_sad_hash
, sad_hash_free_value
, NULL
);
314 mod_hash_destroy_hash(ss
->ss_sad_hash
);
315 ss
->ss_sad_hash
= NULL
;
316 mutex_exit(&ss
->ss_sad_lock
);
318 mutex_destroy(&ss
->ss_sad_lock
);