lockdep_proc.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  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. struct lock_class *class;
  174. unsigned long nr_unused = 0, nr_uncategorized = 0,
  175. nr_irq_safe = 0, nr_irq_unsafe = 0,
  176. nr_softirq_safe = 0, nr_softirq_unsafe = 0,
  177. nr_hardirq_safe = 0, nr_hardirq_unsafe = 0,
  178. nr_irq_read_safe = 0, nr_irq_read_unsafe = 0,
  179. nr_softirq_read_safe = 0, nr_softirq_read_unsafe = 0,
  180. nr_hardirq_read_safe = 0, nr_hardirq_read_unsafe = 0,
  181. sum_forward_deps = 0;
  182. list_for_each_entry(class, &all_lock_classes, lock_entry) {
  183. if (class->usage_mask == 0)
  184. nr_unused++;
  185. if (class->usage_mask == LOCKF_USED)
  186. nr_uncategorized++;
  187. if (class->usage_mask & LOCKF_USED_IN_IRQ)
  188. nr_irq_safe++;
  189. if (class->usage_mask & LOCKF_ENABLED_IRQ)
  190. nr_irq_unsafe++;
  191. if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ)
  192. nr_softirq_safe++;
  193. if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ)
  194. nr_softirq_unsafe++;
  195. if (class->usage_mask & LOCKF_USED_IN_HARDIRQ)
  196. nr_hardirq_safe++;
  197. if (class->usage_mask & LOCKF_ENABLED_HARDIRQ)
  198. nr_hardirq_unsafe++;
  199. if (class->usage_mask & LOCKF_USED_IN_IRQ_READ)
  200. nr_irq_read_safe++;
  201. if (class->usage_mask & LOCKF_ENABLED_IRQ_READ)
  202. nr_irq_read_unsafe++;
  203. if (class->usage_mask & LOCKF_USED_IN_SOFTIRQ_READ)
  204. nr_softirq_read_safe++;
  205. if (class->usage_mask & LOCKF_ENABLED_SOFTIRQ_READ)
  206. nr_softirq_read_unsafe++;
  207. if (class->usage_mask & LOCKF_USED_IN_HARDIRQ_READ)
  208. nr_hardirq_read_safe++;
  209. if (class->usage_mask & LOCKF_ENABLED_HARDIRQ_READ)
  210. nr_hardirq_read_unsafe++;
  211. #ifdef CONFIG_PROVE_LOCKING
  212. sum_forward_deps += lockdep_count_forward_deps(class);
  213. #endif
  214. }
  215. #ifdef CONFIG_DEBUG_LOCKDEP
  216. DEBUG_LOCKS_WARN_ON(debug_atomic_read(nr_unused_locks) != nr_unused);
  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. static int lockdep_stats_open(struct inode *inode, struct file *file)
  295. {
  296. return single_open(file, lockdep_stats_show, NULL);
  297. }
  298. static const struct file_operations proc_lockdep_stats_operations = {
  299. .open = lockdep_stats_open,
  300. .read = seq_read,
  301. .llseek = seq_lseek,
  302. .release = single_release,
  303. };
  304. #ifdef CONFIG_LOCK_STAT
  305. struct lock_stat_data {
  306. struct lock_class *class;
  307. struct lock_class_stats stats;
  308. };
  309. struct lock_stat_seq {
  310. struct lock_stat_data *iter_end;
  311. struct lock_stat_data stats[MAX_LOCKDEP_KEYS];
  312. };
  313. /*
  314. * sort on absolute number of contentions
  315. */
  316. static int lock_stat_cmp(const void *l, const void *r)
  317. {
  318. const struct lock_stat_data *dl = l, *dr = r;
  319. unsigned long nl, nr;
  320. nl = dl->stats.read_waittime.nr + dl->stats.write_waittime.nr;
  321. nr = dr->stats.read_waittime.nr + dr->stats.write_waittime.nr;
  322. return nr - nl;
  323. }
  324. static void seq_line(struct seq_file *m, char c, int offset, int length)
  325. {
  326. int i;
  327. for (i = 0; i < offset; i++)
  328. seq_puts(m, " ");
  329. for (i = 0; i < length; i++)
  330. seq_printf(m, "%c", c);
  331. seq_puts(m, "\n");
  332. }
  333. static void snprint_time(char *buf, size_t bufsiz, s64 nr)
  334. {
  335. s64 div;
  336. s32 rem;
  337. nr += 5; /* for display rounding */
  338. div = div_s64_rem(nr, 1000, &rem);
  339. snprintf(buf, bufsiz, "%lld.%02d", (long long)div, (int)rem/10);
  340. }
  341. static void seq_time(struct seq_file *m, s64 time)
  342. {
  343. char num[15];
  344. snprint_time(num, sizeof(num), time);
  345. seq_printf(m, " %14s", num);
  346. }
  347. static void seq_lock_time(struct seq_file *m, struct lock_time *lt)
  348. {
  349. seq_printf(m, "%14lu", lt->nr);
  350. seq_time(m, lt->min);
  351. seq_time(m, lt->max);
  352. seq_time(m, lt->total);
  353. seq_time(m, lt->nr ? div_s64(lt->total, lt->nr) : 0);
  354. }
  355. static void seq_stats(struct seq_file *m, struct lock_stat_data *data)
  356. {
  357. struct lockdep_subclass_key *ckey;
  358. struct lock_class_stats *stats;
  359. struct lock_class *class;
  360. const char *cname;
  361. int i, namelen;
  362. char name[39];
  363. class = data->class;
  364. stats = &data->stats;
  365. namelen = 38;
  366. if (class->name_version > 1)
  367. namelen -= 2; /* XXX truncates versions > 9 */
  368. if (class->subclass)
  369. namelen -= 2;
  370. rcu_read_lock_sched();
  371. cname = rcu_dereference_sched(class->name);
  372. ckey = rcu_dereference_sched(class->key);
  373. if (!cname && !ckey) {
  374. rcu_read_unlock_sched();
  375. return;
  376. } else if (!cname) {
  377. char str[KSYM_NAME_LEN];
  378. const char *key_name;
  379. key_name = __get_key_name(ckey, str);
  380. snprintf(name, namelen, "%s", key_name);
  381. } else {
  382. snprintf(name, namelen, "%s", cname);
  383. }
  384. rcu_read_unlock_sched();
  385. namelen = strlen(name);
  386. if (class->name_version > 1) {
  387. snprintf(name+namelen, 3, "#%d", class->name_version);
  388. namelen += 2;
  389. }
  390. if (class->subclass) {
  391. snprintf(name+namelen, 3, "/%d", class->subclass);
  392. namelen += 2;
  393. }
  394. if (stats->write_holdtime.nr) {
  395. if (stats->read_holdtime.nr)
  396. seq_printf(m, "%38s-W:", name);
  397. else
  398. seq_printf(m, "%40s:", name);
  399. seq_printf(m, "%14lu ", stats->bounces[bounce_contended_write]);
  400. seq_lock_time(m, &stats->write_waittime);
  401. seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_write]);
  402. seq_lock_time(m, &stats->write_holdtime);
  403. seq_puts(m, "\n");
  404. }
  405. if (stats->read_holdtime.nr) {
  406. seq_printf(m, "%38s-R:", name);
  407. seq_printf(m, "%14lu ", stats->bounces[bounce_contended_read]);
  408. seq_lock_time(m, &stats->read_waittime);
  409. seq_printf(m, " %14lu ", stats->bounces[bounce_acquired_read]);
  410. seq_lock_time(m, &stats->read_holdtime);
  411. seq_puts(m, "\n");
  412. }
  413. if (stats->read_waittime.nr + stats->write_waittime.nr == 0)
  414. return;
  415. if (stats->read_holdtime.nr)
  416. namelen += 2;
  417. for (i = 0; i < LOCKSTAT_POINTS; i++) {
  418. char ip[32];
  419. if (class->contention_point[i] == 0)
  420. break;
  421. if (!i)
  422. seq_line(m, '-', 40-namelen, namelen);
  423. snprintf(ip, sizeof(ip), "[<%p>]",
  424. (void *)class->contention_point[i]);
  425. seq_printf(m, "%40s %14lu %29s %pS\n",
  426. name, stats->contention_point[i],
  427. ip, (void *)class->contention_point[i]);
  428. }
  429. for (i = 0; i < LOCKSTAT_POINTS; i++) {
  430. char ip[32];
  431. if (class->contending_point[i] == 0)
  432. break;
  433. if (!i)
  434. seq_line(m, '-', 40-namelen, namelen);
  435. snprintf(ip, sizeof(ip), "[<%p>]",
  436. (void *)class->contending_point[i]);
  437. seq_printf(m, "%40s %14lu %29s %pS\n",
  438. name, stats->contending_point[i],
  439. ip, (void *)class->contending_point[i]);
  440. }
  441. if (i) {
  442. seq_puts(m, "\n");
  443. seq_line(m, '.', 0, 40 + 1 + 12 * (14 + 1));
  444. seq_puts(m, "\n");
  445. }
  446. }
  447. static void seq_header(struct seq_file *m)
  448. {
  449. seq_puts(m, "lock_stat version 0.4\n");
  450. if (unlikely(!debug_locks))
  451. seq_printf(m, "*WARNING* lock debugging disabled!! - possibly due to a lockdep warning\n");
  452. seq_line(m, '-', 0, 40 + 1 + 12 * (14 + 1));
  453. seq_printf(m, "%40s %14s %14s %14s %14s %14s %14s %14s %14s %14s %14s "
  454. "%14s %14s\n",
  455. "class name",
  456. "con-bounces",
  457. "contentions",
  458. "waittime-min",
  459. "waittime-max",
  460. "waittime-total",
  461. "waittime-avg",
  462. "acq-bounces",
  463. "acquisitions",
  464. "holdtime-min",
  465. "holdtime-max",
  466. "holdtime-total",
  467. "holdtime-avg");
  468. seq_line(m, '-', 0, 40 + 1 + 12 * (14 + 1));
  469. seq_printf(m, "\n");
  470. }
  471. static void *ls_start(struct seq_file *m, loff_t *pos)
  472. {
  473. struct lock_stat_seq *data = m->private;
  474. struct lock_stat_data *iter;
  475. if (*pos == 0)
  476. return SEQ_START_TOKEN;
  477. iter = data->stats + (*pos - 1);
  478. if (iter >= data->iter_end)
  479. iter = NULL;
  480. return iter;
  481. }
  482. static void *ls_next(struct seq_file *m, void *v, loff_t *pos)
  483. {
  484. (*pos)++;
  485. return ls_start(m, pos);
  486. }
  487. static void ls_stop(struct seq_file *m, void *v)
  488. {
  489. }
  490. static int ls_show(struct seq_file *m, void *v)
  491. {
  492. if (v == SEQ_START_TOKEN)
  493. seq_header(m);
  494. else
  495. seq_stats(m, v);
  496. return 0;
  497. }
  498. static const struct seq_operations lockstat_ops = {
  499. .start = ls_start,
  500. .next = ls_next,
  501. .stop = ls_stop,
  502. .show = ls_show,
  503. };
  504. static int lock_stat_open(struct inode *inode, struct file *file)
  505. {
  506. int res;
  507. struct lock_class *class;
  508. struct lock_stat_seq *data = vmalloc(sizeof(struct lock_stat_seq));
  509. if (!data)
  510. return -ENOMEM;
  511. res = seq_open(file, &lockstat_ops);
  512. if (!res) {
  513. struct lock_stat_data *iter = data->stats;
  514. struct seq_file *m = file->private_data;
  515. list_for_each_entry(class, &all_lock_classes, lock_entry) {
  516. iter->class = class;
  517. iter->stats = lock_stats(class);
  518. iter++;
  519. }
  520. data->iter_end = iter;
  521. sort(data->stats, data->iter_end - data->stats,
  522. sizeof(struct lock_stat_data),
  523. lock_stat_cmp, NULL);
  524. m->private = data;
  525. } else
  526. vfree(data);
  527. return res;
  528. }
  529. static ssize_t lock_stat_write(struct file *file, const char __user *buf,
  530. size_t count, loff_t *ppos)
  531. {
  532. struct lock_class *class;
  533. char c;
  534. if (count) {
  535. if (get_user(c, buf))
  536. return -EFAULT;
  537. if (c != '0')
  538. return count;
  539. list_for_each_entry(class, &all_lock_classes, lock_entry)
  540. clear_lock_stats(class);
  541. }
  542. return count;
  543. }
  544. static int lock_stat_release(struct inode *inode, struct file *file)
  545. {
  546. struct seq_file *seq = file->private_data;
  547. vfree(seq->private);
  548. return seq_release(inode, file);
  549. }
  550. static const struct file_operations proc_lock_stat_operations = {
  551. .open = lock_stat_open,
  552. .write = lock_stat_write,
  553. .read = seq_read,
  554. .llseek = seq_lseek,
  555. .release = lock_stat_release,
  556. };
  557. #endif /* CONFIG_LOCK_STAT */
  558. static int __init lockdep_proc_init(void)
  559. {
  560. proc_create_seq("lockdep", S_IRUSR, NULL, &lockdep_ops);
  561. #ifdef CONFIG_PROVE_LOCKING
  562. proc_create_seq("lockdep_chains", S_IRUSR, NULL, &lockdep_chains_ops);
  563. #endif
  564. proc_create("lockdep_stats", S_IRUSR, NULL,
  565. &proc_lockdep_stats_operations);
  566. #ifdef CONFIG_LOCK_STAT
  567. proc_create("lock_stat", S_IRUSR | S_IWUSR, NULL,
  568. &proc_lock_stat_operations);
  569. #endif
  570. return 0;
  571. }
  572. __initcall(lockdep_proc_init);