lockdep_proc.c 17 KB

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