diff options
author | Christoph Lameter <clameter@sgi.com> | 2007-05-09 05:32:37 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-09 15:30:44 -0400 |
commit | a87615b8f9e2349f6d3770af3d72fd6a41ab4239 (patch) | |
tree | 5e2608dad1ad746b0552ef52afec9298320045ac | |
parent | be7b3fbcef34452127bed93632b8e788f685d70e (diff) |
SLUB: slabinfo upgrade
-e Show empty slabs
-d Modification of slab debug options at runtime
-o Operations. Display of ctor / dtor etc.
-r Report: Display all available information about a slabcache.
Cleanup tracking display and make it work right.
Signed-off-by: Christoph Lameter <clameter@sgi.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/vm/slabinfo.c | 426 |
1 files changed, 352 insertions, 74 deletions
diff --git a/Documentation/vm/slabinfo.c b/Documentation/vm/slabinfo.c index 41710ccf3a29..686a8e04a4f3 100644 --- a/Documentation/vm/slabinfo.c +++ b/Documentation/vm/slabinfo.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <stdarg.h> | 16 | #include <stdarg.h> |
17 | #include <getopt.h> | 17 | #include <getopt.h> |
18 | #include <regex.h> | 18 | #include <regex.h> |
19 | #include <errno.h> | ||
19 | 20 | ||
20 | #define MAX_SLABS 500 | 21 | #define MAX_SLABS 500 |
21 | #define MAX_ALIASES 500 | 22 | #define MAX_ALIASES 500 |
@@ -41,12 +42,15 @@ struct aliasinfo { | |||
41 | } aliasinfo[MAX_ALIASES]; | 42 | } aliasinfo[MAX_ALIASES]; |
42 | 43 | ||
43 | int slabs = 0; | 44 | int slabs = 0; |
45 | int actual_slabs = 0; | ||
44 | int aliases = 0; | 46 | int aliases = 0; |
45 | int alias_targets = 0; | 47 | int alias_targets = 0; |
46 | int highest_node = 0; | 48 | int highest_node = 0; |
47 | 49 | ||
48 | char buffer[4096]; | 50 | char buffer[4096]; |
49 | 51 | ||
52 | int show_empty = 0; | ||
53 | int show_report = 0; | ||
50 | int show_alias = 0; | 54 | int show_alias = 0; |
51 | int show_slab = 0; | 55 | int show_slab = 0; |
52 | int skip_zero = 1; | 56 | int skip_zero = 1; |
@@ -59,6 +63,15 @@ int show_inverted = 0; | |||
59 | int show_single_ref = 0; | 63 | int show_single_ref = 0; |
60 | int show_totals = 0; | 64 | int show_totals = 0; |
61 | int sort_size = 0; | 65 | int sort_size = 0; |
66 | int set_debug = 0; | ||
67 | int show_ops = 0; | ||
68 | |||
69 | /* Debug options */ | ||
70 | int sanity = 0; | ||
71 | int redzone = 0; | ||
72 | int poison = 0; | ||
73 | int tracking = 0; | ||
74 | int tracing = 0; | ||
62 | 75 | ||
63 | int page_size; | 76 | int page_size; |
64 | 77 | ||
@@ -76,20 +89,33 @@ void fatal(const char *x, ...) | |||
76 | 89 | ||
77 | void usage(void) | 90 | void usage(void) |
78 | { | 91 | { |
79 | printf("slabinfo [-ahnpvtsz] [slab-regexp]\n" | 92 | printf("slabinfo 5/7/2007. (c) 2007 sgi. clameter@sgi.com\n\n" |
93 | "slabinfo [-ahnpvtsz] [-d debugopts] [slab-regexp]\n" | ||
80 | "-a|--aliases Show aliases\n" | 94 | "-a|--aliases Show aliases\n" |
95 | "-d<options>|--debug=<options> Set/Clear Debug options\n" | ||
96 | "-e|--empty Show empty slabs\n" | ||
97 | "-f|--first-alias Show first alias\n" | ||
81 | "-h|--help Show usage information\n" | 98 | "-h|--help Show usage information\n" |
99 | "-i|--inverted Inverted list\n" | ||
100 | "-l|--slabs Show slabs\n" | ||
82 | "-n|--numa Show NUMA information\n" | 101 | "-n|--numa Show NUMA information\n" |
102 | "-o|--ops Show kmem_cache_ops\n" | ||
83 | "-s|--shrink Shrink slabs\n" | 103 | "-s|--shrink Shrink slabs\n" |
84 | "-v|--validate Validate slabs\n" | 104 | "-r|--report Detailed report on single slabs\n" |
105 | "-S|--Size Sort by size\n" | ||
85 | "-t|--tracking Show alloc/free information\n" | 106 | "-t|--tracking Show alloc/free information\n" |
86 | "-T|--Totals Show summary information\n" | 107 | "-T|--Totals Show summary information\n" |
87 | "-l|--slabs Show slabs\n" | 108 | "-v|--validate Validate slabs\n" |
88 | "-S|--Size Sort by size\n" | ||
89 | "-z|--zero Include empty slabs\n" | 109 | "-z|--zero Include empty slabs\n" |
90 | "-f|--first-alias Show first alias\n" | ||
91 | "-i|--inverted Inverted list\n" | ||
92 | "-1|--1ref Single reference\n" | 110 | "-1|--1ref Single reference\n" |
111 | "\nValid debug options (FZPUT may be combined)\n" | ||
112 | "a / A Switch on all debug options (=FZUP)\n" | ||
113 | "- Switch off all debug options\n" | ||
114 | "f / F Sanity Checks (SLAB_DEBUG_FREE)\n" | ||
115 | "z / Z Redzoning\n" | ||
116 | "p / P Poisoning\n" | ||
117 | "u / U Tracking\n" | ||
118 | "t / T Tracing\n" | ||
93 | ); | 119 | ); |
94 | } | 120 | } |
95 | 121 | ||
@@ -143,11 +169,10 @@ unsigned long get_obj_and_str(char *name, char **x) | |||
143 | void set_obj(struct slabinfo *s, char *name, int n) | 169 | void set_obj(struct slabinfo *s, char *name, int n) |
144 | { | 170 | { |
145 | char x[100]; | 171 | char x[100]; |
172 | FILE *f; | ||
146 | 173 | ||
147 | sprintf(x, "%s/%s", s->name, name); | 174 | sprintf(x, "%s/%s", s->name, name); |
148 | 175 | f = fopen(x, "w"); | |
149 | FILE *f = fopen(x, "w"); | ||
150 | |||
151 | if (!f) | 176 | if (!f) |
152 | fatal("Cannot write to %s\n", x); | 177 | fatal("Cannot write to %s\n", x); |
153 | 178 | ||
@@ -155,6 +180,26 @@ void set_obj(struct slabinfo *s, char *name, int n) | |||
155 | fclose(f); | 180 | fclose(f); |
156 | } | 181 | } |
157 | 182 | ||
183 | unsigned long read_slab_obj(struct slabinfo *s, char *name) | ||
184 | { | ||
185 | char x[100]; | ||
186 | FILE *f; | ||
187 | int l; | ||
188 | |||
189 | sprintf(x, "%s/%s", s->name, name); | ||
190 | f = fopen(x, "r"); | ||
191 | if (!f) { | ||
192 | buffer[0] = 0; | ||
193 | l = 0; | ||
194 | } else { | ||
195 | l = fread(buffer, 1, sizeof(buffer), f); | ||
196 | buffer[l] = 0; | ||
197 | fclose(f); | ||
198 | } | ||
199 | return l; | ||
200 | } | ||
201 | |||
202 | |||
158 | /* | 203 | /* |
159 | * Put a size string together | 204 | * Put a size string together |
160 | */ | 205 | */ |
@@ -226,7 +271,7 @@ int line = 0; | |||
226 | 271 | ||
227 | void first_line(void) | 272 | void first_line(void) |
228 | { | 273 | { |
229 | printf("Name Objects Objsize Space " | 274 | printf("Name Objects Objsize Space " |
230 | "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); | 275 | "Slabs/Part/Cpu O/S O %%Fr %%Ef Flg\n"); |
231 | } | 276 | } |
232 | 277 | ||
@@ -246,10 +291,7 @@ struct aliasinfo *find_one_alias(struct slabinfo *find) | |||
246 | return best; | 291 | return best; |
247 | } | 292 | } |
248 | } | 293 | } |
249 | if (best) | 294 | return best; |
250 | return best; | ||
251 | fatal("Cannot find alias for %s\n", find->name); | ||
252 | return NULL; | ||
253 | } | 295 | } |
254 | 296 | ||
255 | unsigned long slab_size(struct slabinfo *s) | 297 | unsigned long slab_size(struct slabinfo *s) |
@@ -257,6 +299,126 @@ unsigned long slab_size(struct slabinfo *s) | |||
257 | return s->slabs * (page_size << s->order); | 299 | return s->slabs * (page_size << s->order); |
258 | } | 300 | } |
259 | 301 | ||
302 | void slab_numa(struct slabinfo *s, int mode) | ||
303 | { | ||
304 | int node; | ||
305 | |||
306 | if (strcmp(s->name, "*") == 0) | ||
307 | return; | ||
308 | |||
309 | if (!highest_node) { | ||
310 | printf("\n%s: No NUMA information available.\n", s->name); | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | if (skip_zero && !s->slabs) | ||
315 | return; | ||
316 | |||
317 | if (!line) { | ||
318 | printf("\n%-21s:", mode ? "NUMA nodes" : "Slab"); | ||
319 | for(node = 0; node <= highest_node; node++) | ||
320 | printf(" %4d", node); | ||
321 | printf("\n----------------------"); | ||
322 | for(node = 0; node <= highest_node; node++) | ||
323 | printf("-----"); | ||
324 | printf("\n"); | ||
325 | } | ||
326 | printf("%-21s ", mode ? "All slabs" : s->name); | ||
327 | for(node = 0; node <= highest_node; node++) { | ||
328 | char b[20]; | ||
329 | |||
330 | store_size(b, s->numa[node]); | ||
331 | printf(" %4s", b); | ||
332 | } | ||
333 | printf("\n"); | ||
334 | if (mode) { | ||
335 | printf("%-21s ", "Partial slabs"); | ||
336 | for(node = 0; node <= highest_node; node++) { | ||
337 | char b[20]; | ||
338 | |||
339 | store_size(b, s->numa_partial[node]); | ||
340 | printf(" %4s", b); | ||
341 | } | ||
342 | printf("\n"); | ||
343 | } | ||
344 | line++; | ||
345 | } | ||
346 | |||
347 | void show_tracking(struct slabinfo *s) | ||
348 | { | ||
349 | printf("\n%s: Kernel object allocation\n", s->name); | ||
350 | printf("-----------------------------------------------------------------------\n"); | ||
351 | if (read_slab_obj(s, "alloc_calls")) | ||
352 | printf(buffer); | ||
353 | else | ||
354 | printf("No Data\n"); | ||
355 | |||
356 | printf("\n%s: Kernel object freeing\n", s->name); | ||
357 | printf("------------------------------------------------------------------------\n"); | ||
358 | if (read_slab_obj(s, "free_calls")) | ||
359 | printf(buffer); | ||
360 | else | ||
361 | printf("No Data\n"); | ||
362 | |||
363 | } | ||
364 | |||
365 | void ops(struct slabinfo *s) | ||
366 | { | ||
367 | if (strcmp(s->name, "*") == 0) | ||
368 | return; | ||
369 | |||
370 | if (read_slab_obj(s, "ops")) { | ||
371 | printf("\n%s: kmem_cache operations\n", s->name); | ||
372 | printf("--------------------------------------------\n"); | ||
373 | printf(buffer); | ||
374 | } else | ||
375 | printf("\n%s has no kmem_cache operations\n", s->name); | ||
376 | } | ||
377 | |||
378 | const char *onoff(int x) | ||
379 | { | ||
380 | if (x) | ||
381 | return "On "; | ||
382 | return "Off"; | ||
383 | } | ||
384 | |||
385 | void report(struct slabinfo *s) | ||
386 | { | ||
387 | if (strcmp(s->name, "*") == 0) | ||
388 | return; | ||
389 | printf("\nSlabcache: %-20s Aliases: %2d Order : %2d\n", s->name, s->aliases, s->order); | ||
390 | if (s->hwcache_align) | ||
391 | printf("** Hardware cacheline aligned\n"); | ||
392 | if (s->cache_dma) | ||
393 | printf("** Memory is allocated in a special DMA zone\n"); | ||
394 | if (s->destroy_by_rcu) | ||
395 | printf("** Slabs are destroyed via RCU\n"); | ||
396 | if (s->reclaim_account) | ||
397 | printf("** Reclaim accounting active\n"); | ||
398 | |||
399 | printf("\nSizes (bytes) Slabs Debug Memory\n"); | ||
400 | printf("------------------------------------------------------------------------\n"); | ||
401 | printf("Object : %7d Total : %7ld Sanity Checks : %s Total: %7ld\n", | ||
402 | s->object_size, s->slabs, onoff(s->sanity_checks), | ||
403 | s->slabs * (page_size << s->order)); | ||
404 | printf("SlabObj: %7d Full : %7ld Redzoning : %s Used : %7ld\n", | ||
405 | s->slab_size, s->slabs - s->partial - s->cpu_slabs, | ||
406 | onoff(s->red_zone), s->objects * s->object_size); | ||
407 | printf("SlabSiz: %7d Partial: %7ld Poisoning : %s Loss : %7ld\n", | ||
408 | page_size << s->order, s->partial, onoff(s->poison), | ||
409 | s->slabs * (page_size << s->order) - s->objects * s->object_size); | ||
410 | printf("Loss : %7d CpuSlab: %7d Tracking : %s Lalig: %7ld\n", | ||
411 | s->slab_size - s->object_size, s->cpu_slabs, onoff(s->store_user), | ||
412 | (s->slab_size - s->object_size) * s->objects); | ||
413 | printf("Align : %7d Objects: %7d Tracing : %s Lpadd: %7ld\n", | ||
414 | s->align, s->objs_per_slab, onoff(s->trace), | ||
415 | ((page_size << s->order) - s->objs_per_slab * s->slab_size) * | ||
416 | s->slabs); | ||
417 | |||
418 | ops(s); | ||
419 | show_tracking(s); | ||
420 | slab_numa(s, 1); | ||
421 | } | ||
260 | 422 | ||
261 | void slabcache(struct slabinfo *s) | 423 | void slabcache(struct slabinfo *s) |
262 | { | 424 | { |
@@ -265,7 +427,18 @@ void slabcache(struct slabinfo *s) | |||
265 | char flags[20]; | 427 | char flags[20]; |
266 | char *p = flags; | 428 | char *p = flags; |
267 | 429 | ||
268 | if (skip_zero && !s->slabs) | 430 | if (strcmp(s->name, "*") == 0) |
431 | return; | ||
432 | |||
433 | if (actual_slabs == 1) { | ||
434 | report(s); | ||
435 | return; | ||
436 | } | ||
437 | |||
438 | if (skip_zero && !show_empty && !s->slabs) | ||
439 | return; | ||
440 | |||
441 | if (show_empty && s->slabs) | ||
269 | return; | 442 | return; |
270 | 443 | ||
271 | store_size(size_str, slab_size(s)); | 444 | store_size(size_str, slab_size(s)); |
@@ -303,48 +476,128 @@ void slabcache(struct slabinfo *s) | |||
303 | flags); | 476 | flags); |
304 | } | 477 | } |
305 | 478 | ||
306 | void slab_numa(struct slabinfo *s) | 479 | /* |
480 | * Analyze debug options. Return false if something is amiss. | ||
481 | */ | ||
482 | int debug_opt_scan(char *opt) | ||
307 | { | 483 | { |
308 | int node; | 484 | if (!opt || !opt[0] || strcmp(opt, "-") == 0) |
485 | return 1; | ||
486 | |||
487 | if (strcasecmp(opt, "a") == 0) { | ||
488 | sanity = 1; | ||
489 | poison = 1; | ||
490 | redzone = 1; | ||
491 | tracking = 1; | ||
492 | return 1; | ||
493 | } | ||
309 | 494 | ||
310 | if (!highest_node) | 495 | for ( ; *opt; opt++) |
311 | fatal("No NUMA information available.\n"); | 496 | switch (*opt) { |
497 | case 'F' : case 'f': | ||
498 | if (sanity) | ||
499 | return 0; | ||
500 | sanity = 1; | ||
501 | break; | ||
502 | case 'P' : case 'p': | ||
503 | if (poison) | ||
504 | return 0; | ||
505 | poison = 1; | ||
506 | break; | ||
312 | 507 | ||
313 | if (skip_zero && !s->slabs) | 508 | case 'Z' : case 'z': |
314 | return; | 509 | if (redzone) |
510 | return 0; | ||
511 | redzone = 1; | ||
512 | break; | ||
315 | 513 | ||
316 | if (!line) { | 514 | case 'U' : case 'u': |
317 | printf("\nSlab Node "); | 515 | if (tracking) |
318 | for(node = 0; node <= highest_node; node++) | 516 | return 0; |
319 | printf(" %4d", node); | 517 | tracking = 1; |
320 | printf("\n----------------------"); | 518 | break; |
321 | for(node = 0; node <= highest_node; node++) | ||
322 | printf("-----"); | ||
323 | printf("\n"); | ||
324 | } | ||
325 | printf("%-21s ", s->name); | ||
326 | for(node = 0; node <= highest_node; node++) { | ||
327 | char b[20]; | ||
328 | 519 | ||
329 | store_size(b, s->numa[node]); | 520 | case 'T' : case 't': |
330 | printf(" %4s", b); | 521 | if (tracing) |
331 | } | 522 | return 0; |
332 | printf("\n"); | 523 | tracing = 1; |
333 | line++; | 524 | break; |
525 | default: | ||
526 | return 0; | ||
527 | } | ||
528 | return 1; | ||
334 | } | 529 | } |
335 | 530 | ||
336 | void show_tracking(struct slabinfo *s) | 531 | int slab_empty(struct slabinfo *s) |
337 | { | 532 | { |
338 | printf("\n%s: Calls to allocate a slab object\n", s->name); | 533 | if (s->objects > 0) |
339 | printf("---------------------------------------------------\n"); | 534 | return 0; |
340 | if (read_obj("alloc_calls")) | ||
341 | printf(buffer); | ||
342 | 535 | ||
343 | printf("%s: Calls to free a slab object\n", s->name); | 536 | /* |
344 | printf("-----------------------------------------------\n"); | 537 | * We may still have slabs even if there are no objects. Shrinking will |
345 | if (read_obj("free_calls")) | 538 | * remove them. |
346 | printf(buffer); | 539 | */ |
540 | if (s->slabs != 0) | ||
541 | set_obj(s, "shrink", 1); | ||
347 | 542 | ||
543 | return 1; | ||
544 | } | ||
545 | |||
546 | void slab_debug(struct slabinfo *s) | ||
547 | { | ||
548 | if (sanity && !s->sanity_checks) { | ||
549 | set_obj(s, "sanity", 1); | ||
550 | } | ||
551 | if (!sanity && s->sanity_checks) { | ||
552 | if (slab_empty(s)) | ||
553 | set_obj(s, "sanity", 0); | ||
554 | else | ||
555 | fprintf(stderr, "%s not empty cannot disable sanity checks\n", s->name); | ||
556 | } | ||
557 | if (redzone && !s->red_zone) { | ||
558 | if (slab_empty(s)) | ||
559 | set_obj(s, "red_zone", 1); | ||
560 | else | ||
561 | fprintf(stderr, "%s not empty cannot enable redzoning\n", s->name); | ||
562 | } | ||
563 | if (!redzone && s->red_zone) { | ||
564 | if (slab_empty(s)) | ||
565 | set_obj(s, "red_zone", 0); | ||
566 | else | ||
567 | fprintf(stderr, "%s not empty cannot disable redzoning\n", s->name); | ||
568 | } | ||
569 | if (poison && !s->poison) { | ||
570 | if (slab_empty(s)) | ||
571 | set_obj(s, "poison", 1); | ||
572 | else | ||
573 | fprintf(stderr, "%s not empty cannot enable poisoning\n", s->name); | ||
574 | } | ||
575 | if (!poison && s->poison) { | ||
576 | if (slab_empty(s)) | ||
577 | set_obj(s, "poison", 0); | ||
578 | else | ||
579 | fprintf(stderr, "%s not empty cannot disable poisoning\n", s->name); | ||
580 | } | ||
581 | if (tracking && !s->store_user) { | ||
582 | if (slab_empty(s)) | ||
583 | set_obj(s, "store_user", 1); | ||
584 | else | ||
585 | fprintf(stderr, "%s not empty cannot enable tracking\n", s->name); | ||
586 | } | ||
587 | if (!tracking && s->store_user) { | ||
588 | if (slab_empty(s)) | ||
589 | set_obj(s, "store_user", 0); | ||
590 | else | ||
591 | fprintf(stderr, "%s not empty cannot disable tracking\n", s->name); | ||
592 | } | ||
593 | if (tracing && !s->trace) { | ||
594 | if (slabs == 1) | ||
595 | set_obj(s, "trace", 1); | ||
596 | else | ||
597 | fprintf(stderr, "%s can only enable trace for one slab at a time\n", s->name); | ||
598 | } | ||
599 | if (!tracing && s->trace) | ||
600 | set_obj(s, "trace", 1); | ||
348 | } | 601 | } |
349 | 602 | ||
350 | void totals(void) | 603 | void totals(void) |
@@ -673,7 +926,7 @@ void link_slabs(void) | |||
673 | 926 | ||
674 | for (a = aliasinfo; a < aliasinfo + aliases; a++) { | 927 | for (a = aliasinfo; a < aliasinfo + aliases; a++) { |
675 | 928 | ||
676 | for(s = slabinfo; s < slabinfo + slabs; s++) | 929 | for (s = slabinfo; s < slabinfo + slabs; s++) |
677 | if (strcmp(a->ref, s->name) == 0) { | 930 | if (strcmp(a->ref, s->name) == 0) { |
678 | a->slab = s; | 931 | a->slab = s; |
679 | s->refs++; | 932 | s->refs++; |
@@ -704,7 +957,7 @@ void alias(void) | |||
704 | continue; | 957 | continue; |
705 | } | 958 | } |
706 | } | 959 | } |
707 | printf("\n%-20s <- %s", a->slab->name, a->name); | 960 | printf("\n%-12s <- %s", a->slab->name, a->name); |
708 | active = a->slab->name; | 961 | active = a->slab->name; |
709 | } | 962 | } |
710 | else | 963 | else |
@@ -729,7 +982,12 @@ void rename_slabs(void) | |||
729 | 982 | ||
730 | a = find_one_alias(s); | 983 | a = find_one_alias(s); |
731 | 984 | ||
732 | s->name = a->name; | 985 | if (a) |
986 | s->name = a->name; | ||
987 | else { | ||
988 | s->name = "*"; | ||
989 | actual_slabs--; | ||
990 | } | ||
733 | } | 991 | } |
734 | } | 992 | } |
735 | 993 | ||
@@ -748,11 +1006,14 @@ void read_slab_dir(void) | |||
748 | char *t; | 1006 | char *t; |
749 | int count; | 1007 | int count; |
750 | 1008 | ||
1009 | if (chdir("/sys/slab")) | ||
1010 | fatal("SYSFS support for SLUB not active\n"); | ||
1011 | |||
751 | dir = opendir("."); | 1012 | dir = opendir("."); |
752 | while ((de = readdir(dir))) { | 1013 | while ((de = readdir(dir))) { |
753 | if (de->d_name[0] == '.' || | 1014 | if (de->d_name[0] == '.' || |
754 | slab_mismatch(de->d_name)) | 1015 | (de->d_name[0] != ':' && slab_mismatch(de->d_name))) |
755 | continue; | 1016 | continue; |
756 | switch (de->d_type) { | 1017 | switch (de->d_type) { |
757 | case DT_LNK: | 1018 | case DT_LNK: |
758 | alias->name = strdup(de->d_name); | 1019 | alias->name = strdup(de->d_name); |
@@ -807,6 +1068,7 @@ void read_slab_dir(void) | |||
807 | } | 1068 | } |
808 | closedir(dir); | 1069 | closedir(dir); |
809 | slabs = slab - slabinfo; | 1070 | slabs = slab - slabinfo; |
1071 | actual_slabs = slabs; | ||
810 | aliases = alias - aliasinfo; | 1072 | aliases = alias - aliasinfo; |
811 | if (slabs > MAX_SLABS) | 1073 | if (slabs > MAX_SLABS) |
812 | fatal("Too many slabs\n"); | 1074 | fatal("Too many slabs\n"); |
@@ -825,34 +1087,37 @@ void output_slabs(void) | |||
825 | 1087 | ||
826 | 1088 | ||
827 | if (show_numa) | 1089 | if (show_numa) |
828 | slab_numa(slab); | 1090 | slab_numa(slab, 0); |
829 | else | 1091 | else if (show_track) |
830 | if (show_track) | ||
831 | show_tracking(slab); | 1092 | show_tracking(slab); |
832 | else | 1093 | else if (validate) |
833 | if (validate) | ||
834 | slab_validate(slab); | 1094 | slab_validate(slab); |
835 | else | 1095 | else if (shrink) |
836 | if (shrink) | ||
837 | slab_shrink(slab); | 1096 | slab_shrink(slab); |
838 | else { | 1097 | else if (set_debug) |
839 | if (show_slab) | 1098 | slab_debug(slab); |
840 | slabcache(slab); | 1099 | else if (show_ops) |
841 | } | 1100 | ops(slab); |
1101 | else if (show_slab) | ||
1102 | slabcache(slab); | ||
842 | } | 1103 | } |
843 | } | 1104 | } |
844 | 1105 | ||
845 | struct option opts[] = { | 1106 | struct option opts[] = { |
846 | { "aliases", 0, NULL, 'a' }, | 1107 | { "aliases", 0, NULL, 'a' }, |
847 | { "slabs", 0, NULL, 'l' }, | 1108 | { "debug", 2, NULL, 'd' }, |
848 | { "numa", 0, NULL, 'n' }, | 1109 | { "empty", 0, NULL, 'e' }, |
849 | { "zero", 0, NULL, 'z' }, | ||
850 | { "help", 0, NULL, 'h' }, | ||
851 | { "validate", 0, NULL, 'v' }, | ||
852 | { "first-alias", 0, NULL, 'f' }, | 1110 | { "first-alias", 0, NULL, 'f' }, |
1111 | { "help", 0, NULL, 'h' }, | ||
1112 | { "inverted", 0, NULL, 'i'}, | ||
1113 | { "numa", 0, NULL, 'n' }, | ||
1114 | { "ops", 0, NULL, 'o' }, | ||
1115 | { "report", 0, NULL, 'r' }, | ||
853 | { "shrink", 0, NULL, 's' }, | 1116 | { "shrink", 0, NULL, 's' }, |
1117 | { "slabs", 0, NULL, 'l' }, | ||
854 | { "track", 0, NULL, 't'}, | 1118 | { "track", 0, NULL, 't'}, |
855 | { "inverted", 0, NULL, 'i'}, | 1119 | { "validate", 0, NULL, 'v' }, |
1120 | { "zero", 0, NULL, 'z' }, | ||
856 | { "1ref", 0, NULL, '1'}, | 1121 | { "1ref", 0, NULL, '1'}, |
857 | { NULL, 0, NULL, 0 } | 1122 | { NULL, 0, NULL, 0 } |
858 | }; | 1123 | }; |
@@ -864,10 +1129,9 @@ int main(int argc, char *argv[]) | |||
864 | char *pattern_source; | 1129 | char *pattern_source; |
865 | 1130 | ||
866 | page_size = getpagesize(); | 1131 | page_size = getpagesize(); |
867 | if (chdir("/sys/slab")) | ||
868 | fatal("This kernel does not have SLUB support.\n"); | ||
869 | 1132 | ||
870 | while ((c = getopt_long(argc, argv, "afhil1npstvzTS", opts, NULL)) != -1) | 1133 | while ((c = getopt_long(argc, argv, "ad::efhil1noprstvzTS", |
1134 | opts, NULL)) != -1) | ||
871 | switch(c) { | 1135 | switch(c) { |
872 | case '1': | 1136 | case '1': |
873 | show_single_ref = 1; | 1137 | show_single_ref = 1; |
@@ -875,6 +1139,14 @@ int main(int argc, char *argv[]) | |||
875 | case 'a': | 1139 | case 'a': |
876 | show_alias = 1; | 1140 | show_alias = 1; |
877 | break; | 1141 | break; |
1142 | case 'd': | ||
1143 | set_debug = 1; | ||
1144 | if (!debug_opt_scan(optarg)) | ||
1145 | fatal("Invalid debug option '%s'\n", optarg); | ||
1146 | break; | ||
1147 | case 'e': | ||
1148 | show_empty = 1; | ||
1149 | break; | ||
878 | case 'f': | 1150 | case 'f': |
879 | show_first_alias = 1; | 1151 | show_first_alias = 1; |
880 | break; | 1152 | break; |
@@ -887,6 +1159,12 @@ int main(int argc, char *argv[]) | |||
887 | case 'n': | 1159 | case 'n': |
888 | show_numa = 1; | 1160 | show_numa = 1; |
889 | break; | 1161 | break; |
1162 | case 'o': | ||
1163 | show_ops = 1; | ||
1164 | break; | ||
1165 | case 'r': | ||
1166 | show_report = 1; | ||
1167 | break; | ||
890 | case 's': | 1168 | case 's': |
891 | shrink = 1; | 1169 | shrink = 1; |
892 | break; | 1170 | break; |
@@ -914,8 +1192,8 @@ int main(int argc, char *argv[]) | |||
914 | 1192 | ||
915 | } | 1193 | } |
916 | 1194 | ||
917 | if (!show_slab && !show_alias && !show_track | 1195 | if (!show_slab && !show_alias && !show_track && !show_report |
918 | && !validate && !shrink) | 1196 | && !validate && !shrink && !set_debug && !show_ops) |
919 | show_slab = 1; | 1197 | show_slab = 1; |
920 | 1198 | ||
921 | if (argc > optind) | 1199 | if (argc > optind) |