4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #include <sys/types.h>
28 #include <sys/param.h>
29 #include <sys/systm.h>
31 #include <sys/stream.h>
32 #include <sys/strsubr.h>
33 #include <sys/modctl.h>
34 #include <sys/modhash.h>
35 #include <sys/atomic.h>
38 #include <sys/sunddi.h>
39 #include <sys/t_lock.h>
42 * This module provides the framework that manage STREAMS modules.
43 * fmodsw_alloc() is called from modconf.c as a result of a module calling
44 * mod_install() and fmodsw_free() is called as the result of the module
45 * calling mod_remove().
46 * fmodsw_find() will find the fmodsw_impl_t structure relating to a named
47 * module. There is no equivalent of driver major numbers for modules; the
48 * the database of fmodsw_impl_t structures is purely keyed by name and
49 * is hence a hash table to keep lookup cost to a minimum.
53 * fmodsw_hash is the hash table that will be used to map module names to
54 * their fmodsw_impl_t structures. The hash function requires that the value is
55 * a power of 2 so this definition specifies the log of the hash table size.
57 #define FMODSW_LOG_HASHSZ 8
60 * Hash table and associated reader-writer lock
62 * NOTE: Because the lock is global data, it is initialized to zero and hence
63 * a call to rw_init() is not required. Similarly all the pointers in
64 * the hash table will be implicitly initialized to NULL.
66 #define FMODSW_HASHSZ (1 << FMODSW_LOG_HASHSZ)
68 static fmodsw_impl_t
*fmodsw_hash
[FMODSW_HASHSZ
];
69 static krwlock_t fmodsw_lock
;
74 * This is not conditionally compiled since it may be useful to third
75 * parties when developing new modules.
80 #define FMODSW_INIT 0x00000001
81 #define FMODSW_REGISTER 0x00000002
82 #define FMODSW_UNREGISTER 0x00000004
83 #define FMODSW_FIND 0x00000008
85 uint32_t fmodsw_debug_flags
= 0x00000000;
87 static void fmodsw_dprintf(uint_t flag
, const char *fmt
, ...) __KPRINTFLIKE(2);
91 i_fmodsw_dprintf(uint_t flag
, const char *fmt
, ...)
97 if (fmodsw_debug_flags
& flag
) {
100 (void) sprintf(ptr
, "strmod debug: ");
102 (void) vsnprintf(ptr
, buf
+ BUFSZ
- ptr
, fmt
, alist
);
113 #define FMODSW_HASH(_key) \
114 (uint_t)(((_key[0] << 4) | (_key[1] & 0x0f)) & (FMODSW_HASHSZ - 1))
116 #define FMODSW_KEYCMP(_k1, _k2, _match) \
118 char *p1 = (char *)(_k1); \
119 char *p2 = (char *)(_k2); \
121 while (*p1 == *p2++) { \
122 if (*p1++ == '\0') { \
129 i_fmodsw_hash_insert(fmodsw_impl_t
*fp
)
135 ASSERT(rw_write_held(&fmodsw_lock
));
137 bucket
= FMODSW_HASH(fp
->f_name
);
138 for (pp
= &(fmodsw_hash
[bucket
]); (p
= *pp
) != NULL
;
140 FMODSW_KEYCMP(p
->f_name
, fp
->f_name
, found
);
151 i_fmodsw_hash_remove(const char *name
, fmodsw_impl_t
**fpp
)
157 ASSERT(rw_write_held(&fmodsw_lock
));
159 bucket
= FMODSW_HASH(name
);
160 for (pp
= &(fmodsw_hash
[bucket
]); (p
= *pp
) != NULL
;
162 FMODSW_KEYCMP(p
->f_name
, name
, found
);
176 i_fmodsw_hash_find(const char *name
, fmodsw_impl_t
**fpp
)
182 ASSERT(rw_read_held(&fmodsw_lock
));
184 bucket
= FMODSW_HASH(name
);
185 for (p
= fmodsw_hash
[bucket
]; p
!= NULL
; p
= p
->f_next
)
186 FMODSW_KEYCMP(p
->f_name
, name
, found
);
201 * Exported functions:
205 fmodsw_register(const char *name
, struct streamtab
*str
, int flag
)
213 if ((len
= strlen(name
)) > FMNAMESZ
)
216 if ((fp
= kmem_zalloc(sizeof (fmodsw_impl_t
), KM_NOSLEEP
)) == NULL
)
219 (void) strncpy(fp
->f_name
, name
, len
);
220 fp
->f_name
[len
] = '\0';
222 if ((err
= devflg_to_qflag(str
, flag
, &qflag
, &sqtype
)) != 0)
227 fp
->f_sqtype
= sqtype
;
228 if (qflag
& (QPERMOD
| QMTOUTPERIM
))
229 fp
->f_dmp
= hold_dm(str
, qflag
, sqtype
);
231 rw_enter(&fmodsw_lock
, RW_WRITER
);
232 if ((err
= i_fmodsw_hash_insert(fp
)) != 0) {
233 rw_exit(&fmodsw_lock
);
236 rw_exit(&fmodsw_lock
);
238 i_fmodsw_dprintf(FMODSW_REGISTER
, "registered module '%s'\n", name
);
241 i_fmodsw_dprintf(FMODSW_REGISTER
, "failed to register module '%s'\n",
243 if (fp
->f_dmp
!= NULL
)
245 kmem_free(fp
, sizeof (fmodsw_impl_t
));
250 fmodsw_unregister(const char *name
)
255 rw_enter(&fmodsw_lock
, RW_WRITER
);
256 if ((err
= i_fmodsw_hash_remove(name
, &fp
)) != 0) {
257 rw_exit(&fmodsw_lock
);
260 rw_exit(&fmodsw_lock
);
262 if (fp
->f_dmp
!= NULL
)
264 kmem_free(fp
, sizeof (fmodsw_impl_t
));
266 i_fmodsw_dprintf(FMODSW_UNREGISTER
, "unregistered module '%s'\n",
270 i_fmodsw_dprintf(FMODSW_UNREGISTER
, "failed to unregister module "
276 fmodsw_find(const char *name
, fmodsw_flags_t flags
)
282 rw_enter(&fmodsw_lock
, RW_READER
);
283 if (i_fmodsw_hash_find(name
, &fp
) == 0) {
284 if (flags
& FMODSW_HOLD
) {
285 atomic_inc_32(&(fp
->f_ref
)); /* lock must be held */
286 ASSERT(fp
->f_ref
> 0);
289 rw_exit(&fmodsw_lock
);
292 rw_exit(&fmodsw_lock
);
294 if (flags
& FMODSW_LOAD
) {
295 if ((id
= modload("strmod", (char *)name
)) != -1) {
296 i_fmodsw_dprintf(FMODSW_FIND
,
297 "module '%s' loaded: id = %d\n", name
, id
);
306 fmodsw_rele(fmodsw_impl_t
*fp
)
308 ASSERT(fp
->f_ref
> 0);
309 atomic_dec_32(&(fp
->f_ref
));