Print this page
4229 mdb hangs on exit when long umem cache names exist
Reviewed by: Robert Mustacchi <rm@joyent.com>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/mdb/common/mdb/mdb_nv.c
+++ new/usr/src/cmd/mdb/common/mdb/mdb_nv.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, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 -
27 -#pragma ident "%Z%%M% %I% %E% SMI"
26 +/*
27 + * Copyright (c) 2013 Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
28 + */
28 29
29 30 #include <mdb/mdb_debug.h>
30 31 #include <mdb/mdb_string.h>
31 32 #include <mdb/mdb_modapi.h>
32 33 #include <mdb/mdb_err.h>
33 34 #include <mdb/mdb_nv.h>
34 35 #include <mdb/mdb.h>
35 36
36 37 #define NV_NAME(v) \
37 38 (((v)->v_flags & MDB_NV_EXTNAME) ? (v)->v_ename : (v)->v_lname)
38 39
39 40 #define NV_SIZE(v) \
40 41 (((v)->v_flags & MDB_NV_EXTNAME) ? sizeof (mdb_var_t) : \
41 - sizeof (mdb_var_t) + MDB_NV_NAMELEN - 1)
42 + sizeof (mdb_var_t) + strlen((v)->v_lname))
42 43
43 44 #define NV_HASHSZ 211
44 45
45 46 static size_t
46 47 nv_hashstring(const char *key)
47 48 {
48 49 size_t g, h = 0;
49 50 const char *p;
50 51
51 52 ASSERT(key != NULL);
52 53
53 54 for (p = key; *p != '\0'; p++) {
54 55 h = (h << 4) + *p;
55 56
56 57 if ((g = (h & 0xf0000000)) != 0) {
57 58 h ^= (g >> 24);
58 59 h ^= g;
↓ open down ↓ |
7 lines elided |
↑ open up ↑ |
59 60 }
60 61 }
61 62
62 63 return (h);
63 64 }
64 65
65 66 static mdb_var_t *
66 67 nv_var_alloc(const char *name, const mdb_nv_disc_t *disc,
67 68 uintmax_t value, uint_t flags, uint_t um_flags, mdb_var_t *next)
68 69 {
69 - size_t nbytes = (flags & MDB_NV_EXTNAME) ? sizeof (mdb_var_t) :
70 - (sizeof (mdb_var_t) + MDB_NV_NAMELEN - 1);
70 + size_t nbytes;
71 + mdb_var_t *v;
72 +
73 + if (flags & MDB_NV_EXTNAME)
74 + nbytes = sizeof (mdb_var_t);
75 + else
76 + nbytes = sizeof (mdb_var_t) + strlen(name);
71 77
72 - mdb_var_t *v = mdb_alloc(nbytes, um_flags);
78 + v = mdb_alloc(nbytes, um_flags);
73 79
74 80 if (v == NULL)
75 81 return (NULL);
76 82
77 83 if (flags & MDB_NV_EXTNAME) {
78 84 v->v_ename = name;
79 - v->v_lname[0] = 0;
85 + v->v_lname[0] = '\0';
80 86 } else {
81 - (void) strncpy(v->v_lname, name, MDB_NV_NAMELEN - 1);
82 - v->v_lname[MDB_NV_NAMELEN - 1] = '\0';
87 + /*
88 + * We don't overflow here since the mdb_var_t itself has
89 + * room for the trailing \0.
90 + */
91 + (void) strcpy(v->v_lname, name);
83 92 v->v_ename = NULL;
84 93 }
85 94
86 95 v->v_uvalue = value;
87 96 v->v_flags = flags & ~(MDB_NV_SILENT | MDB_NV_INTERPOS);
88 97 v->v_disc = disc;
89 98 v->v_next = next;
90 99
91 100 return (v);
92 101 }
93 102
94 103 static void
95 104 nv_var_free(mdb_var_t *v, uint_t um_flags)
96 105 {
97 106 if (um_flags & UM_GC)
98 107 return;
99 108
100 109 if (v->v_flags & MDB_NV_OVERLOAD) {
101 110 mdb_var_t *w, *nw;
102 111
103 112 for (w = v->v_ndef; w != NULL; w = nw) {
104 113 nw = w->v_ndef;
105 114 mdb_free(w, NV_SIZE(w));
106 115 }
107 116 }
108 117
109 118 mdb_free(v, NV_SIZE(v));
110 119 }
111 120
112 121 /*
113 122 * Can return NULL only if the nv's memory allocation flags include UM_NOSLEEP
114 123 */
115 124 mdb_nv_t *
116 125 mdb_nv_create(mdb_nv_t *nv, uint_t um_flags)
117 126 {
118 127 nv->nv_hash = mdb_zalloc(sizeof (mdb_var_t *) * NV_HASHSZ, um_flags);
119 128
120 129 if (nv->nv_hash == NULL)
121 130 return (NULL);
122 131
123 132 nv->nv_hashsz = NV_HASHSZ;
124 133 nv->nv_nelems = 0;
125 134 nv->nv_iter_elt = NULL;
126 135 nv->nv_iter_bucket = 0;
127 136 nv->nv_um_flags = um_flags;
128 137
129 138 return (nv);
130 139 }
131 140
132 141 void
133 142 mdb_nv_destroy(mdb_nv_t *nv)
134 143 {
135 144 mdb_var_t *v, *w;
136 145 size_t i;
137 146
138 147 if (nv->nv_um_flags & UM_GC)
139 148 return;
140 149
141 150 for (i = 0; i < nv->nv_hashsz; i++) {
142 151 for (v = nv->nv_hash[i]; v != NULL; v = w) {
143 152 w = v->v_next;
144 153 nv_var_free(v, nv->nv_um_flags);
145 154 }
146 155 }
147 156
148 157 mdb_free(nv->nv_hash, sizeof (mdb_var_t *) * NV_HASHSZ);
149 158 }
150 159
151 160 mdb_var_t *
152 161 mdb_nv_lookup(mdb_nv_t *nv, const char *name)
153 162 {
154 163 size_t i = nv_hashstring(name) % nv->nv_hashsz;
155 164 mdb_var_t *v;
156 165
157 166 for (v = nv->nv_hash[i]; v != NULL; v = v->v_next) {
158 167 if (strcmp(NV_NAME(v), name) == 0)
159 168 return (v);
160 169 }
161 170
162 171 return (NULL);
163 172 }
164 173
165 174 /*
166 175 * Interpose W in place of V. We replace V with W in nv_hash, and then
167 176 * set W's v_ndef overload chain to point at V.
168 177 */
169 178 static mdb_var_t *
170 179 nv_var_interpos(mdb_nv_t *nv, size_t i, mdb_var_t *v, mdb_var_t *w)
171 180 {
172 181 mdb_var_t **pvp = &nv->nv_hash[i];
173 182
174 183 while (*pvp != v) {
175 184 mdb_var_t *vp = *pvp;
176 185 ASSERT(vp != NULL);
177 186 pvp = &vp->v_next;
178 187 }
179 188
180 189 *pvp = w;
181 190 w->v_next = v->v_next;
182 191 w->v_ndef = v;
183 192 v->v_next = NULL;
184 193
185 194 return (w);
186 195 }
187 196
188 197 /*
189 198 * Add W to the end of V's overload chain. We simply follow v_ndef to the
190 199 * end, and then append W. We don't expect these chains to grow very long.
191 200 */
192 201 static mdb_var_t *
193 202 nv_var_overload(mdb_var_t *v, mdb_var_t *w)
194 203 {
195 204 while (v->v_ndef != NULL)
196 205 v = v->v_ndef;
197 206
198 207 v->v_ndef = w;
199 208 return (w);
200 209 }
201 210
202 211 /*
203 212 * Can return NULL only if the nv's memory allocation flags include UM_NOSLEEP
204 213 */
205 214 mdb_var_t *
206 215 mdb_nv_insert(mdb_nv_t *nv, const char *name, const mdb_nv_disc_t *disc,
207 216 uintmax_t value, uint_t flags)
208 217 {
209 218 size_t i = nv_hashstring(name) % nv->nv_hashsz;
210 219 mdb_var_t *v;
211 220
212 221 ASSERT(!(flags & MDB_NV_EXTNAME) || !(flags & MDB_NV_OVERLOAD));
213 222 ASSERT(!(flags & MDB_NV_RDONLY) || !(flags & MDB_NV_OVERLOAD));
214 223
215 224 /*
216 225 * If the specified name is already hashed,
217 226 * and MDB_NV_OVERLOAD is set: insert new var into overload chain
218 227 * and MDB_NV_RDONLY is set: leave var unchanged, issue warning
219 228 * otherwise: update var with new value
220 229 */
221 230 for (v = nv->nv_hash[i]; v != NULL; v = v->v_next) {
222 231 if (strcmp(NV_NAME(v), name) == 0) {
223 232 if (v->v_flags & MDB_NV_OVERLOAD) {
224 233 mdb_var_t *w = nv_var_alloc(NV_NAME(v), disc,
225 234 value, flags, nv->nv_um_flags, NULL);
226 235
227 236 if (w == NULL) {
228 237 ASSERT(nv->nv_um_flags & UM_NOSLEEP);
229 238 return (NULL);
230 239 }
231 240
232 241 if (flags & MDB_NV_INTERPOS)
233 242 v = nv_var_interpos(nv, i, v, w);
234 243 else
235 244 v = nv_var_overload(v, w);
236 245
237 246 } else if (v->v_flags & MDB_NV_RDONLY) {
238 247 if (!(flags & MDB_NV_SILENT)) {
239 248 warn("cannot modify read-only "
240 249 "variable '%s'\n", NV_NAME(v));
241 250 }
242 251 } else
243 252 v->v_uvalue = value;
244 253
245 254 ASSERT(v != NULL);
246 255 return (v);
247 256 }
248 257 }
249 258
250 259 /*
251 260 * If the specified name was not found, initialize a new element
252 261 * and add it to the hash table at the beginning of this chain:
253 262 */
254 263 v = nv_var_alloc(name, disc, value, flags, nv->nv_um_flags,
255 264 nv->nv_hash[i]);
256 265
257 266 if (v == NULL) {
258 267 ASSERT(nv->nv_um_flags & UM_NOSLEEP);
259 268 return (NULL);
260 269 }
261 270
262 271 nv->nv_hash[i] = v;
263 272 nv->nv_nelems++;
264 273
265 274 return (v);
266 275 }
267 276
268 277 static void
269 278 nv_var_defn_remove(mdb_var_t *v, mdb_var_t *corpse, uint_t um_flags)
270 279 {
271 280 mdb_var_t *w = v;
272 281
273 282 while (v->v_ndef != NULL && v->v_ndef != corpse)
274 283 v = v->v_ndef;
275 284
276 285 if (v == NULL) {
277 286 fail("var %p ('%s') not found on defn chain of %p\n",
278 287 (void *)corpse, NV_NAME(corpse), (void *)w);
279 288 }
280 289
281 290 v->v_ndef = corpse->v_ndef;
282 291 corpse->v_ndef = NULL;
283 292 nv_var_free(corpse, um_flags);
284 293 }
285 294
286 295 void
287 296 mdb_nv_remove(mdb_nv_t *nv, mdb_var_t *corpse)
288 297 {
289 298 const char *cname = NV_NAME(corpse);
290 299 size_t i = nv_hashstring(cname) % nv->nv_hashsz;
291 300 mdb_var_t *v = nv->nv_hash[i];
292 301 mdb_var_t **pvp;
293 302
294 303 if (corpse->v_flags & MDB_NV_PERSIST) {
295 304 warn("cannot remove persistent variable '%s'\n", cname);
296 305 return;
297 306 }
298 307
299 308 if (v != corpse) {
300 309 do {
301 310 if (strcmp(NV_NAME(v), cname) == 0) {
302 311 if (corpse->v_flags & MDB_NV_OVERLOAD) {
303 312 nv_var_defn_remove(v, corpse,
304 313 nv->nv_um_flags);
305 314 return; /* No v_next changes needed */
306 315 } else
307 316 goto notfound;
308 317 }
309 318
310 319 if (v->v_next == corpse)
311 320 break; /* Corpse is next on the chain */
312 321
313 322 } while ((v = v->v_next) != NULL);
314 323
315 324 if (v == NULL)
316 325 goto notfound;
317 326
318 327 pvp = &v->v_next;
319 328 } else
320 329 pvp = &nv->nv_hash[i];
321 330
322 331 if ((corpse->v_flags & MDB_NV_OVERLOAD) && corpse->v_ndef != NULL) {
323 332 corpse->v_ndef->v_next = corpse->v_next;
324 333 *pvp = corpse->v_ndef;
325 334 corpse->v_ndef = NULL;
326 335 } else {
327 336 *pvp = corpse->v_next;
328 337 nv->nv_nelems--;
329 338 }
330 339
331 340 nv_var_free(corpse, nv->nv_um_flags);
332 341 return;
333 342
334 343 notfound:
335 344 fail("var %p ('%s') not found on hash chain: nv=%p [%lu]\n",
336 345 (void *)corpse, cname, (void *)nv, (ulong_t)i);
337 346 }
338 347
339 348 void
340 349 mdb_nv_rewind(mdb_nv_t *nv)
341 350 {
342 351 size_t i;
343 352
344 353 for (i = 0; i < nv->nv_hashsz; i++) {
345 354 if (nv->nv_hash[i] != NULL)
346 355 break;
347 356 }
348 357
349 358 nv->nv_iter_elt = i < nv->nv_hashsz ? nv->nv_hash[i] : NULL;
350 359 nv->nv_iter_bucket = i;
351 360 }
352 361
353 362 mdb_var_t *
354 363 mdb_nv_advance(mdb_nv_t *nv)
355 364 {
356 365 mdb_var_t *v = nv->nv_iter_elt;
357 366 size_t i;
358 367
359 368 if (v == NULL)
360 369 return (NULL);
361 370
362 371 if (v->v_next != NULL) {
363 372 nv->nv_iter_elt = v->v_next;
364 373 return (v);
365 374 }
366 375
367 376 for (i = nv->nv_iter_bucket + 1; i < nv->nv_hashsz; i++) {
368 377 if (nv->nv_hash[i] != NULL)
369 378 break;
370 379 }
371 380
372 381 nv->nv_iter_elt = i < nv->nv_hashsz ? nv->nv_hash[i] : NULL;
373 382 nv->nv_iter_bucket = i;
374 383
375 384 return (v);
376 385 }
377 386
378 387 mdb_var_t *
379 388 mdb_nv_peek(mdb_nv_t *nv)
380 389 {
381 390 return (nv->nv_iter_elt);
382 391 }
383 392
384 393 size_t
385 394 mdb_nv_size(mdb_nv_t *nv)
386 395 {
387 396 return (nv->nv_nelems);
388 397 }
389 398
390 399 static int
391 400 nv_compare(const mdb_var_t **lp, const mdb_var_t **rp)
392 401 {
393 402 return (strcmp(mdb_nv_get_name(*lp), mdb_nv_get_name(*rp)));
394 403 }
395 404
396 405 void
397 406 mdb_nv_sort_iter(mdb_nv_t *nv, int (*func)(mdb_var_t *, void *),
398 407 void *private, uint_t um_flags)
399 408 {
400 409 mdb_var_t **vps =
401 410 mdb_alloc(nv->nv_nelems * sizeof (mdb_var_t *), um_flags);
402 411
403 412 if (nv->nv_nelems != 0 && vps != NULL) {
404 413 mdb_var_t *v, **vpp = vps;
405 414 size_t i;
406 415
407 416 for (mdb_nv_rewind(nv); (v = mdb_nv_advance(nv)) != NULL; )
408 417 *vpp++ = v;
409 418
410 419 qsort(vps, nv->nv_nelems, sizeof (mdb_var_t *),
411 420 (int (*)(const void *, const void *))nv_compare);
412 421
413 422 for (vpp = vps, i = 0; i < nv->nv_nelems; i++) {
414 423 if (func(*vpp++, private) == -1)
415 424 break;
416 425 }
417 426
418 427 if (!(um_flags & UM_GC))
419 428 mdb_free(vps, nv->nv_nelems * sizeof (mdb_var_t *));
420 429 }
421 430 }
422 431
423 432 void
424 433 mdb_nv_defn_iter(mdb_var_t *v, int (*func)(mdb_var_t *, void *), void *private)
425 434 {
426 435 if (func(v, private) == -1 || !(v->v_flags & MDB_NV_OVERLOAD))
427 436 return;
428 437
429 438 for (v = v->v_ndef; v != NULL; v = v->v_ndef) {
430 439 if (func(v, private) == -1)
431 440 break;
432 441 }
433 442 }
434 443
435 444 uintmax_t
436 445 mdb_nv_get_value(const mdb_var_t *v)
437 446 {
438 447 if (v->v_disc)
439 448 return (v->v_disc->disc_get(v));
440 449
441 450 return (v->v_uvalue);
442 451 }
443 452
444 453 void
445 454 mdb_nv_set_value(mdb_var_t *v, uintmax_t l)
446 455 {
447 456 if (v->v_flags & MDB_NV_RDONLY) {
448 457 warn("cannot modify read-only variable '%s'\n", NV_NAME(v));
449 458 return;
450 459 }
451 460
452 461 if (v->v_disc)
453 462 v->v_disc->disc_set(v, l);
454 463 else
455 464 v->v_uvalue = l;
456 465 }
457 466
458 467 void *
459 468 mdb_nv_get_cookie(const mdb_var_t *v)
460 469 {
461 470 if (v->v_disc)
462 471 return ((void *)(uintptr_t)v->v_disc->disc_get(v));
463 472
464 473 return (MDB_NV_COOKIE(v));
465 474 }
466 475
467 476 void
468 477 mdb_nv_set_cookie(mdb_var_t *v, void *cookie)
469 478 {
470 479 mdb_nv_set_value(v, (uintmax_t)(uintptr_t)cookie);
471 480 }
472 481
473 482 const char *
474 483 mdb_nv_get_name(const mdb_var_t *v)
475 484 {
476 485 return (NV_NAME(v));
477 486 }
478 487
479 488 mdb_var_t *
480 489 mdb_nv_get_ndef(const mdb_var_t *v)
481 490 {
482 491 if (v->v_flags & MDB_NV_OVERLOAD)
483 492 return (v->v_ndef);
484 493
485 494 return (NULL);
486 495 }
↓ open down ↓ |
394 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX