Print this page
OS-XXXX netstack_find_by_stackid() drops-and-reacquires
OS-5423 deadlock between netstack teardown and kstat read
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/uts/common/os/netstack.c
+++ new/usr/src/uts/common/os/netstack.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.
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 /*
23 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 * Copyright (c) 2016, Joyent, Inc. All rights reserved.
26 26 */
27 27
28 28 #include <sys/param.h>
29 29 #include <sys/sysmacros.h>
|
↓ open down ↓ |
29 lines elided |
↑ open up ↑ |
30 30 #include <sys/vm.h>
31 31 #include <sys/proc.h>
32 32 #include <sys/tuneable.h>
33 33 #include <sys/systm.h>
34 34 #include <sys/cmn_err.h>
35 35 #include <sys/debug.h>
36 36 #include <sys/sdt.h>
37 37 #include <sys/mutex.h>
38 38 #include <sys/bitmap.h>
39 39 #include <sys/atomic.h>
40 +#include <sys/sunddi.h>
40 41 #include <sys/kobj.h>
41 42 #include <sys/disp.h>
42 43 #include <vm/seg_kmem.h>
43 44 #include <sys/zone.h>
44 45 #include <sys/netstack.h>
45 46
46 47 /*
47 48 * What we use so that the zones framework can tell us about new zones,
48 49 * which we use to create new stacks.
49 50 */
50 51 static zone_key_t netstack_zone_key;
51 52
52 53 static int netstack_initialized = 0;
53 54
54 55 /*
55 56 * Track the registered netstacks.
56 57 * The global lock protects
57 58 * - ns_reg
58 59 * - the list starting at netstack_head and following the netstack_next
59 60 * pointers.
60 61 */
61 62 static kmutex_t netstack_g_lock;
62 63
63 64 /*
64 65 * Registry of netstacks with their create/shutdown/destory functions.
65 66 */
66 67 static struct netstack_registry ns_reg[NS_MAX];
67 68
68 69 /*
69 70 * Global list of existing stacks. We use this when a new zone with
70 71 * an exclusive IP instance is created.
71 72 *
72 73 * Note that in some cases a netstack_t needs to stay around after the zone
73 74 * has gone away. This is because there might be outstanding references
74 75 * (from TCP TIME_WAIT connections, IPsec state, etc). The netstack_t data
75 76 * structure and all the foo_stack_t's hanging off of it will be cleaned up
76 77 * when the last reference to it is dropped.
77 78 * However, the same zone might be rebooted. That is handled using the
78 79 * assumption that the zones framework picks a new zoneid each time a zone
79 80 * is (re)booted. We assert for that condition in netstack_zone_create().
80 81 * Thus the old netstack_t can take its time for things to time out.
81 82 */
82 83 static netstack_t *netstack_head;
83 84
84 85 /*
85 86 * To support kstat_create_netstack() using kstat_zone_add we need
86 87 * to track both
87 88 * - all zoneids that use the global/shared stack
88 89 * - all kstats that have been added for the shared stack
89 90 */
90 91 struct shared_zone_list {
91 92 struct shared_zone_list *sz_next;
92 93 zoneid_t sz_zoneid;
93 94 };
94 95
95 96 struct shared_kstat_list {
96 97 struct shared_kstat_list *sk_next;
97 98 kstat_t *sk_kstat;
98 99 };
99 100
100 101 static kmutex_t netstack_shared_lock; /* protects the following two */
101 102 static struct shared_zone_list *netstack_shared_zones;
102 103 static struct shared_kstat_list *netstack_shared_kstats;
103 104
104 105 static void *netstack_zone_create(zoneid_t zoneid);
105 106 static void netstack_zone_shutdown(zoneid_t zoneid, void *arg);
106 107 static void netstack_zone_destroy(zoneid_t zoneid, void *arg);
107 108
108 109 static void netstack_shared_zone_add(zoneid_t zoneid);
109 110 static void netstack_shared_zone_remove(zoneid_t zoneid);
110 111 static void netstack_shared_kstat_add(kstat_t *ks);
111 112 static void netstack_shared_kstat_remove(kstat_t *ks);
112 113
113 114 typedef boolean_t applyfn_t(kmutex_t *, netstack_t *, int);
114 115
|
↓ open down ↓ |
65 lines elided |
↑ open up ↑ |
115 116 static void apply_all_netstacks(int, applyfn_t *);
116 117 static void apply_all_modules(netstack_t *, applyfn_t *);
117 118 static void apply_all_modules_reverse(netstack_t *, applyfn_t *);
118 119 static boolean_t netstack_apply_create(kmutex_t *, netstack_t *, int);
119 120 static boolean_t netstack_apply_shutdown(kmutex_t *, netstack_t *, int);
120 121 static boolean_t netstack_apply_destroy(kmutex_t *, netstack_t *, int);
121 122 static boolean_t wait_for_zone_creator(netstack_t *, kmutex_t *);
122 123 static boolean_t wait_for_nms_inprogress(netstack_t *, nm_state_t *,
123 124 kmutex_t *);
124 125
126 +static void netstack_hold_locked(netstack_t *);
127 +static void netstack_reap_work(netstack_t *, boolean_t);
128 +ksema_t netstack_reap_limiter;
129 +
125 130 void
126 131 netstack_init(void)
127 132 {
128 133 mutex_init(&netstack_g_lock, NULL, MUTEX_DEFAULT, NULL);
129 134 mutex_init(&netstack_shared_lock, NULL, MUTEX_DEFAULT, NULL);
130 135
136 + /* XXX KEBE SAYS hard-coded constant needs to be fixed. */
137 + sema_init(&netstack_reap_limiter, 1024, NULL, SEMA_DRIVER, NULL);
138 +
131 139 netstack_initialized = 1;
132 140
133 141 /*
134 142 * We want to be informed each time a zone is created or
135 143 * destroyed in the kernel, so we can maintain the
136 144 * stack instance information.
137 145 */
138 146 zone_key_create(&netstack_zone_key, netstack_zone_create,
139 147 netstack_zone_shutdown, netstack_zone_destroy);
140 148 }
141 149
142 150 /*
143 151 * Register a new module with the framework.
144 152 * This registers interest in changes to the set of netstacks.
145 153 * The createfn and destroyfn are required, but the shutdownfn can be
146 154 * NULL.
147 155 * Note that due to the current zsd implementation, when the create
148 156 * function is called the zone isn't fully present, thus functions
149 157 * like zone_find_by_* will fail, hence the create function can not
150 158 * use many zones kernel functions including zcmn_err().
151 159 */
152 160 void
153 161 netstack_register(int moduleid,
154 162 void *(*module_create)(netstackid_t, netstack_t *),
155 163 void (*module_shutdown)(netstackid_t, void *),
156 164 void (*module_destroy)(netstackid_t, void *))
157 165 {
158 166 netstack_t *ns;
159 167
160 168 ASSERT(netstack_initialized);
161 169 ASSERT(moduleid >= 0 && moduleid < NS_MAX);
162 170 ASSERT(module_create != NULL);
163 171
164 172 /*
165 173 * Make instances created after this point in time run the create
166 174 * callback.
167 175 */
168 176 mutex_enter(&netstack_g_lock);
169 177 ASSERT(ns_reg[moduleid].nr_create == NULL);
170 178 ASSERT(ns_reg[moduleid].nr_flags == 0);
171 179 ns_reg[moduleid].nr_create = module_create;
172 180 ns_reg[moduleid].nr_shutdown = module_shutdown;
173 181 ns_reg[moduleid].nr_destroy = module_destroy;
174 182 ns_reg[moduleid].nr_flags = NRF_REGISTERED;
175 183
176 184 /*
177 185 * Determine the set of stacks that exist before we drop the lock.
178 186 * Set NSS_CREATE_NEEDED for each of those.
179 187 * netstacks which have been deleted will have NSS_CREATE_COMPLETED
180 188 * set, but check NSF_CLOSING to be sure.
181 189 */
182 190 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
183 191 nm_state_t *nms = &ns->netstack_m_state[moduleid];
184 192
185 193 mutex_enter(&ns->netstack_lock);
186 194 if (!(ns->netstack_flags & NSF_CLOSING) &&
187 195 (nms->nms_flags & NSS_CREATE_ALL) == 0) {
188 196 nms->nms_flags |= NSS_CREATE_NEEDED;
189 197 DTRACE_PROBE2(netstack__create__needed,
190 198 netstack_t *, ns, int, moduleid);
191 199 }
192 200 mutex_exit(&ns->netstack_lock);
193 201 }
194 202 mutex_exit(&netstack_g_lock);
195 203
196 204 /*
197 205 * At this point in time a new instance can be created or an instance
198 206 * can be destroyed, or some other module can register or unregister.
199 207 * Make sure we either run all the create functions for this moduleid
200 208 * or we wait for any other creators for this moduleid.
201 209 */
202 210 apply_all_netstacks(moduleid, netstack_apply_create);
203 211 }
204 212
205 213 void
206 214 netstack_unregister(int moduleid)
207 215 {
208 216 netstack_t *ns;
209 217
210 218 ASSERT(moduleid >= 0 && moduleid < NS_MAX);
211 219
212 220 ASSERT(ns_reg[moduleid].nr_create != NULL);
213 221 ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
214 222
215 223 mutex_enter(&netstack_g_lock);
216 224 /*
217 225 * Determine the set of stacks that exist before we drop the lock.
218 226 * Set NSS_SHUTDOWN_NEEDED and NSS_DESTROY_NEEDED for each of those.
219 227 * That ensures that when we return all the callbacks for existing
220 228 * instances have completed. And since we set NRF_DYING no new
221 229 * instances can use this module.
222 230 */
223 231 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
224 232 boolean_t created = B_FALSE;
225 233 nm_state_t *nms = &ns->netstack_m_state[moduleid];
226 234
227 235 mutex_enter(&ns->netstack_lock);
228 236
229 237 /*
230 238 * We need to be careful here. We could actually have a netstack
231 239 * being created as we speak waiting for us to let go of this
232 240 * lock to proceed. It may have set NSS_CREATE_NEEDED, but not
233 241 * have gotten to the point of completing it yet. If
234 242 * NSS_CREATE_NEEDED, we can safely just remove it here and
235 243 * never create the module. However, if NSS_CREATE_INPROGRESS is
236 244 * set, we need to still flag this module for shutdown and
237 245 * deletion, just as though it had reached NSS_CREATE_COMPLETED.
238 246 *
239 247 * It is safe to do that because of two different guarantees
240 248 * that exist in the system. The first is that before we do a
241 249 * create, shutdown, or destroy, we ensure that nothing else is
242 250 * in progress in the system for this netstack and wait for it
243 251 * to complete. Secondly, because the zone is being created, we
244 252 * know that the following call to apply_all_netstack will block
245 253 * on the zone finishing its initialization.
246 254 */
247 255 if (nms->nms_flags & NSS_CREATE_NEEDED)
248 256 nms->nms_flags &= ~NSS_CREATE_NEEDED;
249 257
250 258 if (nms->nms_flags & NSS_CREATE_INPROGRESS ||
251 259 nms->nms_flags & NSS_CREATE_COMPLETED)
252 260 created = B_TRUE;
253 261
254 262 if (ns_reg[moduleid].nr_shutdown != NULL && created &&
255 263 (nms->nms_flags & NSS_CREATE_COMPLETED) &&
256 264 (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
257 265 nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
258 266 DTRACE_PROBE2(netstack__shutdown__needed,
259 267 netstack_t *, ns, int, moduleid);
260 268 }
261 269 if ((ns_reg[moduleid].nr_flags & NRF_REGISTERED) &&
262 270 ns_reg[moduleid].nr_destroy != NULL && created &&
263 271 (nms->nms_flags & NSS_DESTROY_ALL) == 0) {
264 272 nms->nms_flags |= NSS_DESTROY_NEEDED;
265 273 DTRACE_PROBE2(netstack__destroy__needed,
266 274 netstack_t *, ns, int, moduleid);
267 275 }
268 276 mutex_exit(&ns->netstack_lock);
269 277 }
270 278 /*
271 279 * Prevent any new netstack from calling the registered create
272 280 * function, while keeping the function pointers in place until the
273 281 * shutdown and destroy callbacks are complete.
274 282 */
275 283 ns_reg[moduleid].nr_flags |= NRF_DYING;
276 284 mutex_exit(&netstack_g_lock);
277 285
278 286 apply_all_netstacks(moduleid, netstack_apply_shutdown);
279 287 apply_all_netstacks(moduleid, netstack_apply_destroy);
280 288
281 289 /*
282 290 * Clear the nms_flags so that we can handle this module
283 291 * being loaded again.
284 292 * Also remove the registered functions.
285 293 */
286 294 mutex_enter(&netstack_g_lock);
287 295 ASSERT(ns_reg[moduleid].nr_flags & NRF_REGISTERED);
288 296 ASSERT(ns_reg[moduleid].nr_flags & NRF_DYING);
289 297 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
290 298 nm_state_t *nms = &ns->netstack_m_state[moduleid];
291 299
292 300 mutex_enter(&ns->netstack_lock);
293 301 if (nms->nms_flags & NSS_DESTROY_COMPLETED) {
294 302 nms->nms_flags = 0;
295 303 DTRACE_PROBE2(netstack__destroy__done,
296 304 netstack_t *, ns, int, moduleid);
297 305 }
298 306 mutex_exit(&ns->netstack_lock);
299 307 }
300 308
301 309 ns_reg[moduleid].nr_create = NULL;
302 310 ns_reg[moduleid].nr_shutdown = NULL;
303 311 ns_reg[moduleid].nr_destroy = NULL;
304 312 ns_reg[moduleid].nr_flags = 0;
305 313 mutex_exit(&netstack_g_lock);
306 314 }
307 315
308 316 /*
309 317 * Lookup and/or allocate a netstack for this zone.
310 318 */
311 319 static void *
312 320 netstack_zone_create(zoneid_t zoneid)
313 321 {
314 322 netstackid_t stackid;
315 323 netstack_t *ns;
316 324 netstack_t **nsp;
317 325 zone_t *zone;
318 326 int i;
319 327
320 328 ASSERT(netstack_initialized);
321 329
322 330 zone = zone_find_by_id_nolock(zoneid);
323 331 ASSERT(zone != NULL);
324 332
325 333 if (zone->zone_flags & ZF_NET_EXCL) {
326 334 stackid = zoneid;
327 335 } else {
328 336 /* Look for the stack instance for the global */
329 337 stackid = GLOBAL_NETSTACKID;
330 338 }
331 339
332 340 /* Allocate even if it isn't needed; simplifies locking */
333 341 ns = (netstack_t *)kmem_zalloc(sizeof (netstack_t), KM_SLEEP);
334 342
335 343 /* Look if there is a matching stack instance */
336 344 mutex_enter(&netstack_g_lock);
337 345 for (nsp = &netstack_head; *nsp != NULL;
338 346 nsp = &((*nsp)->netstack_next)) {
339 347 if ((*nsp)->netstack_stackid == stackid) {
340 348 /*
341 349 * Should never find a pre-existing exclusive stack
342 350 */
343 351 VERIFY(stackid == GLOBAL_NETSTACKID);
344 352 kmem_free(ns, sizeof (netstack_t));
345 353 ns = *nsp;
346 354 mutex_enter(&ns->netstack_lock);
347 355 ns->netstack_numzones++;
348 356 mutex_exit(&ns->netstack_lock);
349 357 mutex_exit(&netstack_g_lock);
350 358 DTRACE_PROBE1(netstack__inc__numzones,
351 359 netstack_t *, ns);
352 360 /* Record that we have a new shared stack zone */
353 361 netstack_shared_zone_add(zoneid);
354 362 zone->zone_netstack = ns;
355 363 return (ns);
356 364 }
357 365 }
358 366 /* Not found */
359 367 mutex_init(&ns->netstack_lock, NULL, MUTEX_DEFAULT, NULL);
360 368 cv_init(&ns->netstack_cv, NULL, CV_DEFAULT, NULL);
361 369 ns->netstack_stackid = zoneid;
362 370 ns->netstack_numzones = 1;
363 371 ns->netstack_refcnt = 1; /* Decremented by netstack_zone_destroy */
364 372 ns->netstack_flags = NSF_UNINIT;
365 373 *nsp = ns;
366 374 zone->zone_netstack = ns;
367 375
368 376 mutex_enter(&ns->netstack_lock);
369 377 /*
370 378 * Mark this netstack as having a CREATE running so
371 379 * any netstack_register/netstack_unregister waits for
372 380 * the existing create callbacks to complete in moduleid order
373 381 */
374 382 ns->netstack_flags |= NSF_ZONE_CREATE;
375 383
376 384 /*
377 385 * Determine the set of module create functions that need to be
378 386 * called before we drop the lock.
379 387 * Set NSS_CREATE_NEEDED for each of those.
380 388 * Skip any with NRF_DYING set, since those are in the process of
381 389 * going away, by checking for flags being exactly NRF_REGISTERED.
382 390 */
383 391 for (i = 0; i < NS_MAX; i++) {
384 392 nm_state_t *nms = &ns->netstack_m_state[i];
385 393
386 394 cv_init(&nms->nms_cv, NULL, CV_DEFAULT, NULL);
387 395
388 396 if ((ns_reg[i].nr_flags == NRF_REGISTERED) &&
389 397 (nms->nms_flags & NSS_CREATE_ALL) == 0) {
390 398 nms->nms_flags |= NSS_CREATE_NEEDED;
391 399 DTRACE_PROBE2(netstack__create__needed,
392 400 netstack_t *, ns, int, i);
393 401 }
394 402 }
395 403 mutex_exit(&ns->netstack_lock);
396 404 mutex_exit(&netstack_g_lock);
397 405
398 406 apply_all_modules(ns, netstack_apply_create);
399 407
400 408 /* Tell any waiting netstack_register/netstack_unregister to proceed */
401 409 mutex_enter(&ns->netstack_lock);
402 410 ns->netstack_flags &= ~NSF_UNINIT;
403 411 ASSERT(ns->netstack_flags & NSF_ZONE_CREATE);
404 412 ns->netstack_flags &= ~NSF_ZONE_CREATE;
405 413 cv_broadcast(&ns->netstack_cv);
406 414 mutex_exit(&ns->netstack_lock);
407 415
408 416 return (ns);
409 417 }
410 418
411 419 /* ARGSUSED */
412 420 static void
413 421 netstack_zone_shutdown(zoneid_t zoneid, void *arg)
414 422 {
415 423 netstack_t *ns = (netstack_t *)arg;
416 424 int i;
417 425
418 426 ASSERT(arg != NULL);
419 427
420 428 mutex_enter(&ns->netstack_lock);
421 429 ASSERT(ns->netstack_numzones > 0);
422 430 if (ns->netstack_numzones != 1) {
423 431 /* Stack instance being used by other zone */
424 432 mutex_exit(&ns->netstack_lock);
425 433 ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
426 434 return;
427 435 }
428 436 mutex_exit(&ns->netstack_lock);
429 437
430 438 mutex_enter(&netstack_g_lock);
431 439 mutex_enter(&ns->netstack_lock);
432 440 /*
433 441 * Mark this netstack as having a SHUTDOWN running so
434 442 * any netstack_register/netstack_unregister waits for
435 443 * the existing create callbacks to complete in moduleid order
436 444 */
437 445 ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
438 446 ns->netstack_flags |= NSF_ZONE_SHUTDOWN;
439 447
440 448 /*
441 449 * Determine the set of stacks that exist before we drop the lock.
442 450 * Set NSS_SHUTDOWN_NEEDED for each of those.
443 451 */
444 452 for (i = 0; i < NS_MAX; i++) {
445 453 nm_state_t *nms = &ns->netstack_m_state[i];
446 454
447 455 if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
448 456 ns_reg[i].nr_shutdown != NULL &&
449 457 (nms->nms_flags & NSS_CREATE_COMPLETED) &&
450 458 (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
451 459 nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
452 460 DTRACE_PROBE2(netstack__shutdown__needed,
453 461 netstack_t *, ns, int, i);
454 462 }
455 463 }
456 464 mutex_exit(&ns->netstack_lock);
457 465 mutex_exit(&netstack_g_lock);
458 466
459 467 /*
460 468 * Call the shutdown function for all registered modules for this
461 469 * netstack.
462 470 */
463 471 apply_all_modules_reverse(ns, netstack_apply_shutdown);
464 472
465 473 /* Tell any waiting netstack_register/netstack_unregister to proceed */
466 474 mutex_enter(&ns->netstack_lock);
467 475 ASSERT(ns->netstack_flags & NSF_ZONE_SHUTDOWN);
468 476 ns->netstack_flags &= ~NSF_ZONE_SHUTDOWN;
469 477 cv_broadcast(&ns->netstack_cv);
470 478 mutex_exit(&ns->netstack_lock);
471 479 }
472 480
473 481 /*
474 482 * Common routine to release a zone.
475 483 * If this was the last zone using the stack instance then prepare to
476 484 * have the refcnt dropping to zero free the zone.
477 485 */
478 486 /* ARGSUSED */
479 487 static void
480 488 netstack_zone_destroy(zoneid_t zoneid, void *arg)
481 489 {
482 490 netstack_t *ns = (netstack_t *)arg;
483 491
484 492 ASSERT(arg != NULL);
485 493
486 494 mutex_enter(&ns->netstack_lock);
487 495 ASSERT(ns->netstack_numzones > 0);
488 496 ns->netstack_numzones--;
489 497 if (ns->netstack_numzones != 0) {
490 498 /* Stack instance being used by other zone */
491 499 mutex_exit(&ns->netstack_lock);
492 500 ASSERT(ns->netstack_stackid == GLOBAL_NETSTACKID);
493 501 /* Record that we a shared stack zone has gone away */
494 502 netstack_shared_zone_remove(zoneid);
495 503 return;
496 504 }
497 505 /*
498 506 * Set CLOSING so that netstack_find_by will not find it.
499 507 */
500 508 ns->netstack_flags |= NSF_CLOSING;
501 509 mutex_exit(&ns->netstack_lock);
502 510 DTRACE_PROBE1(netstack__dec__numzones, netstack_t *, ns);
503 511 /* No other thread can call zone_destroy for this stack */
504 512
505 513 /*
506 514 * Decrease refcnt to account for the one in netstack_zone_init()
507 515 */
508 516 netstack_rele(ns);
509 517 }
510 518
511 519 /*
512 520 * Called when the reference count drops to zero.
513 521 * Call the destroy functions for each registered module.
514 522 */
515 523 static void
516 524 netstack_stack_inactive(netstack_t *ns)
517 525 {
518 526 int i;
519 527
520 528 mutex_enter(&netstack_g_lock);
521 529 mutex_enter(&ns->netstack_lock);
522 530 /*
523 531 * Mark this netstack as having a DESTROY running so
524 532 * any netstack_register/netstack_unregister waits for
525 533 * the existing destroy callbacks to complete in reverse moduleid order
526 534 */
527 535 ASSERT(!(ns->netstack_flags & NSF_ZONE_INPROGRESS));
528 536 ns->netstack_flags |= NSF_ZONE_DESTROY;
529 537 /*
530 538 * If the shutdown callback wasn't called earlier (e.g., if this is
531 539 * a netstack shared between multiple zones), then we schedule it now.
532 540 *
533 541 * Determine the set of stacks that exist before we drop the lock.
534 542 * Set NSS_DESTROY_NEEDED for each of those. That
535 543 * ensures that when we return all the callbacks for existing
536 544 * instances have completed.
537 545 */
538 546 for (i = 0; i < NS_MAX; i++) {
539 547 nm_state_t *nms = &ns->netstack_m_state[i];
540 548
541 549 if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
542 550 ns_reg[i].nr_shutdown != NULL &&
543 551 (nms->nms_flags & NSS_CREATE_COMPLETED) &&
544 552 (nms->nms_flags & NSS_SHUTDOWN_ALL) == 0) {
545 553 nms->nms_flags |= NSS_SHUTDOWN_NEEDED;
546 554 DTRACE_PROBE2(netstack__shutdown__needed,
547 555 netstack_t *, ns, int, i);
548 556 }
549 557
550 558 if ((ns_reg[i].nr_flags & NRF_REGISTERED) &&
551 559 ns_reg[i].nr_destroy != NULL &&
552 560 (nms->nms_flags & NSS_CREATE_COMPLETED) &&
553 561 (nms->nms_flags & NSS_DESTROY_ALL) == 0) {
554 562 nms->nms_flags |= NSS_DESTROY_NEEDED;
555 563 DTRACE_PROBE2(netstack__destroy__needed,
556 564 netstack_t *, ns, int, i);
557 565 }
558 566 }
559 567 mutex_exit(&ns->netstack_lock);
560 568 mutex_exit(&netstack_g_lock);
561 569
562 570 /*
563 571 * Call the shutdown and destroy functions for all registered modules
564 572 * for this netstack.
565 573 *
566 574 * Since there are some ordering dependencies between the modules we
567 575 * tear them down in the reverse order of what was used to create them.
568 576 *
569 577 * Since a netstack_t is never reused (when a zone is rebooted it gets
570 578 * a new zoneid == netstackid i.e. a new netstack_t is allocated) we
571 579 * leave nms_flags the way it is i.e. with NSS_DESTROY_COMPLETED set.
572 580 * That is different than in the netstack_unregister() case.
573 581 */
574 582 apply_all_modules_reverse(ns, netstack_apply_shutdown);
575 583 apply_all_modules_reverse(ns, netstack_apply_destroy);
576 584
577 585 /* Tell any waiting netstack_register/netstack_unregister to proceed */
578 586 mutex_enter(&ns->netstack_lock);
579 587 ASSERT(ns->netstack_flags & NSF_ZONE_DESTROY);
580 588 ns->netstack_flags &= ~NSF_ZONE_DESTROY;
581 589 cv_broadcast(&ns->netstack_cv);
582 590 mutex_exit(&ns->netstack_lock);
583 591 }
584 592
585 593 /*
586 594 * Apply a function to all netstacks for a particular moduleid.
587 595 *
588 596 * If there is any zone activity (due to a zone being created, shutdown,
589 597 * or destroyed) we wait for that to complete before we proceed. This ensures
590 598 * that the moduleids are processed in order when a zone is created or
591 599 * destroyed.
592 600 *
593 601 * The applyfn has to drop netstack_g_lock if it does some work.
594 602 * In that case we don't follow netstack_next,
595 603 * even if it is possible to do so without any hazards. This is
596 604 * because we want the design to allow for the list of netstacks threaded
597 605 * by netstack_next to change in any arbitrary way during the time the
598 606 * lock was dropped.
599 607 *
600 608 * It is safe to restart the loop at netstack_head since the applyfn
601 609 * changes netstack_m_state as it processes things, so a subsequent
602 610 * pass through will have no effect in applyfn, hence the loop will terminate
603 611 * in at worst O(N^2).
604 612 */
605 613 static void
606 614 apply_all_netstacks(int moduleid, applyfn_t *applyfn)
607 615 {
608 616 netstack_t *ns;
609 617
610 618 mutex_enter(&netstack_g_lock);
611 619 ns = netstack_head;
612 620 while (ns != NULL) {
613 621 if (wait_for_zone_creator(ns, &netstack_g_lock)) {
614 622 /* Lock dropped - restart at head */
615 623 ns = netstack_head;
616 624 } else if ((applyfn)(&netstack_g_lock, ns, moduleid)) {
617 625 /* Lock dropped - restart at head */
618 626 ns = netstack_head;
619 627 } else {
620 628 ns = ns->netstack_next;
621 629 }
622 630 }
623 631 mutex_exit(&netstack_g_lock);
624 632 }
625 633
626 634 /*
627 635 * Apply a function to all moduleids for a particular netstack.
628 636 *
629 637 * Since the netstack linkage doesn't matter in this case we can
630 638 * ignore whether the function drops the lock.
631 639 */
632 640 static void
633 641 apply_all_modules(netstack_t *ns, applyfn_t *applyfn)
634 642 {
635 643 int i;
636 644
637 645 mutex_enter(&netstack_g_lock);
638 646 for (i = 0; i < NS_MAX; i++) {
639 647 /*
640 648 * We don't care whether the lock was dropped
641 649 * since we are not iterating over netstack_head.
642 650 */
643 651 (void) (applyfn)(&netstack_g_lock, ns, i);
644 652 }
645 653 mutex_exit(&netstack_g_lock);
646 654 }
647 655
648 656 /* Like the above but in reverse moduleid order */
649 657 static void
650 658 apply_all_modules_reverse(netstack_t *ns, applyfn_t *applyfn)
651 659 {
652 660 int i;
653 661
654 662 mutex_enter(&netstack_g_lock);
655 663 for (i = NS_MAX-1; i >= 0; i--) {
656 664 /*
657 665 * We don't care whether the lock was dropped
658 666 * since we are not iterating over netstack_head.
659 667 */
660 668 (void) (applyfn)(&netstack_g_lock, ns, i);
661 669 }
662 670 mutex_exit(&netstack_g_lock);
663 671 }
664 672
665 673 /*
666 674 * Call the create function for the ns and moduleid if CREATE_NEEDED
667 675 * is set.
668 676 * If some other thread gets here first and sets *_INPROGRESS, then
669 677 * we wait for that thread to complete so that we can ensure that
670 678 * all the callbacks are done when we've looped over all netstacks/moduleids.
671 679 *
672 680 * When we call the create function, we temporarily drop the netstack_lock
673 681 * held by the caller, and return true to tell the caller it needs to
674 682 * re-evalute the state.
675 683 */
676 684 static boolean_t
677 685 netstack_apply_create(kmutex_t *lockp, netstack_t *ns, int moduleid)
678 686 {
679 687 void *result;
680 688 netstackid_t stackid;
681 689 nm_state_t *nms = &ns->netstack_m_state[moduleid];
682 690 boolean_t dropped = B_FALSE;
683 691
684 692 ASSERT(MUTEX_HELD(lockp));
685 693 mutex_enter(&ns->netstack_lock);
686 694
687 695 if (wait_for_nms_inprogress(ns, nms, lockp))
688 696 dropped = B_TRUE;
689 697
690 698 if (nms->nms_flags & NSS_CREATE_NEEDED) {
691 699 nms->nms_flags &= ~NSS_CREATE_NEEDED;
692 700 nms->nms_flags |= NSS_CREATE_INPROGRESS;
693 701 DTRACE_PROBE2(netstack__create__inprogress,
694 702 netstack_t *, ns, int, moduleid);
695 703 mutex_exit(&ns->netstack_lock);
696 704 mutex_exit(lockp);
697 705 dropped = B_TRUE;
698 706
699 707 ASSERT(ns_reg[moduleid].nr_create != NULL);
700 708 stackid = ns->netstack_stackid;
701 709 DTRACE_PROBE2(netstack__create__start,
702 710 netstackid_t, stackid,
703 711 netstack_t *, ns);
704 712 result = (ns_reg[moduleid].nr_create)(stackid, ns);
705 713 DTRACE_PROBE2(netstack__create__end,
706 714 void *, result, netstack_t *, ns);
707 715
708 716 ASSERT(result != NULL);
709 717 mutex_enter(lockp);
710 718 mutex_enter(&ns->netstack_lock);
711 719 ns->netstack_modules[moduleid] = result;
712 720 nms->nms_flags &= ~NSS_CREATE_INPROGRESS;
713 721 nms->nms_flags |= NSS_CREATE_COMPLETED;
714 722 cv_broadcast(&nms->nms_cv);
715 723 DTRACE_PROBE2(netstack__create__completed,
716 724 netstack_t *, ns, int, moduleid);
717 725 mutex_exit(&ns->netstack_lock);
718 726 return (dropped);
719 727 } else {
720 728 mutex_exit(&ns->netstack_lock);
721 729 return (dropped);
722 730 }
723 731 }
724 732
725 733 /*
726 734 * Call the shutdown function for the ns and moduleid if SHUTDOWN_NEEDED
727 735 * is set.
728 736 * If some other thread gets here first and sets *_INPROGRESS, then
729 737 * we wait for that thread to complete so that we can ensure that
730 738 * all the callbacks are done when we've looped over all netstacks/moduleids.
731 739 *
732 740 * When we call the shutdown function, we temporarily drop the netstack_lock
733 741 * held by the caller, and return true to tell the caller it needs to
734 742 * re-evalute the state.
735 743 */
736 744 static boolean_t
737 745 netstack_apply_shutdown(kmutex_t *lockp, netstack_t *ns, int moduleid)
738 746 {
739 747 netstackid_t stackid;
740 748 void * netstack_module;
741 749 nm_state_t *nms = &ns->netstack_m_state[moduleid];
742 750 boolean_t dropped = B_FALSE;
743 751
744 752 ASSERT(MUTEX_HELD(lockp));
745 753 mutex_enter(&ns->netstack_lock);
746 754
747 755 if (wait_for_nms_inprogress(ns, nms, lockp))
748 756 dropped = B_TRUE;
749 757
750 758 if (nms->nms_flags & NSS_SHUTDOWN_NEEDED) {
751 759 nms->nms_flags &= ~NSS_SHUTDOWN_NEEDED;
752 760 nms->nms_flags |= NSS_SHUTDOWN_INPROGRESS;
753 761 DTRACE_PROBE2(netstack__shutdown__inprogress,
754 762 netstack_t *, ns, int, moduleid);
755 763 mutex_exit(&ns->netstack_lock);
756 764 mutex_exit(lockp);
757 765 dropped = B_TRUE;
758 766
759 767 ASSERT(ns_reg[moduleid].nr_shutdown != NULL);
760 768 stackid = ns->netstack_stackid;
761 769 netstack_module = ns->netstack_modules[moduleid];
762 770 DTRACE_PROBE2(netstack__shutdown__start,
763 771 netstackid_t, stackid,
764 772 void *, netstack_module);
765 773 (ns_reg[moduleid].nr_shutdown)(stackid, netstack_module);
766 774 DTRACE_PROBE1(netstack__shutdown__end,
767 775 netstack_t *, ns);
768 776
769 777 mutex_enter(lockp);
770 778 mutex_enter(&ns->netstack_lock);
771 779 nms->nms_flags &= ~NSS_SHUTDOWN_INPROGRESS;
772 780 nms->nms_flags |= NSS_SHUTDOWN_COMPLETED;
773 781 cv_broadcast(&nms->nms_cv);
774 782 DTRACE_PROBE2(netstack__shutdown__completed,
775 783 netstack_t *, ns, int, moduleid);
776 784 mutex_exit(&ns->netstack_lock);
777 785 return (dropped);
778 786 } else {
779 787 mutex_exit(&ns->netstack_lock);
780 788 return (dropped);
781 789 }
782 790 }
783 791
784 792 /*
785 793 * Call the destroy function for the ns and moduleid if DESTROY_NEEDED
786 794 * is set.
787 795 * If some other thread gets here first and sets *_INPROGRESS, then
788 796 * we wait for that thread to complete so that we can ensure that
789 797 * all the callbacks are done when we've looped over all netstacks/moduleids.
790 798 *
791 799 * When we call the destroy function, we temporarily drop the netstack_lock
792 800 * held by the caller, and return true to tell the caller it needs to
793 801 * re-evalute the state.
794 802 */
795 803 static boolean_t
796 804 netstack_apply_destroy(kmutex_t *lockp, netstack_t *ns, int moduleid)
797 805 {
798 806 netstackid_t stackid;
799 807 void * netstack_module;
800 808 nm_state_t *nms = &ns->netstack_m_state[moduleid];
801 809 boolean_t dropped = B_FALSE;
802 810
803 811 ASSERT(MUTEX_HELD(lockp));
804 812 mutex_enter(&ns->netstack_lock);
805 813
806 814 if (wait_for_nms_inprogress(ns, nms, lockp))
807 815 dropped = B_TRUE;
808 816
809 817 if (nms->nms_flags & NSS_DESTROY_NEEDED) {
810 818 nms->nms_flags &= ~NSS_DESTROY_NEEDED;
811 819 nms->nms_flags |= NSS_DESTROY_INPROGRESS;
812 820 DTRACE_PROBE2(netstack__destroy__inprogress,
813 821 netstack_t *, ns, int, moduleid);
814 822 mutex_exit(&ns->netstack_lock);
815 823 mutex_exit(lockp);
816 824 dropped = B_TRUE;
817 825
818 826 ASSERT(ns_reg[moduleid].nr_destroy != NULL);
819 827 stackid = ns->netstack_stackid;
820 828 netstack_module = ns->netstack_modules[moduleid];
821 829 DTRACE_PROBE2(netstack__destroy__start,
822 830 netstackid_t, stackid,
823 831 void *, netstack_module);
824 832 (ns_reg[moduleid].nr_destroy)(stackid, netstack_module);
825 833 DTRACE_PROBE1(netstack__destroy__end,
826 834 netstack_t *, ns);
827 835
828 836 mutex_enter(lockp);
829 837 mutex_enter(&ns->netstack_lock);
830 838 ns->netstack_modules[moduleid] = NULL;
831 839 nms->nms_flags &= ~NSS_DESTROY_INPROGRESS;
832 840 nms->nms_flags |= NSS_DESTROY_COMPLETED;
833 841 cv_broadcast(&nms->nms_cv);
834 842 DTRACE_PROBE2(netstack__destroy__completed,
835 843 netstack_t *, ns, int, moduleid);
836 844 mutex_exit(&ns->netstack_lock);
837 845 return (dropped);
838 846 } else {
839 847 mutex_exit(&ns->netstack_lock);
840 848 return (dropped);
841 849 }
842 850 }
843 851
844 852 /*
845 853 * If somebody is creating the netstack (due to a new zone being created)
846 854 * then we wait for them to complete. This ensures that any additional
847 855 * netstack_register() doesn't cause the create functions to run out of
848 856 * order.
849 857 * Note that we do not need such a global wait in the case of the shutdown
850 858 * and destroy callbacks, since in that case it is sufficient for both
851 859 * threads to set NEEDED and wait for INPROGRESS to ensure ordering.
852 860 * Returns true if lockp was temporarily dropped while waiting.
853 861 */
854 862 static boolean_t
855 863 wait_for_zone_creator(netstack_t *ns, kmutex_t *lockp)
856 864 {
857 865 boolean_t dropped = B_FALSE;
858 866
859 867 mutex_enter(&ns->netstack_lock);
860 868 while (ns->netstack_flags & NSF_ZONE_CREATE) {
861 869 DTRACE_PROBE1(netstack__wait__zone__inprogress,
862 870 netstack_t *, ns);
863 871 if (lockp != NULL) {
864 872 dropped = B_TRUE;
865 873 mutex_exit(lockp);
866 874 }
867 875 cv_wait(&ns->netstack_cv, &ns->netstack_lock);
868 876 if (lockp != NULL) {
869 877 /* First drop netstack_lock to preserve order */
870 878 mutex_exit(&ns->netstack_lock);
871 879 mutex_enter(lockp);
872 880 mutex_enter(&ns->netstack_lock);
873 881 }
874 882 }
875 883 mutex_exit(&ns->netstack_lock);
876 884 return (dropped);
877 885 }
878 886
879 887 /*
880 888 * Wait for any INPROGRESS flag to be cleared for the netstack/moduleid
881 889 * combination.
882 890 * Returns true if lockp was temporarily dropped while waiting.
883 891 */
884 892 static boolean_t
885 893 wait_for_nms_inprogress(netstack_t *ns, nm_state_t *nms, kmutex_t *lockp)
886 894 {
887 895 boolean_t dropped = B_FALSE;
888 896
889 897 while (nms->nms_flags & NSS_ALL_INPROGRESS) {
890 898 DTRACE_PROBE2(netstack__wait__nms__inprogress,
891 899 netstack_t *, ns, nm_state_t *, nms);
892 900 if (lockp != NULL) {
893 901 dropped = B_TRUE;
894 902 mutex_exit(lockp);
895 903 }
896 904 cv_wait(&nms->nms_cv, &ns->netstack_lock);
897 905 if (lockp != NULL) {
898 906 /* First drop netstack_lock to preserve order */
899 907 mutex_exit(&ns->netstack_lock);
900 908 mutex_enter(lockp);
901 909 mutex_enter(&ns->netstack_lock);
902 910 }
903 911 }
904 912 return (dropped);
905 913 }
906 914
907 915 /*
908 916 * Get the stack instance used in caller's zone.
909 917 * Increases the reference count, caller must do a netstack_rele.
910 918 * It can't be called after zone_destroy() has started.
911 919 */
912 920 netstack_t *
913 921 netstack_get_current(void)
914 922 {
915 923 netstack_t *ns;
916 924
917 925 ns = curproc->p_zone->zone_netstack;
918 926 ASSERT(ns != NULL);
919 927 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
920 928 return (NULL);
921 929
922 930 netstack_hold(ns);
923 931
924 932 return (ns);
925 933 }
926 934
927 935 /*
928 936 * Find a stack instance given the cred.
929 937 * This is used by the modules to potentially allow for a future when
930 938 * something other than the zoneid is used to determine the stack.
931 939 */
932 940 netstack_t *
933 941 netstack_find_by_cred(const cred_t *cr)
934 942 {
935 943 zoneid_t zoneid = crgetzoneid(cr);
936 944
937 945 /* Handle the case when cr_zone is NULL */
938 946 if (zoneid == (zoneid_t)-1)
939 947 zoneid = GLOBAL_ZONEID;
940 948
941 949 /* For performance ... */
942 950 if (curproc->p_zone->zone_id == zoneid)
943 951 return (netstack_get_current());
944 952 else
945 953 return (netstack_find_by_zoneid(zoneid));
946 954 }
947 955
948 956 /*
949 957 * Find a stack instance given the zoneid.
950 958 * Increases the reference count if found; caller must do a
951 959 * netstack_rele().
952 960 *
953 961 * If there is no exact match then assume the shared stack instance
954 962 * matches.
955 963 *
956 964 * Skip the unitialized ones.
957 965 */
958 966 netstack_t *
959 967 netstack_find_by_zoneid(zoneid_t zoneid)
960 968 {
961 969 netstack_t *ns;
962 970 zone_t *zone;
963 971
964 972 zone = zone_find_by_id(zoneid);
965 973
966 974 if (zone == NULL)
967 975 return (NULL);
968 976
969 977 ns = zone->zone_netstack;
970 978 ASSERT(ns != NULL);
971 979 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
972 980 ns = NULL;
973 981 else
974 982 netstack_hold(ns);
975 983
976 984 zone_rele(zone);
977 985 return (ns);
978 986 }
979 987
980 988 /*
981 989 * Find a stack instance given the zoneid. Can only be called from
982 990 * the create callback. See the comments in zone_find_by_id_nolock why
983 991 * that limitation exists.
984 992 *
985 993 * Increases the reference count if found; caller must do a
986 994 * netstack_rele().
987 995 *
988 996 * If there is no exact match then assume the shared stack instance
989 997 * matches.
990 998 *
991 999 * Skip the unitialized ones.
992 1000 */
993 1001 netstack_t *
994 1002 netstack_find_by_zoneid_nolock(zoneid_t zoneid)
995 1003 {
996 1004 netstack_t *ns;
997 1005 zone_t *zone;
998 1006
999 1007 zone = zone_find_by_id_nolock(zoneid);
1000 1008
1001 1009 if (zone == NULL)
1002 1010 return (NULL);
1003 1011
1004 1012 ns = zone->zone_netstack;
1005 1013 ASSERT(ns != NULL);
1006 1014
1007 1015 if (ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))
1008 1016 ns = NULL;
1009 1017 else
1010 1018 netstack_hold(ns);
1011 1019
1012 1020 /* zone_find_by_id_nolock does not have a hold on the zone */
1013 1021 return (ns);
1014 1022 }
1015 1023
1016 1024 /*
1017 1025 * Find a stack instance given the stackid with exact match?
1018 1026 * Increases the reference count if found; caller must do a
1019 1027 * netstack_rele().
1020 1028 *
1021 1029 * Skip the unitialized ones.
1022 1030 */
|
↓ open down ↓ |
882 lines elided |
↑ open up ↑ |
1023 1031 netstack_t *
1024 1032 netstack_find_by_stackid(netstackid_t stackid)
1025 1033 {
1026 1034 netstack_t *ns;
1027 1035
1028 1036 mutex_enter(&netstack_g_lock);
1029 1037 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
1030 1038 mutex_enter(&ns->netstack_lock);
1031 1039 if (ns->netstack_stackid == stackid &&
1032 1040 !(ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING))) {
1041 + netstack_hold_locked(ns);
1033 1042 mutex_exit(&ns->netstack_lock);
1034 - netstack_hold(ns);
1035 1043 mutex_exit(&netstack_g_lock);
1036 1044 return (ns);
1037 1045 }
1038 1046 mutex_exit(&ns->netstack_lock);
1039 1047 }
1040 1048 mutex_exit(&netstack_g_lock);
1041 1049 return (NULL);
1042 1050 }
1043 1051
1044 1052 boolean_t
1045 1053 netstack_inuse_by_stackid(netstackid_t stackid)
1046 1054 {
1047 1055 netstack_t *ns;
1048 1056 boolean_t rval = B_FALSE;
1049 1057
1050 1058 mutex_enter(&netstack_g_lock);
1051 1059
1052 1060 for (ns = netstack_head; ns != NULL; ns = ns->netstack_next) {
1053 1061 if (ns->netstack_stackid == stackid) {
|
↓ open down ↓ |
9 lines elided |
↑ open up ↑ |
1054 1062 rval = B_TRUE;
1055 1063 break;
1056 1064 }
1057 1065 }
1058 1066
1059 1067 mutex_exit(&netstack_g_lock);
1060 1068
1061 1069 return (rval);
1062 1070 }
1063 1071
1064 -void
1065 -netstack_rele(netstack_t *ns)
1072 +
1073 +static void
1074 +netstack_reap(void *arg)
1066 1075 {
1076 + /* Indicate we took a semaphore to get here. */
1077 + netstack_reap_work((netstack_t *)arg, B_TRUE);
1078 +}
1079 +
1080 +static void
1081 +netstack_reap_intr(void *arg)
1082 +{
1083 + /* Indicate we did NOT TAKE a semaphore to get here. */
1084 + netstack_reap_work((netstack_t *)arg, B_FALSE);
1085 +}
1086 +
1087 +static void
1088 +netstack_reap_work(netstack_t *ns, boolean_t semaphore_signal)
1089 +{
1067 1090 netstack_t **nsp;
1068 1091 boolean_t found;
1069 - int refcnt, numzones;
1070 1092 int i;
1071 1093
1094 + /*
1095 + * Time to call the destroy functions and free up
1096 + * the structure
1097 + */
1098 + netstack_stack_inactive(ns);
1099 +
1100 + /* Make sure nothing increased the references */
1101 + ASSERT(ns->netstack_refcnt == 0);
1102 + ASSERT(ns->netstack_numzones == 0);
1103 +
1104 + /* Finally remove from list of netstacks */
1105 + mutex_enter(&netstack_g_lock);
1106 + found = B_FALSE;
1107 + for (nsp = &netstack_head; *nsp != NULL;
1108 + nsp = &(*nsp)->netstack_next) {
1109 + if (*nsp == ns) {
1110 + *nsp = ns->netstack_next;
1111 + ns->netstack_next = NULL;
1112 + found = B_TRUE;
1113 + break;
1114 + }
1115 + }
1116 + ASSERT(found);
1117 + mutex_exit(&netstack_g_lock);
1118 +
1119 + /* Make sure nothing increased the references */
1120 + ASSERT(ns->netstack_refcnt == 0);
1121 + ASSERT(ns->netstack_numzones == 0);
1122 +
1123 + ASSERT(ns->netstack_flags & NSF_CLOSING);
1124 +
1125 + for (i = 0; i < NS_MAX; i++) {
1126 + nm_state_t *nms = &ns->netstack_m_state[i];
1127 +
1128 + cv_destroy(&nms->nms_cv);
1129 + }
1130 + mutex_destroy(&ns->netstack_lock);
1131 + cv_destroy(&ns->netstack_cv);
1132 + kmem_free(ns, sizeof (*ns));
1133 + /* Allow another reap to be scheduled. */
1134 + if (semaphore_signal)
1135 + sema_v(&netstack_reap_limiter);
1136 +}
1137 +
1138 +void
1139 +netstack_rele(netstack_t *ns)
1140 +{
1141 + int refcnt, numzones;
1142 +
1072 1143 mutex_enter(&ns->netstack_lock);
1073 1144 ASSERT(ns->netstack_refcnt > 0);
1074 1145 ns->netstack_refcnt--;
1075 1146 /*
1076 1147 * As we drop the lock additional netstack_rele()s can come in
1077 1148 * and decrement the refcnt to zero and free the netstack_t.
1078 1149 * Store pointers in local variables and if we were not the last
1079 1150 * then don't reference the netstack_t after that.
1080 1151 */
1081 1152 refcnt = ns->netstack_refcnt;
1082 1153 numzones = ns->netstack_numzones;
1083 1154 DTRACE_PROBE1(netstack__dec__ref, netstack_t *, ns);
1084 1155 mutex_exit(&ns->netstack_lock);
1085 1156
1086 1157 if (refcnt == 0 && numzones == 0) {
1158 + boolean_t is_not_intr = !servicing_interrupt();
1159 +
1087 1160 /*
1088 - * Time to call the destroy functions and free up
1089 - * the structure
1161 + * Because there are possibilities of kstats being held by
1162 + * callers, which would then be immediately freed, but held up
1163 + * due to kstat's odd reference model recording the thread, we
1164 + * choose to schedule the actual deletion of this netstack as
1165 + * a deferred task on the system taskq. This way, any
1166 + * store-the-thread-pointer semantics won't trip over
1167 + * themselves.
1168 + *
1169 + * On the off chance this is called in interrupt context, we
1170 + * cannot use the semaphore to enforce rate-limiting.
1090 1171 */
1091 - netstack_stack_inactive(ns);
1172 + if (is_not_intr && sema_tryp(&netstack_reap_limiter) == 0) {
1173 + /*
1174 + * XXX KEBE SAYS inidicate we're slamming against
1175 + * a limit.
1176 + */
1177 + hrtime_t measurement = gethrtime();
1092 1178
1093 - /* Make sure nothing increased the references */
1094 - ASSERT(ns->netstack_refcnt == 0);
1095 - ASSERT(ns->netstack_numzones == 0);
1096 -
1097 - /* Finally remove from list of netstacks */
1098 - mutex_enter(&netstack_g_lock);
1099 - found = B_FALSE;
1100 - for (nsp = &netstack_head; *nsp != NULL;
1101 - nsp = &(*nsp)->netstack_next) {
1102 - if (*nsp == ns) {
1103 - *nsp = ns->netstack_next;
1104 - ns->netstack_next = NULL;
1105 - found = B_TRUE;
1106 - break;
1107 - }
1179 + sema_p(&netstack_reap_limiter);
1180 + /* Caputre delay in ns. */
1181 + DTRACE_PROBE1(netstack__reap__rate__limited,
1182 + hrtime_t *, gethrtime() - measurement);
1108 1183 }
1109 - ASSERT(found);
1110 - mutex_exit(&netstack_g_lock);
1111 1184
1112 - /* Make sure nothing increased the references */
1113 - ASSERT(ns->netstack_refcnt == 0);
1114 - ASSERT(ns->netstack_numzones == 0);
1115 -
1116 - ASSERT(ns->netstack_flags & NSF_CLOSING);
1117 -
1118 - for (i = 0; i < NS_MAX; i++) {
1119 - nm_state_t *nms = &ns->netstack_m_state[i];
1120 -
1121 - cv_destroy(&nms->nms_cv);
1185 + if (taskq_dispatch(system_taskq,
1186 + is_not_intr ? netstack_reap : netstack_reap_intr, ns,
1187 + TQ_NOSLEEP) == NULL) {
1188 + /*
1189 + * Well shoot, why can't we taskq_dispatch?
1190 + * Take our chances with a direct call.
1191 + */
1192 + DTRACE_PROBE1(netstack__reap__taskq__fail,
1193 + netstack_t *, ns);
1194 + netstack_reap_work(ns, is_not_intr);
1122 1195 }
1123 - mutex_destroy(&ns->netstack_lock);
1124 - cv_destroy(&ns->netstack_cv);
1125 - kmem_free(ns, sizeof (*ns));
1126 1196 }
1127 1197 }
1128 1198
1199 +static void
1200 +netstack_hold_locked(netstack_t *ns)
1201 +{
1202 + ASSERT(MUTEX_HELD(&ns->netstack_lock));
1203 + ns->netstack_refcnt++;
1204 + ASSERT(ns->netstack_refcnt > 0);
1205 + DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
1206 +}
1207 +
1129 1208 void
1130 1209 netstack_hold(netstack_t *ns)
1131 1210 {
1132 1211 mutex_enter(&ns->netstack_lock);
1133 - ns->netstack_refcnt++;
1134 - ASSERT(ns->netstack_refcnt > 0);
1212 + netstack_hold_locked(ns);
1135 1213 mutex_exit(&ns->netstack_lock);
1136 - DTRACE_PROBE1(netstack__inc__ref, netstack_t *, ns);
1137 1214 }
1138 1215
1139 1216 /*
1140 1217 * To support kstat_create_netstack() using kstat_zone_add we need
1141 1218 * to track both
1142 1219 * - all zoneids that use the global/shared stack
1143 1220 * - all kstats that have been added for the shared stack
1144 1221 */
1145 1222 kstat_t *
1146 1223 kstat_create_netstack(char *ks_module, int ks_instance, char *ks_name,
1147 1224 char *ks_class, uchar_t ks_type, uint_t ks_ndata, uchar_t ks_flags,
1148 1225 netstackid_t ks_netstackid)
1149 1226 {
1150 1227 kstat_t *ks;
1151 1228
1152 1229 if (ks_netstackid == GLOBAL_NETSTACKID) {
1153 1230 ks = kstat_create_zone(ks_module, ks_instance, ks_name,
1154 1231 ks_class, ks_type, ks_ndata, ks_flags, GLOBAL_ZONEID);
1155 1232 if (ks != NULL)
1156 1233 netstack_shared_kstat_add(ks);
1157 1234 return (ks);
1158 1235 } else {
1159 1236 zoneid_t zoneid = ks_netstackid;
1160 1237
1161 1238 return (kstat_create_zone(ks_module, ks_instance, ks_name,
1162 1239 ks_class, ks_type, ks_ndata, ks_flags, zoneid));
1163 1240 }
1164 1241 }
1165 1242
1166 1243 void
1167 1244 kstat_delete_netstack(kstat_t *ks, netstackid_t ks_netstackid)
1168 1245 {
1169 1246 if (ks_netstackid == GLOBAL_NETSTACKID) {
1170 1247 netstack_shared_kstat_remove(ks);
1171 1248 }
1172 1249 kstat_delete(ks);
1173 1250 }
1174 1251
1175 1252 static void
1176 1253 netstack_shared_zone_add(zoneid_t zoneid)
1177 1254 {
1178 1255 struct shared_zone_list *sz;
1179 1256 struct shared_kstat_list *sk;
1180 1257
1181 1258 sz = (struct shared_zone_list *)kmem_zalloc(sizeof (*sz), KM_SLEEP);
1182 1259 sz->sz_zoneid = zoneid;
1183 1260
1184 1261 /* Insert in list */
1185 1262 mutex_enter(&netstack_shared_lock);
1186 1263 sz->sz_next = netstack_shared_zones;
1187 1264 netstack_shared_zones = sz;
1188 1265
1189 1266 /*
1190 1267 * Perform kstat_zone_add for each existing shared stack kstat.
1191 1268 * Note: Holds netstack_shared_lock lock across kstat_zone_add.
1192 1269 */
1193 1270 for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
1194 1271 kstat_zone_add(sk->sk_kstat, zoneid);
1195 1272 }
1196 1273 mutex_exit(&netstack_shared_lock);
1197 1274 }
1198 1275
1199 1276 static void
1200 1277 netstack_shared_zone_remove(zoneid_t zoneid)
1201 1278 {
1202 1279 struct shared_zone_list **szp, *sz;
1203 1280 struct shared_kstat_list *sk;
1204 1281
1205 1282 /* Find in list */
1206 1283 mutex_enter(&netstack_shared_lock);
1207 1284 sz = NULL;
1208 1285 for (szp = &netstack_shared_zones; *szp != NULL;
1209 1286 szp = &((*szp)->sz_next)) {
1210 1287 if ((*szp)->sz_zoneid == zoneid) {
1211 1288 sz = *szp;
1212 1289 break;
1213 1290 }
1214 1291 }
1215 1292 /* We must find it */
1216 1293 ASSERT(sz != NULL);
1217 1294 *szp = sz->sz_next;
1218 1295 sz->sz_next = NULL;
1219 1296
1220 1297 /*
1221 1298 * Perform kstat_zone_remove for each existing shared stack kstat.
1222 1299 * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
1223 1300 */
1224 1301 for (sk = netstack_shared_kstats; sk != NULL; sk = sk->sk_next) {
1225 1302 kstat_zone_remove(sk->sk_kstat, zoneid);
1226 1303 }
1227 1304 mutex_exit(&netstack_shared_lock);
1228 1305
1229 1306 kmem_free(sz, sizeof (*sz));
1230 1307 }
1231 1308
1232 1309 static void
1233 1310 netstack_shared_kstat_add(kstat_t *ks)
1234 1311 {
1235 1312 struct shared_zone_list *sz;
1236 1313 struct shared_kstat_list *sk;
1237 1314
1238 1315 sk = (struct shared_kstat_list *)kmem_zalloc(sizeof (*sk), KM_SLEEP);
1239 1316 sk->sk_kstat = ks;
1240 1317
1241 1318 /* Insert in list */
1242 1319 mutex_enter(&netstack_shared_lock);
1243 1320 sk->sk_next = netstack_shared_kstats;
1244 1321 netstack_shared_kstats = sk;
1245 1322
1246 1323 /*
1247 1324 * Perform kstat_zone_add for each existing shared stack zone.
1248 1325 * Note: Holds netstack_shared_lock lock across kstat_zone_add.
1249 1326 */
1250 1327 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
1251 1328 kstat_zone_add(ks, sz->sz_zoneid);
1252 1329 }
1253 1330 mutex_exit(&netstack_shared_lock);
1254 1331 }
1255 1332
1256 1333 static void
1257 1334 netstack_shared_kstat_remove(kstat_t *ks)
1258 1335 {
1259 1336 struct shared_zone_list *sz;
1260 1337 struct shared_kstat_list **skp, *sk;
1261 1338
1262 1339 /* Find in list */
1263 1340 mutex_enter(&netstack_shared_lock);
1264 1341 sk = NULL;
1265 1342 for (skp = &netstack_shared_kstats; *skp != NULL;
1266 1343 skp = &((*skp)->sk_next)) {
1267 1344 if ((*skp)->sk_kstat == ks) {
1268 1345 sk = *skp;
1269 1346 break;
1270 1347 }
1271 1348 }
1272 1349 /* Must find it */
1273 1350 ASSERT(sk != NULL);
1274 1351 *skp = sk->sk_next;
1275 1352 sk->sk_next = NULL;
1276 1353
1277 1354 /*
1278 1355 * Perform kstat_zone_remove for each existing shared stack kstat.
1279 1356 * Note: Holds netstack_shared_lock lock across kstat_zone_remove.
1280 1357 */
1281 1358 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
1282 1359 kstat_zone_remove(ks, sz->sz_zoneid);
1283 1360 }
1284 1361 mutex_exit(&netstack_shared_lock);
1285 1362 kmem_free(sk, sizeof (*sk));
1286 1363 }
1287 1364
1288 1365 /*
1289 1366 * If a zoneid is part of the shared zone, return true
1290 1367 */
1291 1368 static boolean_t
1292 1369 netstack_find_shared_zoneid(zoneid_t zoneid)
1293 1370 {
1294 1371 struct shared_zone_list *sz;
1295 1372
1296 1373 mutex_enter(&netstack_shared_lock);
1297 1374 for (sz = netstack_shared_zones; sz != NULL; sz = sz->sz_next) {
1298 1375 if (sz->sz_zoneid == zoneid) {
1299 1376 mutex_exit(&netstack_shared_lock);
1300 1377 return (B_TRUE);
1301 1378 }
1302 1379 }
1303 1380 mutex_exit(&netstack_shared_lock);
1304 1381 return (B_FALSE);
1305 1382 }
1306 1383
1307 1384 /*
1308 1385 * Hide the fact that zoneids and netstackids are allocated from
1309 1386 * the same space in the current implementation.
1310 1387 * We currently do not check that the stackid/zoneids are valid, since there
1311 1388 * is no need for that. But this should only be done for ids that are
1312 1389 * valid.
1313 1390 */
1314 1391 zoneid_t
1315 1392 netstackid_to_zoneid(netstackid_t stackid)
1316 1393 {
1317 1394 return (stackid);
1318 1395 }
1319 1396
1320 1397 netstackid_t
1321 1398 zoneid_to_netstackid(zoneid_t zoneid)
1322 1399 {
1323 1400 if (netstack_find_shared_zoneid(zoneid))
1324 1401 return (GLOBAL_ZONEID);
1325 1402 else
1326 1403 return (zoneid);
1327 1404 }
1328 1405
1329 1406 zoneid_t
1330 1407 netstack_get_zoneid(netstack_t *ns)
1331 1408 {
1332 1409 return (netstackid_to_zoneid(ns->netstack_stackid));
1333 1410 }
1334 1411
1335 1412 /*
1336 1413 * Simplistic support for walking all the handles.
1337 1414 * Example usage:
1338 1415 * netstack_handle_t nh;
1339 1416 * netstack_t *ns;
1340 1417 *
1341 1418 * netstack_next_init(&nh);
1342 1419 * while ((ns = netstack_next(&nh)) != NULL) {
1343 1420 * do something;
1344 1421 * netstack_rele(ns);
1345 1422 * }
1346 1423 * netstack_next_fini(&nh);
1347 1424 */
1348 1425 void
1349 1426 netstack_next_init(netstack_handle_t *handle)
1350 1427 {
1351 1428 *handle = 0;
1352 1429 }
1353 1430
1354 1431 /* ARGSUSED */
1355 1432 void
1356 1433 netstack_next_fini(netstack_handle_t *handle)
1357 1434 {
1358 1435 }
1359 1436
1360 1437 netstack_t *
1361 1438 netstack_next(netstack_handle_t *handle)
1362 1439 {
1363 1440 netstack_t *ns;
1364 1441 int i, end;
1365 1442
1366 1443 end = *handle;
1367 1444 /* Walk skipping *handle number of instances */
1368 1445
1369 1446 /* Look if there is a matching stack instance */
1370 1447 mutex_enter(&netstack_g_lock);
1371 1448 ns = netstack_head;
1372 1449 for (i = 0; i < end; i++) {
1373 1450 if (ns == NULL)
1374 1451 break;
1375 1452 ns = ns->netstack_next;
1376 1453 }
1377 1454 /* skip those with that aren't really here */
1378 1455 while (ns != NULL) {
1379 1456 mutex_enter(&ns->netstack_lock);
1380 1457 if ((ns->netstack_flags & (NSF_UNINIT|NSF_CLOSING)) == 0) {
1381 1458 mutex_exit(&ns->netstack_lock);
1382 1459 break;
1383 1460 }
1384 1461 mutex_exit(&ns->netstack_lock);
1385 1462 end++;
1386 1463 ns = ns->netstack_next;
1387 1464 }
1388 1465 if (ns != NULL) {
1389 1466 *handle = end + 1;
1390 1467 netstack_hold(ns);
1391 1468 }
1392 1469 mutex_exit(&netstack_g_lock);
1393 1470 return (ns);
1394 1471 }
|
↓ open down ↓ |
248 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX