LCOV - code coverage report
Current view: top level - kernel/locking - lockdep_proc.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 5 191 2.6 %
Date: 2021-04-22 12:43:58 Functions: 1 12 8.3 %

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

Generated by: LCOV version 1.14