1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * kernel/lockdep_proc.c 4 * 5 * Runtime locking correctness validator 6 * 7 * Started by Ingo Molnar: 8 * 9 * Copyright (C) 2006,2007 Red Hat, Inc., Ingo Molnar <mingo@redhat.com> 10 * Copyright (C) 2007 Red Hat, Inc., Peter Zijlstra 11 * 12 * Code for /proc/lockdep and /proc/lockdep_stats: 13 * 14 */ 15 #include <linux/export.h> 16 #include <linux/proc_fs.h> 17 #include <linux/seq_file.h> 18 #include <linux/kallsyms.h> 19 #include <linux/debug_locks.h> 20 #include <linux/vmalloc.h> 21 #include <linux/sort.h> 22 #include <linux/uaccess.h> 23 #include <asm/div64.h> 24 25 #include "lockdep_internals.h" 26 27 static void *l_next(struct seq_file *m, void *v, loff_t *pos) 28 { 29 return seq_list_next(v, &all_lock_classes, pos); 30 } 31 32 static void *l_start(struct seq_file *m, loff_t *pos) 33 { 34 return seq_list_start_head(&all_lock_classes, *pos); 35 } 36 37 static void l_stop(struct seq_file *m, void *v) 38 { 39 } 40 41 static void print_name(struct seq_file *m, struct lock_class *class) 42 { 43 char str[KSYM_NAME_LEN]; 44 const char *name = class->name; 45 46 if (!name) { 47 name = __get_key_name(class->key, str); 48 seq_printf(m, "%s", name); 49 } else{ 50 seq_printf(m, "%s", name); 51 if (class->name_version > 1) 52 seq_printf(m, "#%d", class->name_version); 53 if (class->subclass) 54 seq_printf(m, "/%d", class->subclass); 55 } 56 } 57 58 static int l_show(struct seq_file *m, void *v) 59 { 60 struct lock_class *class = list_entry(v, struct lock_class, lock_entry); 61 struct lock_list *entry; 62 char usage[LOCK_USAGE_CHARS]; 63 64 if (v == &all_lock_classes) { 65 seq_printf(m, "all lock classes:\n"); 66 return 0; 67 } 68 69 seq_printf(m, "%p", class->key); 70 #ifdef CONFIG_DEBUG_LOCKDEP 71 seq_printf(m, " OPS:%8ld", class->ops); 72 #endif 73 #ifdef CONFIG_PROVE_LOCKING 74 seq_printf(m, " FD:%5ld", lockdep_count_forward_deps(class)); 75 seq_printf(m, " BD:%5ld", lockdep_count_backward_deps(class)); 76 #endif 77 78 get_usage_chars(class, usage); 79 seq_printf(m, " %s", usage); 80 81 seq_printf(m, ": "); 82 print_name(m, class); 83 seq_puts(m, "\n"); 84 85 list_for_each_entry(entry, &class->locks_after, entry) { 86 if (entry->distance == 1) { 87 seq_printf(m, " -> [%p] ", entry->class->key); 88 print_name(m, entry->class); 89 seq_puts(m, "\n"); 90 } 91 } 92 seq_puts(m, "\n"); 93 94 return 0; 95 } 96 97 static const struct seq_operations lockdep_ops = { 98 .start = l_start, 99 .next = l_next, 100 .stop = l_stop, 101 .show = l_show, 102 }; 103 104 static int lockdep_open(struct inode *inode, struct file *file) 105 { 106 return seq_open(file, &lockdep_ops); 107 } 108 109 static const struct file_operations proc_lockdep_operations = { 110 .open = lockdep_open, 111 .read = seq_read, 112 .llseek = seq_lseek, 113 .release = seq_release, 114 }; 115 116 #ifdef CONFIG_PROVE_LOCKING 117 static void *lc_start(struct seq_file *m, loff_t *pos) 118 { 119 if (*pos == 0) 120 return SEQ_START_TOKEN; 121 122 if (*pos - 1 < nr_lock_chains) 123 return lock_chains + (*pos - 1); 124 125 return NULL; 126 } 127 128 static void *lc_next(struct seq_file *m, void *v, loff_t *pos) 129 { 130 (*pos)++; 131 return lc_start(m, pos); 132 } 133 134 static void lc_stop(struct seq_file *m, void *v) 135 { 136 } 137 138 static int lc_show(struct seq_file *m, void *v) 139 { 140 struct lock_chain *chain = v; 141 struct lock_class *class; 142 int i; 143 144 if (v == SEQ_START_TOKEN) { 145 if (nr_chain_hlocks > MAX_LOCKDEP_CHAIN_HLOCKS) 146 seq_printf(m, "(buggered) "); 147 seq_printf(m, "all lock chains:\n"); 148 return 0; 149 } 150 151 seq_printf(m, "irq_context: %d\n", chain->irq_context); 152 153 for (i = 0; i < chain->depth; i++) { 154 class = lock_chain_get_class(chain, i); 155 if (!class->key) 156 continue; 157 158 seq_printf(m, "[%p] ", class->key); 159 print_name(m, class); 160 seq_puts(m, "\n"); 161 } 162 seq_puts(m, "\n"); 163 164 return 0; 165 } 166 167 static const struct seq_operations lockdep_chains_ops = { 168 .start = lc_start, 169 .next = lc_next, 170 .stop = lc_stop, 171 .show = lc_show, 172 }; 173 174 static int lockdep_chains_open(struct inode *inode, struct file *file) 175 { 176 return seq_open(file, &lockdep_chains_ops); 177 } 178 179 static const struct file_operations proc_lockdep_chains_operations = { 180 .open = lockdep_chains_open, 181 .read = seq_read, 182 .llseek = seq_lseek, 183 .release = seq_release, 184 }; 185 #endif /* CONFIG_PROVE_LOCKING */ 186 187 static void lockdep_stats_debug_show(struct seq_file *m) 188 { 189 #ifdef CONFIG_DEBUG_LOCKDEP 190 unsigned long long hi1 = debug_atomic_read(hardirqs_on_events), 191 hi2 = debug_atomic_read(hardirqs_off_events), 192 hr1 = debug_atomic_read(redundant_hardirqs_on), 193 hr2 = debug_atomic_read(redundant_hardirqs_off), 194 si1 = debug_atomic_read(softirqs_on_events), 195 si2 = debug_atomic_read(softirqs_off_events), 196 sr1 = debug_atomic_read(redundant_softirqs_on), 197 sr2 = debug_atomic_read(redundant_softirqs_off); 198 199 seq_printf(m, " chain lookup misses: %11llu\n", 200 debug_atomic_read(chain_lookup_misses)); 201 seq_printf(m, " chain lookup hits: %11llu\n", 202 debug_atomic_read(chain_lookup_hits)); 203 seq_printf(m, " cyclic checks: %11llu\n", 204 debug_atomic_read(nr_cyclic_checks)); 205 seq_printf(m, " redundant checks: %11llu\n", 206 debug_atomic_read(nr_redundant_checks)); 207 seq_printf(m, " redundant links: %11llu\n", 208 debug_atomic_read(nr_redundant)); 209 seq_printf(m, " find-mask forwards checks: %11llu\n", 210 debug_atomic_read(nr_find_usage_forwards_checks)); 211 seq_printf(m, " find-mask backwards checks: %11llu\n", 212 debug_atomic_read(nr_find_usage_backwards_checks)); 213 214 seq_printf(m, " hardirq on events: %11llu\n", hi1); 215 seq_printf(m, " hardirq off events: %11llu\n", hi2); 216 seq_printf(m, " redundant hardirq ons: %11llu\n", hr1); 217 seq_printf(m, " redundant hardirq offs: %11llu\n", hr2); 218 seq_printf(m, " softirq on events: %11llu\n", si1); 219 seq_printf(m, " softirq off events: %11llu\n", si2); 220 seq_printf(m, " redundant softirq ons: %11llu\n", sr1); 221 seq_printf(m, " redundant softirq offs: %11llu\n", sr2); 222 #endif 223 } 224 225 static int lockdep_stats_show(struct seq_file *m, void *v) 226 { 227 struct lock_class *class; 228 unsigned long nr_unused = 0, nr_uncategorized = 0, 229 nr_irq_safe = 0, nr_irq_unsafe = 0, 230 nr_softirq_safe = 0, nr_softirq_unsafe = 0, 231 nr_hardirq_safe = 0, nr_hardirq_unsafe = 0, 232 nr_irq_read_safe = 0, nr_irq_read_unsafe = 0, 233 nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0, 234 nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0, 235 sum_forward_deps = 0; 236 237 list_for_each_entry(class, &all_lock_classes, lock_entry) { 238 239 if (class->usage_mask == 0) 240 nr_unused++; 241 if (class->usage_mask == LOCKF_USED) 242 nr_uncategorized++; 243 if (class->usage_mask & LOCKF_USED_IN_IRQ) 244 nr_irq_safe++; 245 if (class->usage_mask & LOCKF_ENABLED_IRQ) 246 nr_irq_unsafe++; 247 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ) 248 nr_softirq_safe++; 249 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ) 250 nr_softirq_unsafe++; 251 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ) 252 nr_hardirq_safe++; 253 if (class->usage_mask & LOCKF_ENABLED_HARDIRQ) 254 nr_hardirq_unsafe++; 255 if (class->usage_mask & LOCKF_USED_IN_IRQ_READ) 256 nr_irq_read_safe++; 257 if (class->usage_mask & LOCKF_ENABLED_IRQ_READ) 258 nr_irq_read_unsafe++; 259 if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ) 260 nr_softirq_read_safe++; 261 if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ_READ) 262 nr_softirq_read_unsafe++; 263 if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ) 264 nr_hardirq_read_safe++; 265 if (class->usage_mask & LOCKF_ENABLED_HARDIRQ_READ) 266 nr_hardirq_read_unsafe++; 267 268 #ifdef CONFIG_PROVE_LOCKING 269 sum_forward_deps += lockdep_count_forward_deps(class); 270 #endif 271 } 272 #ifdef CONFIG_DEBUG_LOCKDEP 273 DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused); 274 #endif 275 seq_printf(m, " lock-classes: %11lu [max: %lu]\n", 276 nr_lock_classes, MAX_LOCKDEP_KEYS); 277 seq_printf(m, " direct dependencies: %11lu [max: %lu]\n", 278 nr_list_entries, MAX_LOCKDEP_ENTRIES); 279 seq_printf(m, " indirect dependencies: %11lu\n", 280 sum_forward_deps); 281 282 /* 283 * Total number of dependencies: 284 * 285 * All irq-safe locks may nest inside irq-unsafe locks, 286 * plus all the other known dependencies: 287 */ 288 seq_printf(m, " all direct dependencies: %11lu\n", 289 nr_irq_unsafe * nr_irq_safe + 290 nr_hardirq_unsafe * nr_hardirq_safe + 291 nr_list_entries); 292 293 #ifdef CONFIG_PROVE_LOCKING 294 seq_printf(m, " dependency chains: %11lu [max: %lu]\n", 295 nr_lock_chains, MAX_LOCKDEP_CHAINS); 296 seq_printf(m, " dependency chain hlocks: %11d [max: %lu]\n", 297 nr_chain_hlocks, MAX_LOCKDEP_CHAIN_HLOCKS); 298 #endif 299 300 #ifdef CONFIG_TRACE_IRQFLAGS 301 seq_printf(m, " in-hardirq chains: %11u\n", 302 nr_hardirq_chains); 303 seq_printf(m, " in-softirq chains: %11u\n", 304 nr_softirq_chains); 305 #endif 306 seq_printf(m, " in-process chains: %11u\n", 307 nr_process_chains); 308 seq_printf(m, " stack-trace entries: %11lu [max: %lu]\n", 309 nr_stack_trace_entries, MAX_STACK_TRACE_ENTRIES); 310 seq_printf(m, " combined max dependencies: %11u\n", 311 (nr_hardirq_chains + 1) * 312 (nr_softirq_chains + 1) * 313 (nr_process_chains + 1) 314 ); 315 seq_printf(m, " hardirq-safe locks: %11lu\n", 316 nr_hardirq_safe); 317 seq_printf(m, " hardirq-unsafe locks: %11lu\n", 318 nr_hardirq_unsafe); 319 seq_printf(m, " softirq-safe locks: %11lu\n", 320 nr_softirq_safe); 321 seq_printf(m, " softirq-unsafe locks: %11lu\n", 322 nr_softirq_unsafe); 323 seq_printf(m, " irq-safe locks: %11lu\n", 324 nr_irq_safe); 325 seq_printf(m, " irq-unsafe locks: %11lu\n", 326 nr_irq_unsafe); 327 328 seq_printf(m, " hardirq-read-safe locks: %11lu\n", 329 nr_hardirq_read_safe); 330 seq_printf(m, " hardirq-read-unsafe locks: %11lu\n", 331 nr_hardirq_read_unsafe); 332 seq_printf(m, " softirq-read-safe locks: %11lu\n", 333 nr_softirq_read_safe); 334 seq_printf(m, " softirq-read-unsafe locks: %11lu\n", 335 nr_softirq_read_unsafe); 336 seq_printf(m, " irq-read-safe locks: %11lu\n", 337 nr_irq_read_safe); 338 seq_printf(m, " irq-read-unsafe locks: %11lu\n", 339 nr_irq_read_unsafe); 340 341 seq_printf(m, " uncategorized locks: %11lu\n", 342 nr_uncategorized); 343 seq_printf(m, " unused locks: %11lu\n", 344 nr_unused); 345 seq_printf(m, " max locking depth: %11u\n", 346 max_lockdep_depth); 347 #ifdef CONFIG_PROVE_LOCKING 348 seq_printf(m, " max bfs queue depth: %11u\n", 349 max_bfs_queue_depth); 350 #endif 351 lockdep_stats_debug_show(m); 352 seq_printf(m, " debug_locks: %11u\n", 353 debug_locks); 354 355 return 0; 356 } 357 358 static int lockdep_stats_open(struct inode *inode, struct file *file) 359 { 360 return single_open(file, lockdep_stats_show, NULL); 361 } 362 363 static const struct file_operations proc_lockdep_stats_operations = { 364 .open = lockdep_stats_open, 365 .read = seq_read, 366 .llseek = seq_lseek, 367 .release = single_release, 368 }; 369 370 #ifdef CONFIG_LOCK_STAT 371 372 struct lock_stat_data { 373 struct lock_class *class; 374 struct lock_class_stats stats; 375 }; 376 377 struct lock_stat_seq { 378 struct lock_stat_data *iter_end; 379 struct lock_stat_data stats[MAX_LOCKDEP_KEYS]; 380 }; 381 382 /* 383 * sort on absolute number of contentions 384 */ 385 static int lock_stat_cmp(const void *l, const void *r) 386 { 387 const struct lock_stat_data *dl = l, *dr = r; 388 unsigned long nl, nr; 389 390 nl = dl->stats.read_waittime.nr + dl->stats.write_waittime.nr; 391 nr = dr->stats.read_waittime.nr + dr->stats.write_waittime.nr; 392 393 return nr - nl; 394 } 395 396 static void seq_line(struct seq_file *m, char c, int offset, int length) 397 { 398 int i; 399 400 for (i = 0; i < offset; i++) 401 seq_puts(m, " "); 402 for (i = 0; i < length; i++) 403 seq_printf(m, "%c", c); 404 seq_puts(m, "\n"); 405 } 406 407 static void snprint_time(char *buf, size_t bufsiz, s64 nr) 408 { 409 s64 div; 410 s32 rem; 411 412 nr += 5; /* for display rounding */ 413 div = div_s64_rem(nr, 1000, &rem); 414 snprintf(buf, bufsiz, "%lld.%02d", (long long)div, (int)rem/10); 415 } 416 417 static void seq_time(struct seq_file *m, s64 time) 418 { 419 char num[15]; 420 421 snprint_time(num, sizeof(num), time); 422 seq_printf(m, " %14s", num); 423 } 424 425 static void seq_lock_time(struct seq_file *m, struct lock_time *lt) 426 { 427 seq_printf(m, "%14lu", lt->nr); 428 seq_time(m, lt->min); 429 seq_time(m, lt->max); 430 seq_time(m, lt->total); 431 seq_time(m, lt->nr ? div_s64(lt->total, lt->nr) : 0); 432 } 433 434 static void seq_stats(struct seq_file *m, struct lock_stat_data *data) 435 { 436 struct lockdep_subclass_key *ckey; 437 struct lock_class_stats *stats; 438 struct lock_class *class; 439 const char *cname; 440 int i, namelen; 441 char name[39]; 442 443 class = data->class; 444 stats = &data->stats; 445 446 namelen = 38; 447 if (class->name_version > 1) 448 namelen -= 2; /* XXX truncates versions > 9 */ 449 if (class->subclass) 450 namelen -= 2; 451 452 rcu_read_lock_sched(); 453 cname = rcu_dereference_sched(class->name); 454 ckey = rcu_dereference_sched(class->key); 455 456 if (!cname && !ckey) { 457 rcu_read_unlock_sched(); 458 return; 459 460 } else if (!cname) { 461 char str[KSYM_NAME_LEN]; 462 const char *key_name; 463 464 key_name = __get_key_name(ckey, str); 465 snprintf(name, namelen, "%s", key_name); 466 } else { 467 snprintf(name, namelen, "%s", cname); 468 } 469 rcu_read_unlock_sched(); 470 471 namelen = strlen(name); 472 if (class->name_version > 1) { 473 snprintf(name+namelen, 3, "#%d", class->name_version); 474 namelen += 2; 475 } 476 if (class->subclass) { 477 snprintf(name+namelen, 3, "/%d", class->subclass); 478 namelen += 2; 479 } 480 481 if (stats->write_holdtime.nr) { 482 if (stats->read_holdtime.nr) 483 seq_printf(m, "%38s-W:", name); 484 else 485 seq_printf(m, "%40s:", name); 486 487 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]); 488 seq_lock_time(m, &stats->write_waittime); 489 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]); 490 seq_lock_time(m, &stats->write_holdtime); 491 seq_puts(m, "\n"); 492 } 493 494 if (stats->read_holdtime.nr) { 495 seq_printf(m, "%38s-R:", name); 496 seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]); 497 seq_lock_time(m, &stats->read_waittime); 498 seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]); 499 seq_lock_time(m, &stats->read_holdtime); 500 seq_puts(m, "\n"); 501 } 502 503 if (stats->read_waittime.nr + stats->write_waittime.nr == 0) 504 return; 505 506 if (stats->read_holdtime.nr) 507 namelen += 2; 508 509 for (i = 0; i < LOCKSTAT_POINTS; i++) { 510 char ip[32]; 511 512 if (class->contention_point[i] == 0) 513 break; 514 515 if (!i) 516 seq_line(m, '-', 40-namelen, namelen); 517 518 snprintf(ip, sizeof(ip), "[<%p>]", 519 (void *)class->contention_point[i]); 520 seq_printf(m, "%40s %14lu %29s %pS\n", 521 name, stats->contention_point[i], 522 ip, (void *)class->contention_point[i]); 523 } 524 for (i = 0; i < LOCKSTAT_POINTS; i++) { 525 char ip[32]; 526 527 if (class->contending_point[i] == 0) 528 break; 529 530 if (!i) 531 seq_line(m, '-', 40-namelen, namelen); 532 533 snprintf(ip, sizeof(ip), "[<%p>]", 534 (void *)class->contending_point[i]); 535 seq_printf(m, "%40s %14lu %29s %pS\n", 536 name, stats->contending_point[i], 537 ip, (void *)class->contending_point[i]); 538 } 539 if (i) { 540 seq_puts(m, "\n"); 541 seq_line(m, '.', 0, 40 + 1 + 12 * (14 + 1)); 542 seq_puts(m, "\n"); 543 } 544 } 545 546 static void seq_header(struct seq_file *m) 547 { 548 seq_puts(m, "lock_stat version 0.4\n"); 549 550 if (unlikely(!debug_locks)) 551 seq_printf(m, "*WARNING* lock debugging disabled!! - possibly due to a lockdep warning\n"); 552 553 seq_line(m, '-', 0, 40 + 1 + 12 * (14 + 1)); 554 seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s " 555 "%14s %14s\n", 556 "class name", 557 "con-bounces", 558 "contentions", 559 "waittime-min", 560 "waittime-max", 561 "waittime-total", 562 "waittime-avg", 563 "acq-bounces", 564 "acquisitions", 565 "holdtime-min", 566 "holdtime-max", 567 "holdtime-total", 568 "holdtime-avg"); 569 seq_line(m, '-', 0, 40 + 1 + 12 * (14 + 1)); 570 seq_printf(m, "\n"); 571 } 572 573 static void *ls_start(struct seq_file *m, loff_t *pos) 574 { 575 struct lock_stat_seq *data = m->private; 576 struct lock_stat_data *iter; 577 578 if (*pos == 0) 579 return SEQ_START_TOKEN; 580 581 iter = data->stats + (*pos - 1); 582 if (iter >= data->iter_end) 583 iter = NULL; 584 585 return iter; 586 } 587 588 static void *ls_next(struct seq_file *m, void *v, loff_t *pos) 589 { 590 (*pos)++; 591 return ls_start(m, pos); 592 } 593 594 static void ls_stop(struct seq_file *m, void *v) 595 { 596 } 597 598 static int ls_show(struct seq_file *m, void *v) 599 { 600 if (v == SEQ_START_TOKEN) 601 seq_header(m); 602 else 603 seq_stats(m, v); 604 605 return 0; 606 } 607 608 static const struct seq_operations lockstat_ops = { 609 .start = ls_start, 610 .next = ls_next, 611 .stop = ls_stop, 612 .show = ls_show, 613 }; 614 615 static int lock_stat_open(struct inode *inode, struct file *file) 616 { 617 int res; 618 struct lock_class *class; 619 struct lock_stat_seq *data = vmalloc(sizeof(struct lock_stat_seq)); 620 621 if (!data) 622 return -ENOMEM; 623 624 res = seq_open(file, &lockstat_ops); 625 if (!res) { 626 struct lock_stat_data *iter = data->stats; 627 struct seq_file *m = file->private_data; 628 629 list_for_each_entry(class, &all_lock_classes, lock_entry) { 630 iter->class = class; 631 iter->stats = lock_stats(class); 632 iter++; 633 } 634 data->iter_end = iter; 635 636 sort(data->stats, data->iter_end - data->stats, 637 sizeof(struct lock_stat_data), 638 lock_stat_cmp, NULL); 639 640 m->private = data; 641 } else 642 vfree(data); 643 644 return res; 645 } 646 647 static ssize_t lock_stat_write(struct file *file, const char __user *buf, 648 size_t count, loff_t *ppos) 649 { 650 struct lock_class *class; 651 char c; 652 653 if (count) { 654 if (get_user(c, buf)) 655 return -EFAULT; 656 657 if (c != '0') 658 return count; 659 660 list_for_each_entry(class, &all_lock_classes, lock_entry) 661 clear_lock_stats(class); 662 } 663 return count; 664 } 665 666 static int lock_stat_release(struct inode *inode, struct file *file) 667 { 668 struct seq_file *seq = file->private_data; 669 670 vfree(seq->private); 671 return seq_release(inode, file); 672 } 673 674 static const struct file_operations proc_lock_stat_operations = { 675 .open = lock_stat_open, 676 .write = lock_stat_write, 677 .read = seq_read, 678 .llseek = seq_lseek, 679 .release = lock_stat_release, 680 }; 681 #endif /* CONFIG_LOCK_STAT */ 682 683 static int __init lockdep_proc_init(void) 684 { 685 proc_create("lockdep", S_IRUSR, NULL, &proc_lockdep_operations); 686 #ifdef CONFIG_PROVE_LOCKING 687 proc_create("lockdep_chains", S_IRUSR, NULL, 688 &proc_lockdep_chains_operations); 689 #endif 690 proc_create("lockdep_stats", S_IRUSR, NULL, 691 &proc_lockdep_stats_operations); 692 693 #ifdef CONFIG_LOCK_STAT 694 proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL, 695 &proc_lock_stat_operations); 696 #endif 697 698 return 0; 699 } 700 701 __initcall(lockdep_proc_init); 702 703