Print this page
MFV: illumos-gate@68c34d0407d130a7e8cb7dfb5394a985db03d785
9951 hook_stack_notify_unregister can leave stack locked
Reviewed by: Andy Fiddaman <omnios@citrus-it.net>
Reviewed by: Igor Kozhukhov <igor@dilos.org>
Reviewed by: Yuri Pankov <yuripv@yuripv.net>
Approved by: Dan McDonald <danmcd@joyent.com>
Author: Jason King <jason.king@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/io/hook.c
+++ new/usr/src/uts/common/io/hook.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 *
25 - * Copyright 2013 Joyent, Inc. All rights reserved.
25 + * Copyright 2018 Joyent, Inc. All rights reserved.
26 26 * Copyright (c) 2016 by Delphix. All rights reserved.
27 27 */
28 28 #include <sys/param.h>
29 29 #include <sys/types.h>
30 30 #include <sys/systm.h>
31 31 #include <sys/errno.h>
32 32 #include <sys/kmem.h>
33 33 #include <sys/mutex.h>
34 34 #include <sys/condvar.h>
35 35 #include <sys/modctl.h>
36 36 #include <sys/hook_impl.h>
37 37 #include <sys/sdt.h>
38 38 #include <sys/cmn_err.h>
39 39
40 40 /*
41 41 * This file provides kernel hook framework.
42 42 */
43 43
44 44 static struct modldrv modlmisc = {
45 45 &mod_miscops, /* drv_modops */
46 46 "Hooks Interface v1.0", /* drv_linkinfo */
47 47 };
48 48
49 49 static struct modlinkage modlinkage = {
50 50 MODREV_1, /* ml_rev */
51 51 &modlmisc, /* ml_linkage */
52 52 NULL
53 53 };
54 54
55 55 static const char *hook_hintvalue_none = "<none>";
56 56
57 57 /*
58 58 * How it works.
59 59 * =============
60 60 * Use of the hook framework here is tied up with zones - when a new zone
61 61 * is created, we create a new hook_stack_t and are open to business for
62 62 * allowing new hook families and their events.
63 63 *
64 64 * A consumer of these hooks is expected to operate in this fashion:
65 65 * 1) call hook_family_add() to create a new family of hooks. It is a
66 66 * current requirement that this call must be made with the value
67 67 * returned from hook_stack_init, by way of infrastructure elsewhere.
68 68 * 2) add events to the registered family with calls to hook_event_add.
69 69 *
70 70 * At this point, the structures in place should be open to others to
71 71 * add hooks to the event or add notifiers for when the contents of the
72 72 * hook stack changes.
73 73 *
74 74 * The interesting stuff happens on teardown.
75 75 *
76 76 * It is a requirement that the provider of hook events work in the reverse
77 77 * order to the above, so that the first step is:
78 78 * 1) remove events from each hook family created earlier
79 79 * 2) remove hook families from the hook stack.
80 80 *
81 81 * When doing teardown of both events and families, a check is made to see
82 82 * if either structure is still "busy". If so then a boolean flag (FWF_DESTROY)
83 83 * is set to say that the structure is condemned. The presence of this flag
84 84 * being set must be checked for in _add()/_register()/ functions and a
85 85 * failure returned if it is set. It is ignored by the _find() functions
86 86 * because they're used by _remove()/_unregister().
87 87 * While setting the condemned flag when trying to delete a structure would
88 88 * normally be keyed from the presence of a reference count being greater
89 89 * than 1, in this implementation there are no reference counts required:
90 90 * instead the presence of objects on linked lists is taken to mean
91 91 * something is still "busy."
92 92 *
93 93 * ONLY the caller that adds the family and the events ever has a direct
94 94 * reference to the internal structures and thus ONLY it should be doing
95 95 * the removal of either the event or family. In practise, what this means
96 96 * is that in ip_netinfo.c, we have calls to net_protocol_register(), followed
97 97 * by net_event_register() (these interface to hook_family_add() and
98 98 * hook_event_add(), respectively) that are made when we create an instance
99 99 * of IP and when the IP instance is shutdown/destroyed, it calls
100 100 * net_event_unregister() and net_protocol_unregister(), which in turn call
101 101 * hook_event_remove() and hook_family_remove() respectively. Nobody else
102 102 * is entitled to call the _unregister() functions. It is imperative that
103 103 * there be only one _remove() call for every _add() call.
104 104 *
105 105 * It is possible that code which is interfacing with this hook framework
106 106 * won't do all the cleaning up that it needs to at the right time. While
107 107 * we can't prevent programmers from creating memory leaks, we can synchronise
108 108 * when we clean up data structures to prevent code accessing free'd memory.
109 109 *
110 110 * A simple diagram showing the ownership is as follows:
111 111 *
112 112 * Owned +--------------+
113 113 * by | hook_stack_t |
114 114 * the +--------------+
115 115 * Instance |
116 116 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
117 117 * V
118 118 * Owned +-------------------+ +-------------------+
119 119 * | hook_family_int_t |---->| hook_family_int_t |
120 120 * by +-------------------+ +-------------------+
121 121 * | \+---------------+ \+---------------+
122 122 * network | | hook_family_t | | hook_family_t |
123 123 * V +---------------+ +---------------+
124 124 * protocol +------------------+ +------------------+
125 125 * | hook_event_int_t |---->| hook_event_int_t |
126 126 * (ipv4,ipv6) +------------------+ +------------------+
127 127 * | \+--------------+ \+--------------+
128 128 * | | hook_event_t | | hook_event_t |
129 129 * | +--------------+ +--------------+
130 130 * - - - - - - - -|- - - - - - - - - - - - - - - - - -
131 131 * V
132 132 * Owned +------------+
133 133 * | hook_int_t |
134 134 * by +------------+
135 135 * \+--------+
136 136 * the consumer | hook_t |
137 137 * +--------+
138 138 *
139 139 * The consumers, such as IPFilter, do not have any pointers or hold any
140 140 * references to hook_int_t, hook_event_t or hook_event_int_t. By placing
141 141 * a hook on an event through net_hook_register(), an implicit reference
142 142 * to the hook_event_int_t is returned with a successful call. Additionally,
143 143 * IPFilter does not see the hook_family_int_t or hook_family_t directly.
144 144 * Rather it is returned a net_handle_t (from net_protocol_lookup()) that
145 145 * contains a pointer to hook_family_int_t. The structure behind the
146 146 * net_handle_t (struct net_data) *is* reference counted and managed
147 147 * appropriately.
148 148 *
149 149 * A more detailed picture that describes how the family/event structures
150 150 * are linked together can be found in <sys/hook_impl.h>
151 151 *
152 152 * Notification callbacks.
153 153 * =======================
154 154 * For each of the hook stack, hook family and hook event, it is possible
155 155 * to request notificatin of change to them. Why?
156 156 * First, lets equate the hook stack to an IP instance, a hook family to
157 157 * a network protocol and a hook event to IP packets on the input path.
158 158 * If a kernel module wants to apply security from the very start of
159 159 * things, it needs to know as soon as a new instance of networking
160 160 * is initiated. Whilst for the global zone, it is taken for granted that
161 161 * this instance will always exist before any interaction takes place,
162 162 * that is not true for zones running with an exclusive networking instance.
163 163 * Thus when a local zone is started and a new instance is created to support
164 164 * that, parties that wish to monitor it and apply a security policy from
165 165 * the onset need to be informed as early as possible - quite probably
166 166 * before any networking is started by the zone's boot scripts.
167 167 * Inside each instance, it is possible to have a number of network protocols
168 168 * (hook families) in operation. Inside the context of the global zone,
169 169 * it is possible to have code run before the kernel module providing the
170 170 * IP networking is loaded. From here, to apply the appropriate security,
171 171 * it is necessary to become informed of when IP is being configured into
172 172 * the zone and this is done by registering a notification callback with
173 173 * the hook stack for changes to it. The next step is to know when packets
174 174 * can be received through the physical_in, etc, events. This is achieved
175 175 * by registering a callback with the appropriate network protocol (or in
176 176 * this file, the correct hook family.) Thus when IP finally attaches a
177 177 * physical_in event to inet, the module looking to enforce a security
178 178 * policy can become aware of it being present. Of course there's no
179 179 * requirement for such a module to be present before all of the above
180 180 * happens and in such a case, it is reasonable for the same module to
181 181 * work after everything has been put in place. For this reason, when
182 182 * a notification callback is added, a series of fake callback events
183 183 * is generated to simulate the arrival of those entities. There is one
184 184 * final series of callbacks that can be registered - those to monitor
185 185 * actual hooks that are added or removed from an event. In practice,
186 186 * this is useful when there are multiple kernel modules participating
187 187 * in the processing of packets and there are behaviour dependencies
188 188 * involved, such that one kernel module might only register its hook
189 189 * if another is already present and also might want to remove its hook
190 190 * when the other disappears.
191 191 *
192 192 * If you know a kernel module will not be loaded before the infrastructure
193 193 * used in this file is present then it is not necessary to use this
194 194 * notification callback mechanism.
195 195 */
196 196
197 197 /*
198 198 * Locking
199 199 * =======
200 200 * The use of CVW_* macros to do locking is driven by the need to allow
201 201 * recursive locking with read locks when we're processing packets. This
202 202 * is necessary because various netinfo functions need to hold read locks,
203 203 * by design, as they can be called in or out of packet context.
204 204 */
205 205 /*
206 206 * Hook internal functions
207 207 */
208 208 static hook_int_t *hook_copy(hook_t *src);
209 209 static hook_event_int_t *hook_event_checkdup(hook_event_t *he,
210 210 hook_stack_t *hks);
211 211 static hook_event_int_t *hook_event_copy(hook_event_t *src);
212 212 static hook_event_int_t *hook_event_find(hook_family_int_t *hfi, char *event);
213 213 static void hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi);
214 214 static hook_family_int_t *hook_family_copy(hook_family_t *src);
215 215 static hook_family_int_t *hook_family_find(char *family, hook_stack_t *hks);
216 216 static void hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks);
217 217 static hook_int_t *hook_find(hook_event_int_t *hei, hook_t *h);
218 218 static void hook_int_free(hook_int_t *hi, netstackid_t);
219 219 static void hook_init(void);
220 220 static void hook_fini(void);
221 221 static void *hook_stack_init(netstackid_t stackid, netstack_t *ns);
222 222 static void hook_stack_fini(netstackid_t stackid, void *arg);
223 223 static void hook_stack_shutdown(netstackid_t stackid, void *arg);
224 224 static int hook_insert(hook_int_head_t *head, hook_int_t *new);
225 225 static void hook_insert_plain(hook_int_head_t *head, hook_int_t *new);
226 226 static int hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new);
227 227 static hook_int_t *hook_find_byname(hook_int_head_t *head, char *name);
228 228 static void hook_event_init_kstats(hook_family_int_t *, hook_event_int_t *);
229 229 static void hook_event_notify_run(hook_event_int_t *, hook_family_int_t *,
230 230 char *event, char *name, hook_notify_cmd_t cmd);
231 231 static void hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei,
232 232 hook_int_t *hi);
233 233 static int hook_notify_register(hook_notify_head_t *head,
234 234 hook_notify_fn_t callback, void *arg);
235 235 static int hook_notify_unregister(hook_notify_head_t *head,
236 236 hook_notify_fn_t callback, void **);
237 237 static void hook_notify_run(hook_notify_head_t *head, char *family,
238 238 char *event, char *name, hook_notify_cmd_t cmd);
239 239 static void hook_stack_notify_run(hook_stack_t *hks, char *name,
240 240 hook_notify_cmd_t cmd);
241 241 static void hook_stack_remove(hook_stack_t *hks);
242 242
243 243 /*
244 244 * A list of the hook stacks is kept here because we need to enable
245 245 * net_instance_notify_register() to be called during the creation
246 246 * of a new instance. Previously hook_stack_get() would just use
247 247 * the netstack functions for this work but they will return NULL
248 248 * until the zone has been fully initialised.
249 249 */
250 250 static hook_stack_head_t hook_stacks;
251 251 static kmutex_t hook_stack_lock;
252 252
253 253 /*
254 254 * Module entry points.
255 255 */
256 256 int
257 257 _init(void)
258 258 {
259 259 int error;
260 260
261 261 hook_init();
262 262 error = mod_install(&modlinkage);
263 263 if (error != 0)
264 264 hook_fini();
265 265
266 266 return (error);
267 267 }
268 268
269 269 int
270 270 _fini(void)
271 271 {
272 272 int error;
273 273
274 274 error = mod_remove(&modlinkage);
275 275 if (error == 0)
276 276 hook_fini();
277 277
278 278 return (error);
279 279 }
280 280
281 281 int
282 282 _info(struct modinfo *modinfop)
283 283 {
284 284 return (mod_info(&modlinkage, modinfop));
285 285 }
286 286
287 287 /*
288 288 * Function: hook_init
289 289 * Returns: None
290 290 * Parameters: None
291 291 *
292 292 * Initialize hooks
293 293 */
294 294 static void
295 295 hook_init(void)
296 296 {
297 297 mutex_init(&hook_stack_lock, NULL, MUTEX_DRIVER, NULL);
298 298 SLIST_INIT(&hook_stacks);
299 299
300 300 /*
301 301 * We want to be informed each time a stack is created or
302 302 * destroyed in the kernel.
303 303 */
304 304 netstack_register(NS_HOOK, hook_stack_init, hook_stack_shutdown,
305 305 hook_stack_fini);
306 306 }
307 307
308 308 /*
309 309 * Function: hook_fini
310 310 * Returns: None
311 311 * Parameters: None
312 312 *
313 313 * Deinitialize hooks
314 314 */
315 315 static void
316 316 hook_fini(void)
317 317 {
318 318 netstack_unregister(NS_HOOK);
319 319
320 320 mutex_destroy(&hook_stack_lock);
321 321 ASSERT(SLIST_EMPTY(&hook_stacks));
322 322 }
323 323
324 324 /*
325 325 * Function: hook_wait_setflag
326 326 * Returns: -1 = setting flag is disallowed, 0 = flag set and did
327 327 * not have to wait (ie no lock droped), 1 = flag set but
328 328 * it was necessary to drop locks to set it.
329 329 * Parameters: waiter(I) - control data structure
330 330 * busyset(I) - set of flags that we don't want set while
331 331 * we are active.
332 332 * wanted(I) - flag associated with newflag to indicate
333 333 * what we want to do.
334 334 * newflag(I) - the new ACTIVE flag we want to set that
335 335 * indicates what we are doing.
336 336 *
337 337 * The set of functions hook_wait_* implement an API that builds on top of
338 338 * the kcondvar_t to provide controlled execution through a critical region.
339 339 * For each flag that indicates work is being done (FWF_*_ACTIVE) there is
340 340 * also a flag that we set to indicate that we want to do it (FWF_*_WANTED).
341 341 * The combination of flags is required as when this function exits to do
342 342 * the task, the structure is then free for another caller to use and
343 343 * to indicate that it wants to do work. The flags used when a caller wants
344 344 * to destroy an object take precedence over those that are used for making
345 345 * changes to it (add/remove.) In this case, we don't try to secure the
346 346 * ability to run and return with an error.
347 347 *
348 348 * "wantedset" is used here to determine who has the right to clear the
349 349 * wanted bit from the fw_flags set: only whomever sets the flag has the
350 350 * right to clear it at the bottom of the loop, even if someone else
351 351 * wants to set it.
352 352 *
353 353 * wanted - the FWF_*_WANTED flag that describes the action being requested
354 354 * busyset- the set of FWF_* flags we don't want set when we run
355 355 * newflag- the FWF_*_ACTIVE flag we will set to indicate we are busy
356 356 */
357 357 int
358 358 hook_wait_setflag(flagwait_t *waiter, uint32_t busyset, fwflag_t wanted,
359 359 fwflag_t newflag)
360 360 {
361 361 boolean_t wantedset;
362 362 int waited = 0;
363 363
364 364 mutex_enter(&waiter->fw_lock);
365 365 if (waiter->fw_flags & FWF_DESTROY) {
366 366 cv_signal(&waiter->fw_cv);
367 367 mutex_exit(&waiter->fw_lock);
368 368 return (-1);
369 369 }
370 370 while (waiter->fw_flags & busyset) {
371 371 wantedset = ((waiter->fw_flags & wanted) == wanted);
372 372 if (!wantedset)
373 373 waiter->fw_flags |= wanted;
374 374 CVW_EXIT_WRITE(waiter->fw_owner);
375 375 cv_wait(&waiter->fw_cv, &waiter->fw_lock);
376 376 /*
377 377 * This lock needs to be dropped here to preserve the order
378 378 * of acquisition that is fw_owner followed by fw_lock, else
379 379 * we can deadlock.
380 380 */
381 381 mutex_exit(&waiter->fw_lock);
382 382 waited = 1;
383 383 CVW_ENTER_WRITE(waiter->fw_owner);
384 384 mutex_enter(&waiter->fw_lock);
385 385 if (!wantedset)
386 386 waiter->fw_flags &= ~wanted;
387 387 if (waiter->fw_flags & FWF_DESTROY) {
388 388 cv_signal(&waiter->fw_cv);
389 389 mutex_exit(&waiter->fw_lock);
390 390 return (-1);
391 391 }
392 392 }
393 393 waiter->fw_flags &= ~wanted;
394 394 ASSERT((waiter->fw_flags & wanted) == 0);
395 395 ASSERT((waiter->fw_flags & newflag) == 0);
396 396 waiter->fw_flags |= newflag;
397 397 mutex_exit(&waiter->fw_lock);
398 398 return (waited);
399 399 }
400 400
401 401 /*
402 402 * Function: hook_wait_unsetflag
403 403 * Returns: None
404 404 * Parameters: waiter(I) - control data structure
405 405 * oldflag(I) - flag to reset
406 406 *
407 407 * Turn off the bit that we had set to run and let others know that
408 408 * they should now check to see if they can run.
409 409 */
410 410 void
411 411 hook_wait_unsetflag(flagwait_t *waiter, fwflag_t oldflag)
412 412 {
413 413 mutex_enter(&waiter->fw_lock);
414 414 waiter->fw_flags &= ~oldflag;
415 415 cv_signal(&waiter->fw_cv);
416 416 mutex_exit(&waiter->fw_lock);
417 417 }
418 418
419 419 /*
420 420 * Function: hook_wait_destroy
421 421 * Returns: None
422 422 * Parameters: waiter(I) - control data structure
423 423 *
424 424 * Since outer locking (on fw_owner) should ensure that only one function
425 425 * at a time gets to call hook_wait_destroy() on a given object, there is
426 426 * no need to guard against setting FWF_DESTROY_WANTED already being set.
427 427 * It is, however, necessary to wait for all activity on the owning
428 428 * structure to cease.
429 429 */
430 430 int
431 431 hook_wait_destroy(flagwait_t *waiter)
432 432 {
433 433 ASSERT((waiter->fw_flags & FWF_DESTROY_WANTED) == 0);
434 434 mutex_enter(&waiter->fw_lock);
435 435 if (waiter->fw_flags & FWF_DESTROY_WANTED) {
436 436 cv_signal(&waiter->fw_cv);
437 437 mutex_exit(&waiter->fw_lock);
438 438 return (EINPROGRESS);
439 439 }
440 440 waiter->fw_flags |= FWF_DESTROY_WANTED;
441 441 while (!FWF_DESTROY_OK(waiter)) {
442 442 CVW_EXIT_WRITE(waiter->fw_owner);
443 443 cv_wait(&waiter->fw_cv, &waiter->fw_lock);
444 444 CVW_ENTER_WRITE(waiter->fw_owner);
445 445 }
446 446 /*
447 447 * There should now be nothing else using "waiter" or its
448 448 * owner, so we can safely assign here without risk of wiiping
449 449 * out someone's bit.
450 450 */
451 451 waiter->fw_flags = FWF_DESTROY_ACTIVE;
452 452 cv_signal(&waiter->fw_cv);
453 453 mutex_exit(&waiter->fw_lock);
454 454
455 455 return (0);
456 456 }
457 457
458 458 /*
459 459 * Function: hook_wait_init
460 460 * Returns: None
461 461 * Parameters: waiter(I) - control data structure
462 462 * ownder(I) - pointer to lock that the owner of this
463 463 * waiter uses
464 464 *
465 465 * "owner" gets passed in here so that when we need to call cv_wait,
466 466 * for example in hook_wait_setflag(), we can drop the lock for the
467 467 * next layer out, which is likely to be held in an exclusive manner.
468 468 */
469 469 void
470 470 hook_wait_init(flagwait_t *waiter, cvwaitlock_t *owner)
471 471 {
472 472 cv_init(&waiter->fw_cv, NULL, CV_DRIVER, NULL);
473 473 mutex_init(&waiter->fw_lock, NULL, MUTEX_DRIVER, NULL);
474 474 waiter->fw_flags = FWF_NONE;
475 475 waiter->fw_owner = owner;
476 476 }
477 477
478 478 /*
479 479 * Function: hook_stack_init
480 480 * Returns: void * - pointer to new hook stack structure
481 481 * Parameters: stackid(I) - identifier for the network instance that owns this
482 482 * ns(I) - pointer to the network instance data structure
483 483 *
484 484 * Allocate and initialize the hook stack instance. This function is not
485 485 * allowed to fail, so KM_SLEEP is used here when allocating memory. The
486 486 * value returned is passed back into the shutdown and destroy hooks.
487 487 */
488 488 /*ARGSUSED*/
489 489 static void *
490 490 hook_stack_init(netstackid_t stackid, netstack_t *ns)
491 491 {
492 492 hook_stack_t *hks;
493 493
494 494 #ifdef NS_DEBUG
495 495 printf("hook_stack_init(stack %d)\n", stackid);
496 496 #endif
497 497
498 498 hks = (hook_stack_t *)kmem_zalloc(sizeof (*hks), KM_SLEEP);
499 499 hks->hks_netstack = ns;
500 500 hks->hks_netstackid = stackid;
501 501
502 502 CVW_INIT(&hks->hks_lock);
503 503 TAILQ_INIT(&hks->hks_nhead);
504 504 SLIST_INIT(&hks->hks_familylist);
505 505
506 506 hook_wait_init(&hks->hks_waiter, &hks->hks_lock);
507 507
508 508 mutex_enter(&hook_stack_lock);
509 509 SLIST_INSERT_HEAD(&hook_stacks, hks, hks_entry);
510 510 mutex_exit(&hook_stack_lock);
511 511
512 512 return (hks);
513 513 }
514 514
515 515 /*
516 516 * Function: hook_stack_shutdown
517 517 * Returns: void
518 518 * Parameters: stackid(I) - identifier for the network instance that owns this
519 519 * arg(I) - pointer returned by hook_stack_init
520 520 *
521 521 * Set the shutdown flag to indicate that we should stop accepting new
522 522 * register calls as we're now in the cleanup process. The cleanup is a
523 523 * two stage process and we're not required to free any memory here.
524 524 *
525 525 * The curious would wonder why isn't there any code that walks through
526 526 * all of the data structures and sets the flag(s) there? The answer is
527 527 * that it is expected that this will happen when the zone shutdown calls
528 528 * the shutdown callbacks for other modules that they will initiate the
529 529 * free'ing and shutdown of the hooks themselves.
530 530 */
531 531 /*ARGSUSED*/
532 532 static void
533 533 hook_stack_shutdown(netstackid_t stackid, void *arg)
534 534 {
535 535 hook_stack_t *hks = (hook_stack_t *)arg;
536 536
537 537 mutex_enter(&hook_stack_lock);
538 538 /*
539 539 * Once this flag gets set to one, no more additions are allowed
540 540 * to any of the structures that make up this stack.
541 541 */
542 542 hks->hks_shutdown = 1;
543 543 mutex_exit(&hook_stack_lock);
544 544 }
545 545
546 546 /*
547 547 * Function: hook_stack_destroy
548 548 * Returns: void
549 549 * Parameters: stackid(I) - identifier for the network instance that owns this
550 550 * arg(I) - pointer returned by hook_stack_init
551 551 *
552 552 * Free the hook stack instance.
553 553 *
554 554 * The rationale for the shutdown being lazy (see the comment above for
555 555 * hook_stack_shutdown) also applies to the destroy being lazy. Only if
556 556 * the hook_stack_t data structure is unused will it go away. Else it
557 557 * is left up to the last user of a data structure to actually free it.
558 558 */
559 559 /*ARGSUSED*/
560 560 static void
561 561 hook_stack_fini(netstackid_t stackid, void *arg)
562 562 {
563 563 hook_stack_t *hks = (hook_stack_t *)arg;
564 564
565 565 mutex_enter(&hook_stack_lock);
566 566 hks->hks_shutdown = 2;
567 567 hook_stack_remove(hks);
568 568 mutex_exit(&hook_stack_lock);
569 569 }
570 570
571 571 /*
572 572 * Function: hook_stack_remove
573 573 * Returns: void
574 574 * Parameters: hks(I) - pointer to an instance of a hook_stack_t
575 575 *
576 576 * This function assumes that it is called with hook_stack_lock held.
577 577 * It functions differently to hook_family/event_remove in that it does
578 578 * the checks to see if it can be removed. This difference exists
579 579 * because this structure has nothing higher up that depends on it.
580 580 */
581 581 static void
582 582 hook_stack_remove(hook_stack_t *hks)
583 583 {
584 584
585 585 ASSERT(mutex_owned(&hook_stack_lock));
586 586
587 587 /*
588 588 * Is the structure still in use?
589 589 */
590 590 if (!SLIST_EMPTY(&hks->hks_familylist) ||
591 591 !TAILQ_EMPTY(&hks->hks_nhead))
592 592 return;
593 593
594 594 SLIST_REMOVE(&hook_stacks, hks, hook_stack, hks_entry);
595 595
596 596 VERIFY(hook_wait_destroy(&hks->hks_waiter) == 0);
597 597 CVW_DESTROY(&hks->hks_lock);
598 598 kmem_free(hks, sizeof (*hks));
599 599 }
600 600
601 601 /*
602 602 * Function: hook_stack_get
603 603 * Returns: hook_stack_t * - NULL if not found, else matching instance
604 604 * Parameters: stackid(I) - instance id to search for
605 605 *
606 606 * Search the list of currently active hook_stack_t structures for one that
607 607 * has a matching netstackid_t to the value passed in. The linked list can
608 608 * only ever have at most one match for this value.
609 609 */
610 610 static hook_stack_t *
611 611 hook_stack_get(netstackid_t stackid)
612 612 {
613 613 hook_stack_t *hks;
614 614
615 615 SLIST_FOREACH(hks, &hook_stacks, hks_entry) {
616 616 if (hks->hks_netstackid == stackid)
617 617 break;
618 618 }
619 619
620 620 return (hks);
621 621 }
622 622
623 623 /*
624 624 * Function: hook_stack_notify_register
625 625 * Returns: int - 0 = success, else failure
626 626 * Parameters: stackid(I) - netstack identifier
627 627 * callback(I)- function to be called
628 628 * arg(I) - arg to provide callback when it is called
629 629 *
630 630 * If we're not shutting down this instance, append a new function to the
631 631 * list of those to call when a new family of hooks is added to this stack.
632 632 * If the function can be successfully added to the list of callbacks
633 633 * activated when there is a change to the stack (addition or removal of
634 634 * a hook family) then generate a fake HN_REGISTER event by directly
635 635 * calling the callback with the relevant information for each hook
636 636 * family that currently exists (and isn't being shutdown.)
637 637 */
638 638 int
639 639 hook_stack_notify_register(netstackid_t stackid, hook_notify_fn_t callback,
640 640 void *arg)
641 641 {
642 642 hook_family_int_t *hfi;
643 643 hook_stack_t *hks;
644 644 boolean_t canrun;
645 645 char buffer[16];
646 646 int error;
647 647
648 648 ASSERT(callback != NULL);
649 649
650 650 canrun = B_FALSE;
651 651 mutex_enter(&hook_stack_lock);
652 652 hks = hook_stack_get(stackid);
653 653 if (hks != NULL) {
654 654 if (hks->hks_shutdown != 0) {
655 655 error = ESHUTDOWN;
656 656 } else {
657 657 CVW_ENTER_WRITE(&hks->hks_lock);
658 658 canrun = (hook_wait_setflag(&hks->hks_waiter,
659 659 FWF_ADD_WAIT_MASK, FWF_ADD_WANTED,
660 660 FWF_ADD_ACTIVE) != -1);
661 661 error = hook_notify_register(&hks->hks_nhead,
662 662 callback, arg);
663 663 CVW_EXIT_WRITE(&hks->hks_lock);
664 664 }
665 665 } else {
666 666 error = ESRCH;
667 667 }
668 668 mutex_exit(&hook_stack_lock);
669 669
670 670 if (error == 0 && canrun) {
671 671 /*
672 672 * Generate fake register event for callback that
673 673 * is being added, letting it know everything that
674 674 * already exists.
675 675 */
676 676 (void) snprintf(buffer, sizeof (buffer), "%u",
677 677 hks->hks_netstackid);
678 678
679 679 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
680 680 if (hfi->hfi_condemned || hfi->hfi_shutdown)
681 681 continue;
682 682 callback(HN_REGISTER, arg, buffer, NULL,
683 683 hfi->hfi_family.hf_name);
684 684 }
685 685 }
686 686
687 687 if (canrun)
688 688 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
689 689
690 690 return (error);
691 691 }
692 692
693 693 /*
694 694 * Function: hook_stack_notify_unregister
695 695 * Returns: int - 0 = success, else failure
696 696 * Parameters: stackid(I) - netstack identifier
697 697 * callback(I) - function to be called
698 698 *
699 699 * Attempt to remove a registered function from a hook stack's list of
|
↓ open down ↓ |
664 lines elided |
↑ open up ↑ |
700 700 * callbacks to activiate when protocols are added/deleted.
701 701 * As with hook_stack_notify_register, if all things are going well then
702 702 * a fake unregister event is delivered to the callback being removed
703 703 * for each hook family that presently exists.
704 704 */
705 705 int
706 706 hook_stack_notify_unregister(netstackid_t stackid, hook_notify_fn_t callback)
707 707 {
708 708 hook_family_int_t *hfi;
709 709 hook_stack_t *hks;
710 - boolean_t canrun;
711 710 char buffer[16];
712 711 void *arg;
713 712 int error;
714 713
715 714 mutex_enter(&hook_stack_lock);
716 715 hks = hook_stack_get(stackid);
717 - if (hks != NULL) {
718 - CVW_ENTER_WRITE(&hks->hks_lock);
719 - canrun = (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK,
720 - FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
716 + if (hks == NULL) {
717 + mutex_exit(&hook_stack_lock);
718 + return (ESRCH);
719 + }
721 720
722 - error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
721 + CVW_ENTER_WRITE(&hks->hks_lock);
722 + /*
723 + * If hook_wait_setflag returns -1, another thread has flagged that it
724 + * is attempting to destroy this hook stack. Before it can flag that
725 + * it's destroying the hook stack, it must first verify (with
726 + * hook_stack_lock held) that the hook stack is empty. If we
727 + * encounter this, it means we should have nothing to do and we
728 + * just snuck in.
729 + */
730 + if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
731 + FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
732 + VERIFY(TAILQ_EMPTY(&hks->hks_nhead));
723 733 CVW_EXIT_WRITE(&hks->hks_lock);
724 - } else {
725 - error = ESRCH;
734 + mutex_exit(&hook_stack_lock);
735 + return (ESRCH);
726 736 }
737 +
738 + error = hook_notify_unregister(&hks->hks_nhead, callback, &arg);
739 + CVW_EXIT_WRITE(&hks->hks_lock);
727 740 mutex_exit(&hook_stack_lock);
728 741
729 742 if (error == 0) {
730 - if (canrun) {
731 - /*
732 - * Generate fake unregister event for callback that
733 - * is being removed, letting it know everything that
734 - * currently exists is now "disappearing."
735 - */
736 - (void) snprintf(buffer, sizeof (buffer), "%u",
737 - hks->hks_netstackid);
743 + /*
744 + * Generate fake unregister event for callback that
745 + * is being removed, letting it know everything that
746 + * currently exists is now "disappearing."
747 + */
748 + (void) snprintf(buffer, sizeof (buffer), "%u",
749 + hks->hks_netstackid);
738 750
739 - SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
740 - callback(HN_UNREGISTER, arg, buffer, NULL,
741 - hfi->hfi_family.hf_name);
742 - }
743 -
744 - hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
751 + SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
752 + callback(HN_UNREGISTER, arg, buffer, NULL,
753 + hfi->hfi_family.hf_name);
745 754 }
746 -
747 - mutex_enter(&hook_stack_lock);
748 - hks = hook_stack_get(stackid);
749 - if ((error == 0) && (hks->hks_shutdown == 2))
750 - hook_stack_remove(hks);
751 - mutex_exit(&hook_stack_lock);
755 + } else {
756 + /*
757 + * hook_notify_unregister() should only fail if the callback has
758 + * already been deleted (ESRCH).
759 + */
760 + VERIFY3S(error, ==, ESRCH);
752 761 }
753 762
763 + mutex_enter(&hook_stack_lock);
764 + hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
765 + if (hks->hks_shutdown == 2)
766 + hook_stack_remove(hks);
767 + mutex_exit(&hook_stack_lock);
768 +
754 769 return (error);
755 770 }
756 771
757 772 /*
758 773 * Function: hook_stack_notify_run
759 774 * Returns: None
760 775 * Parameters: hks(I) - hook stack pointer to execute callbacks for
761 776 * name(I) - name of a hook family
762 777 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
763 778 *
764 779 * Run through the list of callbacks on the hook stack to be called when
765 780 * a new hook family is added
766 781 *
767 782 * As hook_notify_run() expects 3 names, one for the family that is associated
768 783 * with the cmd (HN_REGISTER or HN_UNREGISTER), one for the event and one
769 784 * for the object being introduced and we really only have one name (that
770 785 * of the new hook family), fake the hook stack's name by converting the
771 786 * integer to a string and for the event just pass NULL.
772 787 */
773 788 static void
774 789 hook_stack_notify_run(hook_stack_t *hks, char *name,
775 790 hook_notify_cmd_t cmd)
776 791 {
777 792 char buffer[16];
778 793
779 794 ASSERT(hks != NULL);
780 795 ASSERT(name != NULL);
781 796
782 797 (void) snprintf(buffer, sizeof (buffer), "%u", hks->hks_netstackid);
783 798
784 799 hook_notify_run(&hks->hks_nhead, buffer, NULL, name, cmd);
785 800 }
786 801
787 802 /*
788 803 * Function: hook_run
789 804 * Returns: int - return value according to callback func
790 805 * Parameters: token(I) - event pointer
791 806 * info(I) - message
792 807 *
793 808 * Run hooks for specific provider. The hooks registered are stepped through
794 809 * until either the end of the list is reached or a hook function returns a
795 810 * non-zero value. If a non-zero value is returned from a hook function, we
796 811 * return that value back to our caller. By design, a hook function can be
797 812 * called more than once, simultaneously.
798 813 */
799 814 int
800 815 hook_run(hook_family_int_t *hfi, hook_event_token_t token, hook_data_t info)
801 816 {
802 817 hook_event_int_t *hei;
803 818 hook_int_t *hi;
804 819 int rval = 0;
805 820
806 821 ASSERT(token != NULL);
807 822
808 823 hei = (hook_event_int_t *)token;
809 824 DTRACE_PROBE2(hook__run__start,
810 825 hook_event_token_t, token,
811 826 hook_data_t, info);
812 827
813 828 /*
814 829 * If we consider that this function is only called from within the
815 830 * stack while an instance is currently active,
816 831 */
817 832 CVW_ENTER_READ(&hfi->hfi_lock);
818 833
819 834 TAILQ_FOREACH(hi, &hei->hei_head, hi_entry) {
820 835 ASSERT(hi->hi_hook.h_func != NULL);
821 836 DTRACE_PROBE3(hook__func__start,
822 837 hook_event_token_t, token,
823 838 hook_data_t, info,
824 839 hook_int_t *, hi);
825 840 rval = (*hi->hi_hook.h_func)(token, info, hi->hi_hook.h_arg);
826 841 DTRACE_PROBE4(hook__func__end,
827 842 hook_event_token_t, token,
828 843 hook_data_t, info,
829 844 hook_int_t *, hi,
830 845 int, rval);
831 846 hi->hi_kstats.hook_hits.value.ui64++;
832 847 if (rval != 0)
833 848 break;
834 849 }
835 850
836 851 hei->hei_kstats.events.value.ui64++;
837 852
838 853 CVW_EXIT_READ(&hfi->hfi_lock);
839 854
840 855 DTRACE_PROBE3(hook__run__end,
841 856 hook_event_token_t, token,
842 857 hook_data_t, info,
843 858 hook_int_t *, hi);
844 859
845 860 return (rval);
846 861 }
847 862
848 863 /*
849 864 * Function: hook_family_add
850 865 * Returns: internal family pointer - NULL = Fail
851 866 * Parameters: hf(I) - family pointer
852 867 * hks(I) - pointer to an instance of a hook_stack_t
853 868 * store(O) - where returned pointer will be stored
854 869 *
855 870 * Add new family to the family list. The requirements for the addition to
856 871 * succeed are that the family name must not already be registered and that
857 872 * the hook stack is not being shutdown.
858 873 * If store is non-NULL, it is expected to be a pointer to the same variable
859 874 * that is awaiting to be assigned the return value of this function.
860 875 * In its current use, the returned value is assigned to netd_hooks in
861 876 * net_family_register. The use of "store" allows the return value to be
862 877 * used before this function returns. How can this happen? Through the
863 878 * callbacks that can be activated at the bottom of this function, when
864 879 * hook_stack_notify_run is called.
865 880 */
866 881 hook_family_int_t *
867 882 hook_family_add(hook_family_t *hf, hook_stack_t *hks, void **store)
868 883 {
869 884 hook_family_int_t *hfi, *new;
870 885
871 886 ASSERT(hf != NULL);
872 887 ASSERT(hf->hf_name != NULL);
873 888
874 889 new = hook_family_copy(hf);
875 890 if (new == NULL)
876 891 return (NULL);
877 892
878 893 mutex_enter(&hook_stack_lock);
879 894 CVW_ENTER_WRITE(&hks->hks_lock);
880 895
881 896 if (hks->hks_shutdown != 0) {
882 897 CVW_EXIT_WRITE(&hks->hks_lock);
883 898 mutex_exit(&hook_stack_lock);
884 899 hook_family_free(new, NULL);
885 900 return (NULL);
886 901 }
887 902
888 903 /* search family list */
889 904 hfi = hook_family_find(hf->hf_name, hks);
890 905 if (hfi != NULL) {
891 906 CVW_EXIT_WRITE(&hks->hks_lock);
892 907 mutex_exit(&hook_stack_lock);
893 908 hook_family_free(new, NULL);
894 909 return (NULL);
895 910 }
896 911
897 912 /*
898 913 * Try and set the FWF_ADD_ACTIVE flag so that we can drop all the
899 914 * lock further down when calling all of the functions registered
900 915 * for notification when a new hook family is added.
901 916 */
902 917 if (hook_wait_setflag(&hks->hks_waiter, FWF_ADD_WAIT_MASK,
903 918 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
904 919 CVW_EXIT_WRITE(&hks->hks_lock);
905 920 mutex_exit(&hook_stack_lock);
906 921 hook_family_free(new, NULL);
907 922 return (NULL);
908 923 }
909 924
910 925 CVW_INIT(&new->hfi_lock);
911 926 SLIST_INIT(&new->hfi_head);
912 927 TAILQ_INIT(&new->hfi_nhead);
913 928
914 929 hook_wait_init(&new->hfi_waiter, &new->hfi_lock);
915 930
916 931 new->hfi_stack = hks;
917 932 if (store != NULL)
918 933 *store = new;
919 934
920 935 /* Add to family list head */
921 936 SLIST_INSERT_HEAD(&hks->hks_familylist, new, hfi_entry);
922 937
923 938 CVW_EXIT_WRITE(&hks->hks_lock);
924 939 mutex_exit(&hook_stack_lock);
925 940
926 941 hook_stack_notify_run(hks, hf->hf_name, HN_REGISTER);
927 942
928 943 hook_wait_unsetflag(&hks->hks_waiter, FWF_ADD_ACTIVE);
929 944
930 945 return (new);
931 946 }
932 947
933 948 /*
934 949 * Function: hook_family_remove
935 950 * Returns: int - 0 = success, else = failure
936 951 * Parameters: hfi(I) - internal family pointer
937 952 *
938 953 * Remove family from family list. This function has been designed to be
939 954 * called once and once only per hook_family_int_t. Thus when cleaning up
940 955 * this structure as an orphan, callers should only call hook_family_free.
941 956 */
942 957 int
943 958 hook_family_remove(hook_family_int_t *hfi)
944 959 {
945 960 hook_stack_t *hks;
946 961 boolean_t notifydone;
947 962
948 963 ASSERT(hfi != NULL);
949 964 hks = hfi->hfi_stack;
950 965
951 966 CVW_ENTER_WRITE(&hfi->hfi_lock);
952 967 notifydone = hfi->hfi_shutdown;
953 968 hfi->hfi_shutdown = B_TRUE;
954 969 CVW_EXIT_WRITE(&hfi->hfi_lock);
955 970
956 971 CVW_ENTER_WRITE(&hks->hks_lock);
957 972
958 973 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
959 974 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
960 975 /*
961 976 * If we're trying to destroy the hook_stack_t...
962 977 */
963 978 CVW_EXIT_WRITE(&hks->hks_lock);
964 979 return (ENXIO);
965 980 }
966 981
967 982 /*
968 983 * Check if the family is in use by the presence of either events
969 984 * or notify callbacks on the hook family.
970 985 */
971 986 if (!SLIST_EMPTY(&hfi->hfi_head) || !TAILQ_EMPTY(&hfi->hfi_nhead)) {
972 987 hfi->hfi_condemned = B_TRUE;
973 988 } else {
974 989 VERIFY(hook_wait_destroy(&hfi->hfi_waiter) == 0);
975 990 /*
976 991 * Although hfi_condemned = B_FALSE is implied from creation,
977 992 * putting a comment here inside the else upsets lint.
978 993 */
979 994 hfi->hfi_condemned = B_FALSE;
980 995 }
981 996 CVW_EXIT_WRITE(&hks->hks_lock);
982 997
983 998 if (!notifydone)
984 999 hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
985 1000 HN_UNREGISTER);
986 1001
987 1002 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
988 1003
989 1004 /*
990 1005 * If we don't have to wait for anything else to disappear from this
991 1006 * structure then we can free it up.
992 1007 */
993 1008 if (!hfi->hfi_condemned)
994 1009 hook_family_free(hfi, hks);
995 1010
996 1011 return (0);
997 1012 }
998 1013
999 1014
1000 1015 /*
1001 1016 * Function: hook_family_free
1002 1017 * Returns: None
1003 1018 * Parameters: hfi(I) - internal family pointer
1004 1019 *
1005 1020 * Free alloc memory for family
1006 1021 */
1007 1022 static void
1008 1023 hook_family_free(hook_family_int_t *hfi, hook_stack_t *hks)
1009 1024 {
1010 1025
1011 1026 /*
1012 1027 * This lock gives us possession of the hks pointer after the
1013 1028 * SLIST_REMOVE, for which it is not needed, when hks_shutdown
1014 1029 * is checked and hook_stack_remove called.
1015 1030 */
1016 1031 mutex_enter(&hook_stack_lock);
1017 1032
1018 1033 ASSERT(hfi != NULL);
1019 1034
1020 1035 if (hks != NULL) {
1021 1036 CVW_ENTER_WRITE(&hks->hks_lock);
1022 1037 /* Remove from family list */
1023 1038 SLIST_REMOVE(&hks->hks_familylist, hfi, hook_family_int,
1024 1039 hfi_entry);
1025 1040
1026 1041 CVW_EXIT_WRITE(&hks->hks_lock);
1027 1042 }
1028 1043
1029 1044 /* Free name space */
1030 1045 if (hfi->hfi_family.hf_name != NULL) {
1031 1046 kmem_free(hfi->hfi_family.hf_name,
1032 1047 strlen(hfi->hfi_family.hf_name) + 1);
1033 1048 }
1034 1049
1035 1050 /* Free container */
1036 1051 kmem_free(hfi, sizeof (*hfi));
1037 1052
1038 1053 if (hks->hks_shutdown == 2)
1039 1054 hook_stack_remove(hks);
1040 1055
1041 1056 mutex_exit(&hook_stack_lock);
1042 1057 }
1043 1058
1044 1059 /*
1045 1060 * Function: hook_family_shutdown
1046 1061 * Returns: int - 0 = success, else = failure
1047 1062 * Parameters: hfi(I) - internal family pointer
1048 1063 *
1049 1064 * As an alternative to removing a family, we may desire to just generate
1050 1065 * a series of callbacks to indicate that we will be going away in the
1051 1066 * future. The hfi_condemned flag isn't set because we aren't trying to
1052 1067 * remove the structure.
1053 1068 */
1054 1069 int
1055 1070 hook_family_shutdown(hook_family_int_t *hfi)
1056 1071 {
1057 1072 hook_stack_t *hks;
1058 1073 boolean_t notifydone;
1059 1074
1060 1075 ASSERT(hfi != NULL);
1061 1076 hks = hfi->hfi_stack;
1062 1077
1063 1078 CVW_ENTER_WRITE(&hfi->hfi_lock);
1064 1079 notifydone = hfi->hfi_shutdown;
1065 1080 hfi->hfi_shutdown = B_TRUE;
1066 1081 CVW_EXIT_WRITE(&hfi->hfi_lock);
1067 1082
1068 1083 CVW_ENTER_WRITE(&hks->hks_lock);
1069 1084
1070 1085 if (hook_wait_setflag(&hks->hks_waiter, FWF_DEL_WAIT_MASK,
1071 1086 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1072 1087 /*
1073 1088 * If we're trying to destroy the hook_stack_t...
1074 1089 */
1075 1090 CVW_EXIT_WRITE(&hks->hks_lock);
1076 1091 return (ENXIO);
1077 1092 }
1078 1093
1079 1094 CVW_EXIT_WRITE(&hks->hks_lock);
1080 1095
1081 1096 if (!notifydone)
1082 1097 hook_stack_notify_run(hks, hfi->hfi_family.hf_name,
1083 1098 HN_UNREGISTER);
1084 1099
1085 1100 hook_wait_unsetflag(&hks->hks_waiter, FWF_DEL_ACTIVE);
1086 1101
1087 1102 return (0);
1088 1103 }
1089 1104
1090 1105 /*
1091 1106 * Function: hook_family_copy
1092 1107 * Returns: internal family pointer - NULL = Failed
1093 1108 * Parameters: src(I) - family pointer
1094 1109 *
1095 1110 * Allocate internal family block and duplicate incoming family
1096 1111 * No locks should be held across this function as it may sleep.
1097 1112 */
1098 1113 static hook_family_int_t *
1099 1114 hook_family_copy(hook_family_t *src)
1100 1115 {
1101 1116 hook_family_int_t *new;
1102 1117 hook_family_t *dst;
1103 1118
1104 1119 ASSERT(src != NULL);
1105 1120 ASSERT(src->hf_name != NULL);
1106 1121
1107 1122 new = (hook_family_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
1108 1123
1109 1124 /* Copy body */
1110 1125 dst = &new->hfi_family;
1111 1126 *dst = *src;
1112 1127
1113 1128 SLIST_INIT(&new->hfi_head);
1114 1129 TAILQ_INIT(&new->hfi_nhead);
1115 1130
1116 1131 /* Copy name */
1117 1132 dst->hf_name = (char *)kmem_alloc(strlen(src->hf_name) + 1, KM_SLEEP);
1118 1133 (void) strcpy(dst->hf_name, src->hf_name);
|
↓ open down ↓ |
355 lines elided |
↑ open up ↑ |
1119 1134
1120 1135 return (new);
1121 1136 }
1122 1137
1123 1138 /*
1124 1139 * Function: hook_family_find
1125 1140 * Returns: internal family pointer - NULL = Not match
1126 1141 * Parameters: family(I) - family name string
1127 1142 *
1128 1143 * Search family list with family name
1129 - * A lock on hfi_lock must be held when called.
1144 + * A lock on hfi_lock must be held when called.
1130 1145 */
1131 1146 static hook_family_int_t *
1132 1147 hook_family_find(char *family, hook_stack_t *hks)
1133 1148 {
1134 1149 hook_family_int_t *hfi = NULL;
1135 1150
1136 1151 ASSERT(family != NULL);
1137 1152
1138 1153 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
1139 1154 if (strcmp(hfi->hfi_family.hf_name, family) == 0)
1140 1155 break;
1141 1156 }
1142 1157 return (hfi);
1143 1158 }
1144 1159
1145 1160 /*
1146 1161 * Function: hook_family_notify_register
1147 1162 * Returns: int - 0 = success, else failure
1148 1163 * Parameters: hfi(I) - hook family
1149 1164 * callback(I) - function to be called
1150 1165 * arg(I) - arg to provide callback when it is called
1151 1166 *
1152 1167 * So long as this hook stack isn't being shut down, register a new
1153 1168 * callback to be activated each time a new event is added to this
1154 1169 * family.
1155 1170 *
1156 1171 * To call this function we must have an active handle in use on the family,
1157 1172 * so if we take this into account, then neither the hook_family_int_t nor
1158 1173 * the hook_stack_t that owns it can disappear. We have to put some trust
1159 1174 * in the callers to be properly synchronised...
1160 1175 *
1161 1176 * Holding hks_lock is required to provide synchronisation for hks_shutdown.
1162 1177 */
1163 1178 int
1164 1179 hook_family_notify_register(hook_family_int_t *hfi,
1165 1180 hook_notify_fn_t callback, void *arg)
1166 1181 {
1167 1182 hook_event_int_t *hei;
1168 1183 hook_stack_t *hks;
1169 1184 boolean_t canrun;
1170 1185 int error;
1171 1186
1172 1187 ASSERT(hfi != NULL);
1173 1188 canrun = B_FALSE;
1174 1189 hks = hfi->hfi_stack;
1175 1190
1176 1191 CVW_ENTER_READ(&hks->hks_lock);
1177 1192
1178 1193 if ((hfi->hfi_stack->hks_shutdown != 0) ||
1179 1194 hfi->hfi_condemned || hfi->hfi_shutdown) {
1180 1195 CVW_EXIT_READ(&hks->hks_lock);
1181 1196 return (ESHUTDOWN);
1182 1197 }
1183 1198
1184 1199 CVW_ENTER_WRITE(&hfi->hfi_lock);
1185 1200 canrun = (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
1186 1201 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1187 1202 error = hook_notify_register(&hfi->hfi_nhead, callback, arg);
1188 1203 CVW_EXIT_WRITE(&hfi->hfi_lock);
1189 1204
1190 1205 CVW_EXIT_READ(&hks->hks_lock);
1191 1206
1192 1207 if (error == 0 && canrun) {
1193 1208 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1194 1209 callback(HN_REGISTER, arg,
1195 1210 hfi->hfi_family.hf_name, NULL,
1196 1211 hei->hei_event->he_name);
1197 1212 }
1198 1213 }
1199 1214
1200 1215 if (canrun)
1201 1216 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1202 1217
1203 1218 return (error);
1204 1219 }
1205 1220
1206 1221 /*
1207 1222 * Function: hook_family_notify_unregister
1208 1223 * Returns: int - 0 = success, else failure
1209 1224 * Parameters: hfi(I) - hook family
1210 1225 * callback(I) - function to be called
1211 1226 *
1212 1227 * Remove a callback from the list of those executed when a new event is
1213 1228 * added to a hook family. If the family is not in the process of being
1214 1229 * destroyed then simulate an unregister callback for each event that is
1215 1230 * on the family. This pairs up with the hook_family_notify_register
1216 1231 * action that simulates register events.
1217 1232 * The order of what happens here is important and goes like this.
1218 1233 * 1) Remove the callback from the list of functions to be called as part
1219 1234 * of the notify operation when an event is added or removed from the
1220 1235 * hook family.
1221 1236 * 2) If the hook_family_int_t structure is on death row (free_family will
1222 1237 * be set to true) then there's nothing else to do than let it be free'd.
1223 1238 * 3) If the structure isn't about to die, mark it up as being busy using
1224 1239 * hook_wait_setflag and then drop the lock so the loop can be run.
1225 1240 * 4) if hook_wait_setflag was successful, tell all of the notify callback
1226 1241 * functions that this family has been unregistered.
1227 1242 * 5) Cleanup
1228 1243 */
1229 1244 int
1230 1245 hook_family_notify_unregister(hook_family_int_t *hfi,
1231 1246 hook_notify_fn_t callback)
1232 1247 {
1233 1248 hook_event_int_t *hei;
1234 1249 boolean_t free_family;
1235 1250 boolean_t canrun;
1236 1251 int error;
1237 1252 void *arg;
1238 1253
1239 1254 canrun = B_FALSE;
1240 1255
1241 1256 CVW_ENTER_WRITE(&hfi->hfi_lock);
1242 1257
1243 1258 (void) hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
1244 1259 FWF_DEL_WANTED, FWF_DEL_ACTIVE);
1245 1260
1246 1261 error = hook_notify_unregister(&hfi->hfi_nhead, callback, &arg);
1247 1262
1248 1263 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1249 1264
1250 1265 /*
1251 1266 * If hook_family_remove has been called but the structure was still
1252 1267 * "busy" ... but we might have just made it "unbusy"...
1253 1268 */
1254 1269 if ((error == 0) && hfi->hfi_condemned &&
1255 1270 SLIST_EMPTY(&hfi->hfi_head) && TAILQ_EMPTY(&hfi->hfi_nhead)) {
1256 1271 free_family = B_TRUE;
1257 1272 } else {
1258 1273 free_family = B_FALSE;
1259 1274 }
1260 1275
1261 1276 if (error == 0 && !free_family) {
1262 1277 canrun = (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
1263 1278 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1264 1279 }
1265 1280
1266 1281 CVW_EXIT_WRITE(&hfi->hfi_lock);
1267 1282
1268 1283 if (canrun) {
1269 1284 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1270 1285 callback(HN_UNREGISTER, arg,
1271 1286 hfi->hfi_family.hf_name, NULL,
1272 1287 hei->hei_event->he_name);
1273 1288 }
1274 1289
1275 1290 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1276 1291 } else if (free_family) {
1277 1292 hook_family_free(hfi, hfi->hfi_stack);
1278 1293 }
1279 1294
1280 1295 return (error);
1281 1296 }
1282 1297
1283 1298 /*
1284 1299 * Function: hook_event_add
1285 1300 * Returns: internal event pointer - NULL = Fail
1286 1301 * Parameters: hfi(I) - internal family pointer
1287 1302 * he(I) - event pointer
1288 1303 *
1289 1304 * Add new event to event list on specific family.
1290 1305 * This function can fail to return successfully if (1) it cannot allocate
1291 1306 * enough memory for its own internal data structures, (2) the event has
1292 1307 * already been registered (for any hook family.)
1293 1308 */
1294 1309 hook_event_int_t *
1295 1310 hook_event_add(hook_family_int_t *hfi, hook_event_t *he)
1296 1311 {
1297 1312 hook_event_int_t *hei, *new;
1298 1313 hook_stack_t *hks;
1299 1314
1300 1315 ASSERT(hfi != NULL);
1301 1316 ASSERT(he != NULL);
1302 1317 ASSERT(he->he_name != NULL);
1303 1318
1304 1319 new = hook_event_copy(he);
1305 1320 if (new == NULL)
1306 1321 return (NULL);
1307 1322
1308 1323 hks = hfi->hfi_stack;
1309 1324 CVW_ENTER_READ(&hks->hks_lock);
1310 1325
1311 1326 hks = hfi->hfi_stack;
1312 1327 if (hks->hks_shutdown != 0) {
1313 1328 CVW_EXIT_READ(&hks->hks_lock);
1314 1329 hook_event_free(new, NULL);
1315 1330 return (NULL);
1316 1331 }
1317 1332
1318 1333 /* Check whether this event pointer is already registered */
1319 1334 hei = hook_event_checkdup(he, hks);
1320 1335 if (hei != NULL) {
1321 1336 CVW_EXIT_READ(&hks->hks_lock);
1322 1337 hook_event_free(new, NULL);
1323 1338 return (NULL);
1324 1339 }
1325 1340
1326 1341 CVW_ENTER_WRITE(&hfi->hfi_lock);
1327 1342
1328 1343 if (hfi->hfi_condemned || hfi->hfi_shutdown) {
1329 1344 CVW_EXIT_WRITE(&hfi->hfi_lock);
1330 1345 CVW_EXIT_READ(&hks->hks_lock);
1331 1346 hook_event_free(new, NULL);
1332 1347 return (NULL);
1333 1348 }
1334 1349 CVW_EXIT_READ(&hks->hks_lock);
1335 1350
1336 1351 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_ADD_WAIT_MASK,
1337 1352 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
1338 1353 CVW_EXIT_WRITE(&hfi->hfi_lock);
1339 1354 hook_event_free(new, NULL);
1340 1355 return (NULL);
1341 1356 }
1342 1357
1343 1358 TAILQ_INIT(&new->hei_nhead);
1344 1359
1345 1360 hook_event_init_kstats(hfi, new);
1346 1361 hook_wait_init(&new->hei_waiter, &new->hei_lock);
1347 1362
1348 1363 /* Add to event list head */
1349 1364 SLIST_INSERT_HEAD(&hfi->hfi_head, new, hei_entry);
1350 1365
1351 1366 CVW_EXIT_WRITE(&hfi->hfi_lock);
1352 1367
1353 1368 hook_notify_run(&hfi->hfi_nhead,
1354 1369 hfi->hfi_family.hf_name, NULL, he->he_name, HN_REGISTER);
1355 1370
1356 1371 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_ADD_ACTIVE);
1357 1372
1358 1373 return (new);
1359 1374 }
1360 1375
1361 1376 /*
1362 1377 * Function: hook_event_init_kstats
1363 1378 * Returns: None
1364 1379 * Parameters: hfi(I) - pointer to the family that owns this event.
1365 1380 * hei(I) - pointer to the hook event that needs some kstats.
1366 1381 *
1367 1382 * Create a set of kstats that relate to each event registered with
1368 1383 * the hook framework. A counter is kept for each time the event is
1369 1384 * activated and for each time a hook is added or removed. As the
1370 1385 * kstats just count the events as they happen, the total number of
1371 1386 * hooks registered must be obtained by subtractived removed from added.
1372 1387 */
1373 1388 static void
1374 1389 hook_event_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei)
1375 1390 {
1376 1391 hook_event_kstat_t template = {
1377 1392 { "hooksAdded", KSTAT_DATA_UINT64 },
1378 1393 { "hooksRemoved", KSTAT_DATA_UINT64 },
1379 1394 { "events", KSTAT_DATA_UINT64 }
1380 1395 };
1381 1396 hook_stack_t *hks;
1382 1397
1383 1398 hks = hfi->hfi_stack;
1384 1399 hei->hei_kstatp = kstat_create_netstack(hfi->hfi_family.hf_name, 0,
1385 1400 hei->hei_event->he_name, "hook_event", KSTAT_TYPE_NAMED,
1386 1401 sizeof (hei->hei_kstats) / sizeof (kstat_named_t),
1387 1402 KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
1388 1403
1389 1404 bcopy((char *)&template, &hei->hei_kstats, sizeof (template));
1390 1405
1391 1406 if (hei->hei_kstatp != NULL) {
1392 1407 hei->hei_kstatp->ks_data = (void *)&hei->hei_kstats;
1393 1408 hei->hei_kstatp->ks_private =
1394 1409 (void *)(uintptr_t)hks->hks_netstackid;
1395 1410
1396 1411 kstat_install(hei->hei_kstatp);
1397 1412 }
1398 1413 }
1399 1414
1400 1415 /*
1401 1416 * Function: hook_event_remove
1402 1417 * Returns: int - 0 = success, else = failure
1403 1418 * Parameters: hfi(I) - internal family pointer
1404 1419 * he(I) - event pointer
1405 1420 *
1406 1421 * Remove event from event list on specific family
1407 1422 *
1408 1423 * This function assumes that the caller has received a pointer to a the
1409 1424 * hook_family_int_t via a call to net_protocol_lookup or net_protocol_unreg'.
1410 1425 * This the hook_family_int_t is guaranteed to be around for the life of this
1411 1426 * call, unless the caller has decided to call net_protocol_release or
1412 1427 * net_protocol_unregister before calling net_event_unregister - an error.
1413 1428 */
1414 1429 int
1415 1430 hook_event_remove(hook_family_int_t *hfi, hook_event_t *he)
1416 1431 {
1417 1432 boolean_t free_family;
1418 1433 hook_event_int_t *hei;
1419 1434 boolean_t notifydone;
1420 1435
1421 1436 ASSERT(hfi != NULL);
1422 1437 ASSERT(he != NULL);
1423 1438
1424 1439 CVW_ENTER_WRITE(&hfi->hfi_lock);
1425 1440
1426 1441 /*
1427 1442 * Set the flag so that we can call hook_event_notify_run without
1428 1443 * holding any locks but at the same time prevent other changes to
1429 1444 * the event at the same time.
1430 1445 */
1431 1446 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
1432 1447 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1433 1448 CVW_EXIT_WRITE(&hfi->hfi_lock);
1434 1449 return (ENXIO);
1435 1450 }
1436 1451
1437 1452 hei = hook_event_find(hfi, he->he_name);
1438 1453 if (hei == NULL) {
1439 1454 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1440 1455 CVW_EXIT_WRITE(&hfi->hfi_lock);
1441 1456 return (ESRCH);
1442 1457 }
1443 1458
1444 1459 free_family = B_FALSE;
1445 1460
1446 1461 CVW_ENTER_WRITE(&hei->hei_lock);
1447 1462 /*
1448 1463 * The hei_shutdown flag is used to indicate whether or not we have
1449 1464 * done a shutdown and thus already walked through the notify list.
1450 1465 */
1451 1466 notifydone = hei->hei_shutdown;
1452 1467 hei->hei_shutdown = B_TRUE;
1453 1468 /*
1454 1469 * If there are any hooks still registered for this event or
1455 1470 * there are any notifiers registered, return an error indicating
1456 1471 * that the event is still busy.
1457 1472 */
1458 1473 if (!TAILQ_EMPTY(&hei->hei_head) || !TAILQ_EMPTY(&hei->hei_nhead)) {
1459 1474 hei->hei_condemned = B_TRUE;
1460 1475 CVW_EXIT_WRITE(&hei->hei_lock);
1461 1476 } else {
1462 1477 /* hei_condemned = B_FALSE is implied from creation */
1463 1478 /*
1464 1479 * Even though we know the notify list is empty, we call
1465 1480 * hook_wait_destroy here to synchronise wait removing a
1466 1481 * hook from an event.
1467 1482 */
1468 1483 VERIFY(hook_wait_destroy(&hei->hei_waiter) == 0);
1469 1484
1470 1485 CVW_EXIT_WRITE(&hei->hei_lock);
1471 1486
1472 1487 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
1473 1488 TAILQ_EMPTY(&hfi->hfi_nhead))
1474 1489 free_family = B_TRUE;
1475 1490 }
1476 1491
1477 1492 CVW_EXIT_WRITE(&hfi->hfi_lock);
1478 1493
1479 1494 if (!notifydone)
1480 1495 hook_notify_run(&hfi->hfi_nhead,
1481 1496 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
1482 1497
1483 1498 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1484 1499
1485 1500 if (!hei->hei_condemned) {
1486 1501 hook_event_free(hei, hfi);
1487 1502 if (free_family)
1488 1503 hook_family_free(hfi, hfi->hfi_stack);
1489 1504 }
1490 1505
1491 1506 return (0);
1492 1507 }
1493 1508
1494 1509 /*
1495 1510 * Function: hook_event_shutdown
1496 1511 * Returns: int - 0 = success, else = failure
1497 1512 * Parameters: hfi(I) - internal family pointer
1498 1513 * he(I) - event pointer
1499 1514 *
1500 1515 * As with hook_family_shutdown, we want to generate the notify callbacks
1501 1516 * as if the event was being removed but not actually do the remove.
1502 1517 */
1503 1518 int
1504 1519 hook_event_shutdown(hook_family_int_t *hfi, hook_event_t *he)
1505 1520 {
1506 1521 hook_event_int_t *hei;
1507 1522 boolean_t notifydone;
1508 1523
1509 1524 ASSERT(hfi != NULL);
1510 1525 ASSERT(he != NULL);
1511 1526
1512 1527 CVW_ENTER_WRITE(&hfi->hfi_lock);
1513 1528
1514 1529 /*
1515 1530 * Set the flag so that we can call hook_event_notify_run without
1516 1531 * holding any locks but at the same time prevent other changes to
1517 1532 * the event at the same time.
1518 1533 */
1519 1534 if (hook_wait_setflag(&hfi->hfi_waiter, FWF_DEL_WAIT_MASK,
1520 1535 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
1521 1536 CVW_EXIT_WRITE(&hfi->hfi_lock);
1522 1537 return (ENXIO);
1523 1538 }
1524 1539
1525 1540 hei = hook_event_find(hfi, he->he_name);
1526 1541 if (hei == NULL) {
1527 1542 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1528 1543 CVW_EXIT_WRITE(&hfi->hfi_lock);
1529 1544 return (ESRCH);
1530 1545 }
1531 1546
1532 1547 CVW_ENTER_WRITE(&hei->hei_lock);
1533 1548 notifydone = hei->hei_shutdown;
1534 1549 hei->hei_shutdown = B_TRUE;
1535 1550 CVW_EXIT_WRITE(&hei->hei_lock);
1536 1551
1537 1552 CVW_EXIT_WRITE(&hfi->hfi_lock);
1538 1553
1539 1554 if (!notifydone)
1540 1555 hook_notify_run(&hfi->hfi_nhead,
1541 1556 hfi->hfi_family.hf_name, NULL, he->he_name, HN_UNREGISTER);
1542 1557
1543 1558 hook_wait_unsetflag(&hfi->hfi_waiter, FWF_DEL_ACTIVE);
1544 1559
1545 1560 return (0);
1546 1561 }
1547 1562
1548 1563 /*
1549 1564 * Function: hook_event_free
1550 1565 * Returns: None
1551 1566 * Parameters: hei(I) - internal event pointer
1552 1567 *
1553 1568 * Free alloc memory for event
1554 1569 */
1555 1570 static void
1556 1571 hook_event_free(hook_event_int_t *hei, hook_family_int_t *hfi)
1557 1572 {
1558 1573 boolean_t free_family;
1559 1574
1560 1575 ASSERT(hei != NULL);
1561 1576
1562 1577 if (hfi != NULL) {
1563 1578 CVW_ENTER_WRITE(&hfi->hfi_lock);
1564 1579 /*
1565 1580 * Remove the event from the hook family's list.
1566 1581 */
1567 1582 SLIST_REMOVE(&hfi->hfi_head, hei, hook_event_int, hei_entry);
1568 1583 if (hfi->hfi_condemned && SLIST_EMPTY(&hfi->hfi_head) &&
1569 1584 TAILQ_EMPTY(&hfi->hfi_nhead)) {
1570 1585 free_family = B_TRUE;
1571 1586 } else {
1572 1587 free_family = B_FALSE;
1573 1588 }
1574 1589 CVW_EXIT_WRITE(&hfi->hfi_lock);
1575 1590 }
1576 1591
1577 1592 if (hei->hei_kstatp != NULL) {
1578 1593 ASSERT(hfi != NULL);
1579 1594
1580 1595 kstat_delete_netstack(hei->hei_kstatp,
1581 1596 hfi->hfi_stack->hks_netstackid);
1582 1597 hei->hei_kstatp = NULL;
1583 1598 }
1584 1599
1585 1600 /* Free container */
1586 1601 kmem_free(hei, sizeof (*hei));
1587 1602
1588 1603 if (free_family)
1589 1604 hook_family_free(hfi, hfi->hfi_stack);
1590 1605 }
1591 1606
1592 1607 /*
1593 1608 * Function: hook_event_checkdup
1594 1609 * Returns: internal event pointer - NULL = Not match
1595 1610 * Parameters: he(I) - event pointer
1596 1611 *
1597 1612 * Search all of the hook families to see if the event being passed in
1598 1613 * has already been associated with one.
1599 1614 */
1600 1615 static hook_event_int_t *
1601 1616 hook_event_checkdup(hook_event_t *he, hook_stack_t *hks)
1602 1617 {
1603 1618 hook_family_int_t *hfi;
1604 1619 hook_event_int_t *hei;
1605 1620
1606 1621 ASSERT(he != NULL);
1607 1622
1608 1623 CVW_ENTER_READ(&hks->hks_lock);
1609 1624 SLIST_FOREACH(hfi, &hks->hks_familylist, hfi_entry) {
1610 1625 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1611 1626 if (hei->hei_event == he) {
1612 1627 CVW_EXIT_READ(&hks->hks_lock);
1613 1628 return (hei);
1614 1629 }
1615 1630 }
1616 1631 }
1617 1632 CVW_EXIT_READ(&hks->hks_lock);
1618 1633
1619 1634 return (NULL);
1620 1635 }
1621 1636
1622 1637 /*
1623 1638 * Function: hook_event_copy
1624 1639 * Returns: internal event pointer - NULL = Failed
1625 1640 * Parameters: src(I) - event pointer
1626 1641 *
1627 1642 * Allocate internal event block and duplicate incoming event
1628 1643 * No locks should be held across this function as it may sleep.
1629 1644 */
1630 1645 static hook_event_int_t *
1631 1646 hook_event_copy(hook_event_t *src)
1632 1647 {
1633 1648 hook_event_int_t *new;
1634 1649
1635 1650 ASSERT(src != NULL);
1636 1651 ASSERT(src->he_name != NULL);
1637 1652
1638 1653 new = (hook_event_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
1639 1654
1640 1655 /* Copy body */
1641 1656 TAILQ_INIT(&new->hei_head);
1642 1657 new->hei_event = src;
1643 1658
|
↓ open down ↓ |
504 lines elided |
↑ open up ↑ |
1644 1659 return (new);
1645 1660 }
1646 1661
1647 1662 /*
1648 1663 * Function: hook_event_find
1649 1664 * Returns: internal event pointer - NULL = Not match
1650 1665 * Parameters: hfi(I) - internal family pointer
1651 1666 * event(I) - event name string
1652 1667 *
1653 1668 * Search event list with event name
1654 - * A lock on hfi->hfi_lock must be held when called.
1669 + * A lock on hfi->hfi_lock must be held when called.
1655 1670 */
1656 1671 static hook_event_int_t *
1657 1672 hook_event_find(hook_family_int_t *hfi, char *event)
1658 1673 {
1659 1674 hook_event_int_t *hei = NULL;
1660 1675
1661 1676 ASSERT(hfi != NULL);
1662 1677 ASSERT(event != NULL);
1663 1678
1664 1679 SLIST_FOREACH(hei, &hfi->hfi_head, hei_entry) {
1665 1680 if ((strcmp(hei->hei_event->he_name, event) == 0) &&
1666 1681 ((hei->hei_waiter.fw_flags & FWF_UNSAFE) == 0))
1667 1682 break;
1668 1683 }
1669 1684 return (hei);
1670 1685 }
1671 1686
1672 1687 /*
1673 1688 * Function: hook_event_notify_register
1674 1689 * Returns: int - 0 = success, else failure
1675 1690 * Parameters: hfi(I) - hook family
1676 1691 * event(I) - name of the event
1677 1692 * callback(I) - function to be called
1678 1693 * arg(I) - arg to provide callback when it is called
1679 1694 *
1680 1695 * Adds a new callback to the event named by "event" (we must find it)
1681 1696 * that will be executed each time a new hook is added to the event.
1682 1697 * Of course, if the stack is being shut down, this call should fail.
1683 1698 */
1684 1699 int
1685 1700 hook_event_notify_register(hook_family_int_t *hfi, char *event,
1686 1701 hook_notify_fn_t callback, void *arg)
1687 1702 {
1688 1703 hook_event_int_t *hei;
1689 1704 hook_stack_t *hks;
1690 1705 boolean_t canrun;
1691 1706 hook_int_t *h;
1692 1707 int error;
1693 1708
1694 1709 canrun = B_FALSE;
1695 1710 hks = hfi->hfi_stack;
1696 1711 CVW_ENTER_READ(&hks->hks_lock);
1697 1712 if (hks->hks_shutdown != 0) {
1698 1713 CVW_EXIT_READ(&hks->hks_lock);
1699 1714 return (ESHUTDOWN);
1700 1715 }
1701 1716
1702 1717 CVW_ENTER_READ(&hfi->hfi_lock);
1703 1718
1704 1719 if (hfi->hfi_condemned || hfi->hfi_shutdown) {
1705 1720 CVW_EXIT_READ(&hfi->hfi_lock);
1706 1721 CVW_EXIT_READ(&hks->hks_lock);
1707 1722 return (ESHUTDOWN);
1708 1723 }
1709 1724
1710 1725 hei = hook_event_find(hfi, event);
1711 1726 if (hei == NULL) {
1712 1727 CVW_EXIT_READ(&hfi->hfi_lock);
1713 1728 CVW_EXIT_READ(&hks->hks_lock);
1714 1729 return (ESRCH);
1715 1730 }
1716 1731
1717 1732 if (hei->hei_condemned || hei->hei_shutdown) {
1718 1733 CVW_EXIT_READ(&hfi->hfi_lock);
1719 1734 CVW_EXIT_READ(&hks->hks_lock);
1720 1735 return (ESHUTDOWN);
1721 1736 }
1722 1737
1723 1738 CVW_ENTER_WRITE(&hei->hei_lock);
1724 1739 canrun = (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
1725 1740 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1726 1741 error = hook_notify_register(&hei->hei_nhead, callback, arg);
1727 1742 CVW_EXIT_WRITE(&hei->hei_lock);
1728 1743
1729 1744 CVW_EXIT_READ(&hfi->hfi_lock);
1730 1745 CVW_EXIT_READ(&hks->hks_lock);
1731 1746
1732 1747 if (error == 0 && canrun) {
1733 1748 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
1734 1749 callback(HN_REGISTER, arg,
1735 1750 hfi->hfi_family.hf_name, hei->hei_event->he_name,
1736 1751 h->hi_hook.h_name);
1737 1752 }
1738 1753 }
1739 1754
1740 1755 if (canrun)
1741 1756 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1742 1757
1743 1758 return (error);
1744 1759 }
1745 1760
1746 1761 /*
1747 1762 * Function: hook_event_notify_unregister
1748 1763 * Returns: int - 0 = success, else failure
1749 1764 * Parameters: hfi(I) - hook family
1750 1765 * event(I) - name of the event
1751 1766 * callback(I) - function to be called
1752 1767 *
1753 1768 * Remove the given callback from the named event's list of functions
1754 1769 * to call when a hook is added or removed.
1755 1770 */
1756 1771 int
1757 1772 hook_event_notify_unregister(hook_family_int_t *hfi, char *event,
1758 1773 hook_notify_fn_t callback)
1759 1774 {
1760 1775 hook_event_int_t *hei;
1761 1776 boolean_t free_event;
1762 1777 boolean_t canrun;
1763 1778 hook_int_t *h;
1764 1779 void *arg;
1765 1780 int error;
1766 1781
1767 1782 canrun = B_FALSE;
1768 1783
1769 1784 CVW_ENTER_READ(&hfi->hfi_lock);
1770 1785
1771 1786 hei = hook_event_find(hfi, event);
1772 1787 if (hei == NULL) {
1773 1788 CVW_EXIT_READ(&hfi->hfi_lock);
1774 1789 return (ESRCH);
1775 1790 }
1776 1791
1777 1792 CVW_ENTER_WRITE(&hei->hei_lock);
1778 1793
1779 1794 (void) hook_wait_setflag(&hei->hei_waiter, FWF_DEL_WAIT_MASK,
1780 1795 FWF_DEL_WANTED, FWF_DEL_ACTIVE);
1781 1796
1782 1797 error = hook_notify_unregister(&hei->hei_nhead, callback, &arg);
1783 1798
1784 1799 hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
1785 1800
1786 1801 /*
1787 1802 * hei_condemned has been set if someone tried to remove the
1788 1803 * event but couldn't because there were still things attached to
1789 1804 * it. Now that we've done a successful remove, if it is now empty
1790 1805 * then by all rights we should be free'ing it too. Note that the
1791 1806 * expectation is that only the caller of hook_event_add will ever
1792 1807 * call hook_event_remove.
1793 1808 */
1794 1809 if ((error == 0) && hei->hei_condemned &&
1795 1810 TAILQ_EMPTY(&hei->hei_head) && TAILQ_EMPTY(&hei->hei_nhead)) {
1796 1811 free_event = B_TRUE;
1797 1812 } else {
1798 1813 free_event = B_FALSE;
1799 1814 }
1800 1815
1801 1816 if (error == 0 && !free_event) {
1802 1817 canrun = (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
1803 1818 FWF_ADD_WANTED, FWF_ADD_ACTIVE) != -1);
1804 1819 }
1805 1820
1806 1821 CVW_EXIT_WRITE(&hei->hei_lock);
1807 1822 CVW_EXIT_READ(&hfi->hfi_lock);
1808 1823
1809 1824 if (canrun) {
1810 1825 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
1811 1826 callback(HN_UNREGISTER, arg,
1812 1827 hfi->hfi_family.hf_name, hei->hei_event->he_name,
1813 1828 h->hi_hook.h_name);
1814 1829 }
1815 1830
1816 1831 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1817 1832 }
1818 1833
1819 1834 if (free_event) {
1820 1835 /*
1821 1836 * It is safe to pass in hfi here, without a lock, because
1822 1837 * our structure (hei) is still on one of its lists and thus
1823 1838 * it won't be able to disappear yet...
1824 1839 */
1825 1840 hook_event_free(hei, hfi);
1826 1841 }
1827 1842
1828 1843 return (error);
1829 1844 }
1830 1845
1831 1846 /*
1832 1847 * Function: hook_event_notify_run
1833 1848 * Returns: None
1834 1849 * Parameters: nrun(I) - pointer to the list of callbacks to execute
1835 1850 * hfi(I) - hook stack pointer to execute callbacks for
1836 1851 * name(I) - name of a hook family
1837 1852 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
1838 1853 *
1839 1854 * Execute all of the callbacks registered for this event.
1840 1855 */
1841 1856 static void
1842 1857 hook_event_notify_run(hook_event_int_t *hei, hook_family_int_t *hfi,
1843 1858 char *event, char *name, hook_notify_cmd_t cmd)
1844 1859 {
1845 1860
1846 1861 hook_notify_run(&hei->hei_nhead, hfi->hfi_family.hf_name,
1847 1862 event, name, cmd);
1848 1863 }
1849 1864
1850 1865 /*
1851 1866 * Function: hook_register
1852 1867 * Returns: int - 0 = success, else = failure
1853 1868 * Parameters: hfi(I) - internal family pointer
1854 1869 * event(I) - event name string
1855 1870 * h(I) - hook pointer
1856 1871 *
1857 1872 * Add new hook to hook list on the specified family and event.
1858 1873 */
1859 1874 int
1860 1875 hook_register(hook_family_int_t *hfi, char *event, hook_t *h)
1861 1876 {
1862 1877 hook_event_int_t *hei;
1863 1878 hook_int_t *hi, *new;
1864 1879 int error;
1865 1880
1866 1881 ASSERT(hfi != NULL);
1867 1882 ASSERT(event != NULL);
1868 1883 ASSERT(h != NULL);
1869 1884
1870 1885 if (hfi->hfi_stack->hks_shutdown)
1871 1886 return (NULL);
1872 1887
1873 1888 /* Alloc hook_int_t and copy hook */
1874 1889 new = hook_copy(h);
1875 1890 if (new == NULL)
1876 1891 return (ENOMEM);
1877 1892
1878 1893 /*
1879 1894 * Since hook add/remove only impact event, so it is unnecessary
1880 1895 * to hold global family write lock. Just get read lock here to
1881 1896 * ensure event will not be removed when doing hooks operation
1882 1897 */
1883 1898 CVW_ENTER_WRITE(&hfi->hfi_lock);
1884 1899
1885 1900 hei = hook_event_find(hfi, event);
1886 1901 if (hei == NULL) {
1887 1902 CVW_EXIT_WRITE(&hfi->hfi_lock);
1888 1903 hook_int_free(new, hfi->hfi_stack->hks_netstackid);
1889 1904 return (ENXIO);
1890 1905 }
1891 1906
1892 1907 CVW_ENTER_WRITE(&hei->hei_lock);
1893 1908
1894 1909 /*
1895 1910 * If we've run either the remove() or shutdown(), do not allow any
1896 1911 * more hooks to be added to this event.
1897 1912 */
1898 1913 if (hei->hei_shutdown) {
1899 1914 error = ESHUTDOWN;
1900 1915 goto bad_add;
1901 1916 }
1902 1917
1903 1918 hi = hook_find(hei, h);
1904 1919 if (hi != NULL) {
1905 1920 error = EEXIST;
1906 1921 goto bad_add;
1907 1922 }
1908 1923
1909 1924 if (hook_wait_setflag(&hei->hei_waiter, FWF_ADD_WAIT_MASK,
1910 1925 FWF_ADD_WANTED, FWF_ADD_ACTIVE) == -1) {
1911 1926 error = ENOENT;
1912 1927 bad_add:
1913 1928 CVW_EXIT_WRITE(&hei->hei_lock);
1914 1929 CVW_EXIT_WRITE(&hfi->hfi_lock);
1915 1930 hook_int_free(new, hfi->hfi_stack->hks_netstackid);
1916 1931 return (error);
1917 1932 }
1918 1933
1919 1934 /* Add to hook list head */
1920 1935 error = hook_insert(&hei->hei_head, new);
1921 1936 if (error == 0) {
1922 1937 hei->hei_event->he_interested = B_TRUE;
1923 1938 hei->hei_kstats.hooks_added.value.ui64++;
1924 1939
1925 1940 hook_init_kstats(hfi, hei, new);
1926 1941 }
1927 1942
1928 1943 CVW_EXIT_WRITE(&hei->hei_lock);
1929 1944 CVW_EXIT_WRITE(&hfi->hfi_lock);
1930 1945
1931 1946 /*
1932 1947 * Note that the name string passed through to the notify callbacks
1933 1948 * is from the original hook being registered, not the copy being
1934 1949 * inserted.
1935 1950 */
1936 1951 if (error == 0)
1937 1952 hook_event_notify_run(hei, hfi, event, h->h_name, HN_REGISTER);
1938 1953
1939 1954 hook_wait_unsetflag(&hei->hei_waiter, FWF_ADD_ACTIVE);
1940 1955
1941 1956 return (error);
1942 1957 }
1943 1958
1944 1959 /*
1945 1960 * Function: hook_insert
1946 1961 * Returns: int - 0 = success, else = failure
1947 1962 * Parameters: head(I) - pointer to hook list to insert hook onto
1948 1963 * new(I) - pointer to hook to be inserted
1949 1964 *
1950 1965 * Try to insert the hook onto the list of hooks according to the hints
1951 1966 * given in the hook to be inserted and those that already exist on the
1952 1967 * list. For now, the implementation permits only a single hook to be
1953 1968 * either first or last and names provided with before or after are only
1954 1969 * loosely coupled with the action.
1955 1970 */
1956 1971 static int
1957 1972 hook_insert(hook_int_head_t *head, hook_int_t *new)
1958 1973 {
1959 1974 hook_int_t *before;
1960 1975 hook_int_t *hi;
1961 1976 hook_t *hih;
1962 1977 hook_t *h = &new->hi_hook;
1963 1978
1964 1979 switch (new->hi_hook.h_hint) {
1965 1980 case HH_NONE :
1966 1981 before = NULL;
1967 1982 /*
1968 1983 * If there is no hint present (or not one that can be
1969 1984 * satisfied now) then try to at least respect the wishes
1970 1985 * of those that want to be last. If there are none wanting
1971 1986 * to be last then add the new hook to the tail of the
1972 1987 * list - this means we keep any wanting to be first
1973 1988 * happy without having to search for HH_FIRST.
1974 1989 */
1975 1990 TAILQ_FOREACH(hi, head, hi_entry) {
1976 1991 hih = &hi->hi_hook;
1977 1992 if ((hih->h_hint == HH_AFTER) &&
1978 1993 (strcmp(h->h_name,
1979 1994 (char *)hih->h_hintvalue) == 0)) {
1980 1995 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
1981 1996 return (0);
1982 1997 }
1983 1998 if ((hih->h_hint == HH_BEFORE) && (before == NULL) &&
1984 1999 (strcmp(h->h_name,
1985 2000 (char *)hih->h_hintvalue) == 0)) {
1986 2001 before = hi;
1987 2002 }
1988 2003 }
1989 2004 if (before != NULL) {
1990 2005 TAILQ_INSERT_AFTER(head, before, new, hi_entry);
1991 2006 return (0);
1992 2007 }
1993 2008 hook_insert_plain(head, new);
1994 2009 break;
1995 2010
1996 2011 case HH_FIRST :
1997 2012 hi = TAILQ_FIRST(head);
1998 2013 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_FIRST))
1999 2014 return (EBUSY);
2000 2015 TAILQ_INSERT_HEAD(head, new, hi_entry);
2001 2016 break;
2002 2017
2003 2018 case HH_LAST :
2004 2019 hi = TAILQ_LAST(head, hook_int_head);
2005 2020 if ((hi != NULL) && (hi->hi_hook.h_hint == HH_LAST))
2006 2021 return (EBUSY);
2007 2022 TAILQ_INSERT_TAIL(head, new, hi_entry);
2008 2023 break;
2009 2024
2010 2025 case HH_BEFORE :
2011 2026 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
2012 2027 if (hi == NULL)
2013 2028 return (hook_insert_afterbefore(head, new));
2014 2029
2015 2030 if (hi->hi_hook.h_hint == HH_FIRST)
2016 2031 return (EBUSY);
2017 2032
2018 2033 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2019 2034 break;
2020 2035
2021 2036 case HH_AFTER :
2022 2037 hi = hook_find_byname(head, (char *)new->hi_hook.h_hintvalue);
2023 2038 if (hi == NULL)
2024 2039 return (hook_insert_afterbefore(head, new));
2025 2040
2026 2041 if (hi->hi_hook.h_hint == HH_LAST)
2027 2042 return (EBUSY);
2028 2043
2029 2044 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2030 2045 break;
2031 2046
2032 2047 default :
2033 2048 return (EINVAL);
2034 2049 }
2035 2050
2036 2051 return (0);
2037 2052 }
2038 2053
2039 2054 /*
2040 2055 * Function: hook_insert_plain
2041 2056 * Returns: int - 0 = success, else = failure
2042 2057 * Parameters: head(I) - pointer to hook list to insert hook onto
2043 2058 * new(I) - pointer to hook to be inserted
2044 2059 *
2045 2060 * Insert a hook such that it respects the wishes of those that want to
2046 2061 * be last. If there are none wanting to be last then add the new hook
2047 2062 * to the tail of the list - this means we keep any wanting to be first
2048 2063 * happy without having to search for HH_FIRST.
2049 2064 */
2050 2065 static void
2051 2066 hook_insert_plain(hook_int_head_t *head, hook_int_t *new)
2052 2067 {
2053 2068 hook_int_t *hi;
2054 2069
2055 2070 hi = TAILQ_FIRST(head);
2056 2071 if (hi != NULL) {
2057 2072 if (hi->hi_hook.h_hint == HH_LAST) {
2058 2073 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2059 2074 } else {
2060 2075 TAILQ_INSERT_TAIL(head, new, hi_entry);
2061 2076 }
2062 2077 } else {
2063 2078 TAILQ_INSERT_TAIL(head, new, hi_entry);
2064 2079 }
2065 2080 }
2066 2081
2067 2082 /*
2068 2083 * Function: hook_insert_afterbefore
2069 2084 * Returns: int - 0 = success, else = failure
2070 2085 * Parameters: head(I) - pointer to hook list to insert hook onto
2071 2086 * new(I) - pointer to hook to be inserted
2072 2087 *
2073 2088 * Simple insertion of a hook specifying a HH_BEFORE or HH_AFTER was not
2074 2089 * possible, so now we need to be more careful. The first pass is to go
2075 2090 * through the list and look for any other hooks that also specify the
2076 2091 * same hint name as the new one. The object of this exercise is to make
2077 2092 * sure that hooks with HH_BEFORE always appear on the list before those
2078 2093 * with HH_AFTER so that when said hook arrives, it can be placed in the
2079 2094 * middle of the BEFOREs and AFTERs. If this condition does not arise,
2080 2095 * just use hook_insert_plain() to try and insert the hook somewhere that
2081 2096 * is innocuous to existing efforts.
2082 2097 */
2083 2098 static int
2084 2099 hook_insert_afterbefore(hook_int_head_t *head, hook_int_t *new)
2085 2100 {
2086 2101 hook_int_t *hi;
2087 2102 hook_t *nh;
2088 2103 hook_t *h;
2089 2104
2090 2105 nh = &new->hi_hook;
2091 2106 ASSERT(new->hi_hook.h_hint != HH_NONE);
2092 2107 ASSERT(new->hi_hook.h_hint != HH_LAST);
2093 2108 ASSERT(new->hi_hook.h_hint != HH_FIRST);
2094 2109
2095 2110 /*
2096 2111 * First, look through the list to see if there are any other
2097 2112 * before's or after's that have a matching hint name.
2098 2113 */
2099 2114 TAILQ_FOREACH(hi, head, hi_entry) {
2100 2115 h = &hi->hi_hook;
2101 2116 switch (h->h_hint) {
2102 2117 case HH_FIRST :
2103 2118 case HH_LAST :
2104 2119 case HH_NONE :
2105 2120 break;
2106 2121 case HH_BEFORE :
2107 2122 if ((nh->h_hint == HH_BEFORE) &&
2108 2123 (strcmp((char *)h->h_hintvalue,
2109 2124 (char *)nh->h_hintvalue) == 0)) {
2110 2125 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2111 2126 return (0);
2112 2127 }
2113 2128 if ((nh->h_hint == HH_AFTER) &&
2114 2129 (strcmp((char *)h->h_hintvalue,
2115 2130 (char *)nh->h_hintvalue) == 0)) {
2116 2131 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2117 2132 return (0);
2118 2133 }
2119 2134 break;
2120 2135 case HH_AFTER :
2121 2136 if ((nh->h_hint == HH_AFTER) &&
2122 2137 (strcmp((char *)h->h_hintvalue,
2123 2138 (char *)nh->h_hintvalue) == 0)) {
2124 2139 TAILQ_INSERT_AFTER(head, hi, new, hi_entry);
2125 2140 return (0);
2126 2141 }
2127 2142 if ((nh->h_hint == HH_BEFORE) &&
2128 2143 (strcmp((char *)h->h_hintvalue,
2129 2144 (char *)nh->h_hintvalue) == 0)) {
2130 2145 TAILQ_INSERT_BEFORE(hi, new, hi_entry);
2131 2146 return (0);
2132 2147 }
2133 2148 break;
2134 2149 }
2135 2150 }
2136 2151
2137 2152 hook_insert_plain(head, new);
2138 2153
2139 2154 return (0);
2140 2155 }
2141 2156
2142 2157 /*
2143 2158 * Function: hook_unregister
2144 2159 * Returns: int - 0 = success, else = failure
2145 2160 * Parameters: hfi(I) - internal family pointer
2146 2161 * event(I) - event name string
2147 2162 * h(I) - hook pointer
2148 2163 *
2149 2164 * Remove hook from hook list on specific family, event
2150 2165 */
2151 2166 int
2152 2167 hook_unregister(hook_family_int_t *hfi, char *event, hook_t *h)
2153 2168 {
2154 2169 hook_event_int_t *hei;
2155 2170 hook_int_t *hi;
2156 2171 boolean_t free_event;
2157 2172
2158 2173 ASSERT(hfi != NULL);
2159 2174 ASSERT(h != NULL);
2160 2175
2161 2176 CVW_ENTER_WRITE(&hfi->hfi_lock);
2162 2177
2163 2178 hei = hook_event_find(hfi, event);
2164 2179 if (hei == NULL) {
2165 2180 CVW_EXIT_WRITE(&hfi->hfi_lock);
2166 2181 return (ENXIO);
2167 2182 }
2168 2183
2169 2184 /* Hold write lock for event */
2170 2185 CVW_ENTER_WRITE(&hei->hei_lock);
2171 2186
2172 2187 hi = hook_find(hei, h);
2173 2188 if (hi == NULL) {
2174 2189 CVW_EXIT_WRITE(&hei->hei_lock);
2175 2190 CVW_EXIT_WRITE(&hfi->hfi_lock);
2176 2191 return (ENXIO);
2177 2192 }
2178 2193
2179 2194 if (hook_wait_setflag(&hei->hei_waiter, FWF_DEL_WAIT_MASK,
2180 2195 FWF_DEL_WANTED, FWF_DEL_ACTIVE) == -1) {
2181 2196 CVW_EXIT_WRITE(&hei->hei_lock);
2182 2197 CVW_EXIT_WRITE(&hfi->hfi_lock);
2183 2198 return (ENOENT);
2184 2199 }
2185 2200
2186 2201 /* Remove from hook list */
2187 2202 TAILQ_REMOVE(&hei->hei_head, hi, hi_entry);
2188 2203
2189 2204 free_event = B_FALSE;
2190 2205 if (TAILQ_EMPTY(&hei->hei_head)) {
2191 2206 hei->hei_event->he_interested = B_FALSE;
2192 2207 /*
2193 2208 * If the delete pending flag has been set and there are
2194 2209 * no notifiers on the event (and we've removed the last
2195 2210 * hook) then we need to free this event after we're done.
2196 2211 */
2197 2212 if (hei->hei_condemned && TAILQ_EMPTY(&hei->hei_nhead))
2198 2213 free_event = B_TRUE;
2199 2214 }
2200 2215 hei->hei_kstats.hooks_removed.value.ui64++;
2201 2216
2202 2217 CVW_EXIT_WRITE(&hei->hei_lock);
2203 2218 CVW_EXIT_WRITE(&hfi->hfi_lock);
2204 2219 /*
2205 2220 * While the FWF_DEL_ACTIVE flag is set, the hook_event_int_t
2206 2221 * will not be free'd and thus the hook_family_int_t wil not
2207 2222 * be free'd either.
2208 2223 */
2209 2224 hook_event_notify_run(hei, hfi, event, h->h_name, HN_UNREGISTER);
2210 2225 hook_wait_unsetflag(&hei->hei_waiter, FWF_DEL_ACTIVE);
2211 2226
2212 2227 hook_int_free(hi, hfi->hfi_stack->hks_netstackid);
2213 2228
2214 2229 if (free_event)
2215 2230 hook_event_free(hei, hfi);
2216 2231
2217 2232 return (0);
2218 2233 }
2219 2234
2220 2235 /*
2221 2236 * Function: hook_find_byname
2222 2237 * Returns: internal hook pointer - NULL = Not match
2223 2238 * Parameters: hei(I) - internal event pointer
2224 2239 * name(I)- hook name
2225 2240 *
2226 2241 * Search an event's list of hooks to see if there is a hook present that
2227 2242 * has a matching name to the one being looked for.
2228 2243 */
2229 2244 static hook_int_t *
2230 2245 hook_find_byname(hook_int_head_t *head, char *name)
2231 2246 {
2232 2247 hook_int_t *hi;
2233 2248
2234 2249 TAILQ_FOREACH(hi, head, hi_entry) {
2235 2250 if (strcmp(hi->hi_hook.h_name, name) == 0)
2236 2251 return (hi);
2237 2252 }
2238 2253
2239 2254 return (NULL);
2240 2255 }
2241 2256
2242 2257 /*
2243 2258 * Function: hook_find
2244 2259 * Returns: internal hook pointer - NULL = Not match
2245 2260 * Parameters: hei(I) - internal event pointer
2246 2261 * h(I) - hook pointer
2247 2262 *
2248 2263 * Search an event's list of hooks to see if there is already one that
2249 2264 * matches the hook being passed in. Currently the only criteria for a
2250 2265 * successful search here is for the names to be the same.
2251 2266 */
2252 2267 static hook_int_t *
2253 2268 hook_find(hook_event_int_t *hei, hook_t *h)
2254 2269 {
2255 2270
2256 2271 ASSERT(hei != NULL);
2257 2272 ASSERT(h != NULL);
2258 2273
2259 2274 return (hook_find_byname(&hei->hei_head, h->h_name));
2260 2275 }
2261 2276
2262 2277 /*
2263 2278 * Function: hook_copy
2264 2279 * Returns: internal hook pointer - NULL = Failed
2265 2280 * Parameters: src(I) - hook pointer
2266 2281 *
2267 2282 * Allocate internal hook block and duplicate incoming hook.
2268 2283 * No locks should be held across this function as it may sleep.
2269 2284 * Because hook_copy() is responsible for the creation of the internal
2270 2285 * hook structure that is used here, it takes on population the structure
2271 2286 * with the kstat information. Note that while the kstat bits are
2272 2287 * seeded here, their installation of the kstats is handled elsewhere.
2273 2288 */
2274 2289 static hook_int_t *
2275 2290 hook_copy(hook_t *src)
2276 2291 {
2277 2292 hook_int_t *new;
2278 2293 hook_t *dst;
2279 2294 int len;
2280 2295
2281 2296 ASSERT(src != NULL);
2282 2297 ASSERT(src->h_name != NULL);
2283 2298
2284 2299 new = (hook_int_t *)kmem_zalloc(sizeof (*new), KM_SLEEP);
2285 2300
2286 2301 /* Copy body */
2287 2302 dst = &new->hi_hook;
2288 2303 *dst = *src;
2289 2304
2290 2305 /* Copy name */
2291 2306 len = strlen(src->h_name);
2292 2307 dst->h_name = (char *)kmem_alloc(len + 1, KM_SLEEP);
2293 2308 (void) strcpy(dst->h_name, src->h_name);
2294 2309
2295 2310 /*
2296 2311 * This is initialised in this manner to make it safer to use the
2297 2312 * same pointer in the kstats field.
2298 2313 */
2299 2314 dst->h_hintvalue = (uintptr_t)"";
2300 2315
2301 2316 if (dst->h_hint == HH_BEFORE || dst->h_hint == HH_AFTER) {
2302 2317 len = strlen((char *)src->h_hintvalue);
2303 2318 if (len > 0) {
2304 2319 dst->h_hintvalue = (uintptr_t)kmem_alloc(len + 1,
2305 2320 KM_SLEEP);
2306 2321 (void) strcpy((char *)dst->h_hintvalue,
2307 2322 (char *)src->h_hintvalue);
2308 2323 }
2309 2324 }
2310 2325
2311 2326 return (new);
2312 2327 }
2313 2328
2314 2329 /*
2315 2330 * Function: hook_init_kstats
2316 2331 * Returns: None
2317 2332 * Parameters: hfi(I) - pointer to the family that owns the event.
2318 2333 * hei(I) - pointer to the event that owns this hook
2319 2334 * hi(I) - pointer to the hook for which we create kstats for
2320 2335 *
2321 2336 * Each hook that is registered with this framework has its own kstats
2322 2337 * set up so that we can provide an easy way in which to observe the
2323 2338 * look of hooks (using the kstat command.) The position is set to 0
2324 2339 * here but is recalculated after we know the insertion has been a
2325 2340 * success.
2326 2341 */
2327 2342 static void
2328 2343 hook_init_kstats(hook_family_int_t *hfi, hook_event_int_t *hei, hook_int_t *hi)
2329 2344 {
2330 2345 hook_hook_kstat_t template = {
2331 2346 { "version", KSTAT_DATA_INT32 },
2332 2347 { "flags", KSTAT_DATA_UINT32 },
2333 2348 { "hint", KSTAT_DATA_INT32 },
2334 2349 { "hint_value", KSTAT_DATA_STRING },
2335 2350 { "position", KSTAT_DATA_INT32 },
2336 2351 { "hook_hits", KSTAT_DATA_UINT64 }
2337 2352 };
2338 2353 hook_stack_t *hks;
2339 2354 size_t kslen;
2340 2355 int position;
2341 2356 hook_int_t *h;
2342 2357
2343 2358 kslen = strlen(hfi->hfi_family.hf_name) +
2344 2359 strlen(hei->hei_event->he_name) + 2;
2345 2360
2346 2361 hi->hi_ksname = (char *)kmem_zalloc(kslen, KM_SLEEP);
2347 2362 (void) snprintf(hi->hi_ksname, kslen, "%s/%s",
2348 2363 hfi->hfi_family.hf_name, hei->hei_event->he_name);
2349 2364
2350 2365 hks = hfi->hfi_stack;
2351 2366 hi->hi_kstatp = kstat_create_netstack(hi->hi_ksname, 0,
2352 2367 hi->hi_hook.h_name, "hook", KSTAT_TYPE_NAMED,
2353 2368 sizeof (hi->hi_kstats) / sizeof (kstat_named_t),
2354 2369 KSTAT_FLAG_VIRTUAL, hks->hks_netstackid);
2355 2370
2356 2371 /* Initialise the kstats for the structure */
2357 2372 bcopy(&template, &hi->hi_kstats, sizeof (template));
2358 2373 hi->hi_kstats.hook_version.value.i32 = hi->hi_hook.h_version;
2359 2374 hi->hi_kstats.hook_flags.value.ui32 = hi->hi_hook.h_flags;
2360 2375 hi->hi_kstats.hook_hint.value.i32 = hi->hi_hook.h_hint;
2361 2376 hi->hi_kstats.hook_position.value.i32 = 0;
2362 2377 hi->hi_kstats.hook_hits.value.ui64 = 0;
2363 2378
2364 2379 switch (hi->hi_hook.h_hint) {
2365 2380 case HH_BEFORE :
2366 2381 case HH_AFTER :
2367 2382 kstat_named_setstr(&(hi->hi_kstats.hook_hintvalue),
2368 2383 (const char *)hi->hi_hook.h_hintvalue);
2369 2384 break;
2370 2385 default :
2371 2386 kstat_named_setstr(&(hi->hi_kstats.hook_hintvalue),
2372 2387 hook_hintvalue_none);
2373 2388 break;
2374 2389 }
2375 2390
2376 2391 if (hi->hi_kstatp != NULL) {
2377 2392 hi->hi_kstatp->ks_data = (void *)&hi->hi_kstats;
2378 2393 hi->hi_kstatp->ks_private =
2379 2394 (void *)(uintptr_t)hks->hks_netstackid;
2380 2395 hi->hi_kstatp->ks_data_size +=
2381 2396 KSTAT_NAMED_STR_BUFLEN(&(hi->hi_kstats.hook_hintvalue)) + 1;
2382 2397
2383 2398 kstat_install(hi->hi_kstatp);
2384 2399 }
2385 2400
2386 2401 position = 1;
2387 2402 TAILQ_FOREACH(h, &hei->hei_head, hi_entry) {
2388 2403 h->hi_kstats.hook_position.value.ui32 = position++;
2389 2404 }
2390 2405 }
2391 2406
2392 2407 /*
2393 2408 * Function: hook_int_free
2394 2409 * Returns: None
2395 2410 * Parameters: hi(I) - internal hook pointer
2396 2411 *
2397 2412 * Free memory allocated to support a hook.
2398 2413 */
2399 2414 static void
2400 2415 hook_int_free(hook_int_t *hi, netstackid_t stackid)
2401 2416 {
2402 2417 int len;
2403 2418
2404 2419 ASSERT(hi != NULL);
2405 2420
2406 2421 /* Free name space */
2407 2422 if (hi->hi_hook.h_name != NULL) {
2408 2423 kmem_free(hi->hi_hook.h_name, strlen(hi->hi_hook.h_name) + 1);
2409 2424 }
2410 2425 if (hi->hi_ksname != NULL) {
2411 2426 kmem_free(hi->hi_ksname, strlen(hi->hi_ksname) + 1);
2412 2427 }
2413 2428
2414 2429 /* Free the name used with the before/after hints. */
2415 2430 switch (hi->hi_hook.h_hint) {
2416 2431 case HH_BEFORE :
2417 2432 case HH_AFTER :
2418 2433 len = strlen((char *)hi->hi_hook.h_hintvalue);
2419 2434 if (len > 0)
2420 2435 kmem_free((void *)hi->hi_hook.h_hintvalue, len + 1);
2421 2436 break;
2422 2437 default :
2423 2438 break;
2424 2439 }
2425 2440
2426 2441 if (hi->hi_kstatp != NULL)
2427 2442 kstat_delete_netstack(hi->hi_kstatp, stackid);
2428 2443
2429 2444 /* Free container */
2430 2445 kmem_free(hi, sizeof (*hi));
2431 2446 }
2432 2447
2433 2448 /*
2434 2449 * Function: hook_alloc
2435 2450 * Returns: hook_t * - pointer to new hook structure
2436 2451 * Parameters: version(I) - version number of the API when compiled
2437 2452 *
2438 2453 * This function serves as the interface for consumers to obtain a hook_t
2439 2454 * structure. At this point in time, there is only a single "version" of
2440 2455 * it, leading to a straight forward function. In a perfect world the
2441 2456 * h_vesion would be a protected data structure member, but C isn't that
2442 2457 * advanced...
2443 2458 */
2444 2459 hook_t *
2445 2460 hook_alloc(const int h_version)
2446 2461 {
2447 2462 hook_t *h;
2448 2463
2449 2464 h = kmem_zalloc(sizeof (hook_t), KM_SLEEP);
2450 2465 h->h_version = h_version;
2451 2466 return (h);
2452 2467 }
2453 2468
2454 2469 /*
2455 2470 * Function: hook_free
2456 2471 * Returns: None
2457 2472 * Parameters: h(I) - external hook pointer
2458 2473 *
2459 2474 * This function only free's memory allocated with hook_alloc(), so that if
2460 2475 * (for example) kernel memory was allocated for h_name, this needs to be
2461 2476 * free'd before calling hook_free().
2462 2477 */
2463 2478 void
2464 2479 hook_free(hook_t *h)
2465 2480 {
2466 2481 kmem_free(h, sizeof (*h));
2467 2482 }
2468 2483
2469 2484 /*
2470 2485 * Function: hook_notify_register
2471 2486 * Returns: int - 0 = success, else failure
2472 2487 * Parameters: head(I) - top of the list of callbacks
2473 2488 * callback(I) - function to be called
2474 2489 * arg(I) - arg to pass back to the function
2475 2490 *
2476 2491 * This function implements the modification of the list of callbacks
2477 2492 * that are registered when someone wants to be advised of a change
2478 2493 * that has happened.
2479 2494 */
2480 2495 static int
2481 2496 hook_notify_register(hook_notify_head_t *head, hook_notify_fn_t callback,
2482 2497 void *arg)
2483 2498 {
2484 2499 hook_notify_t *hn;
2485 2500
2486 2501 TAILQ_FOREACH(hn, head, hn_entry) {
2487 2502 if (hn->hn_func == callback) {
2488 2503 return (EEXIST);
2489 2504 }
2490 2505 }
2491 2506
2492 2507 hn = (hook_notify_t *)kmem_alloc(sizeof (*hn), KM_SLEEP);
2493 2508 hn->hn_func = callback;
2494 2509 hn->hn_arg = arg;
2495 2510 TAILQ_INSERT_TAIL(head, hn, hn_entry);
2496 2511
2497 2512 return (0);
2498 2513 }
2499 2514
2500 2515 /*
2501 2516 * Function: hook_notify_unregister
2502 2517 * Returns: int - 0 = success, else failure
2503 2518 * Parameters: stackid(I) - netstack identifier
2504 2519 * callback(I) - function to be called
2505 2520 * parg(O) - pointer to storage for pointer
2506 2521 *
2507 2522 * When calling this function, the provision of a valid pointer in parg
2508 2523 * allows the caller to be made aware of what argument the hook function
2509 2524 * was expecting. This then allows the simulation of HN_UNREGISTER events
2510 2525 * when a notify-unregister is performed.
2511 2526 */
2512 2527 static int
2513 2528 hook_notify_unregister(hook_notify_head_t *head,
2514 2529 hook_notify_fn_t callback, void **parg)
2515 2530 {
2516 2531 hook_notify_t *hn;
2517 2532
2518 2533 ASSERT(parg != NULL);
2519 2534
2520 2535 TAILQ_FOREACH(hn, head, hn_entry) {
2521 2536 if (hn->hn_func == callback)
2522 2537 break;
2523 2538 }
2524 2539
2525 2540 if (hn == NULL)
2526 2541 return (ESRCH);
2527 2542
2528 2543 *parg = hn->hn_arg;
2529 2544
2530 2545 TAILQ_REMOVE(head, hn, hn_entry);
2531 2546
2532 2547 kmem_free(hn, sizeof (*hn));
2533 2548
2534 2549 return (0);
2535 2550 }
2536 2551
2537 2552 /*
2538 2553 * Function: hook_notify_run
2539 2554 * Returns: None
2540 2555 * Parameters: head(I) - top of the list of callbacks
2541 2556 * family(I) - name of the hook family that owns the event
2542 2557 * event(I) - name of the event being changed
2543 2558 * name(I) - name of the object causing change
2544 2559 * cmd(I) - either HN_UNREGISTER or HN_REGISTER
2545 2560 *
2546 2561 * This function walks through the list of registered callbacks and
2547 2562 * executes each one, passing back the arg supplied when registered
2548 2563 * and the name of the family (that owns the event), event (the thing
2549 2564 * to which we're making a change) and finally a name that describes
2550 2565 * what is being added or removed, as indicated by cmd.
2551 2566 *
2552 2567 * This function does not acquire or release any lock as it is required
2553 2568 * that code calling it do so before hand. The use of hook_notify_head_t
2554 2569 * is protected by the use of flagwait_t in the structures that own this
2555 2570 * list and with the use of the FWF_ADD/DEL_ACTIVE flags.
2556 2571 */
2557 2572 static void
2558 2573 hook_notify_run(hook_notify_head_t *head, char *family, char *event,
2559 2574 char *name, hook_notify_cmd_t cmd)
2560 2575 {
2561 2576 hook_notify_t *hn;
2562 2577
2563 2578 TAILQ_FOREACH(hn, head, hn_entry) {
2564 2579 (*hn->hn_func)(cmd, hn->hn_arg, family, event, name);
2565 2580 }
2566 2581 }
|
↓ open down ↓ |
902 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX