~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/kernel/slow-work-debugfs.c

Version: ~ [ linux-5.5-rc7 ] ~ [ linux-5.4.13 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.97 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.166 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.210 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.210 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.81 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /* Slow work debugging
  2  *
  3  * Copyright (C) 2009 Red Hat, Inc. All Rights Reserved.
  4  * Written by David Howells (dhowells@redhat.com)
  5  *
  6  * This program is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU General Public Licence
  8  * as published by the Free Software Foundation; either version
  9  * 2 of the Licence, or (at your option) any later version.
 10  */
 11 
 12 #include <linux/module.h>
 13 #include <linux/slow-work.h>
 14 #include <linux/fs.h>
 15 #include <linux/time.h>
 16 #include <linux/seq_file.h>
 17 #include "slow-work.h"
 18 
 19 #define ITERATOR_SHIFT          (BITS_PER_LONG - 4)
 20 #define ITERATOR_SELECTOR       (0xfUL << ITERATOR_SHIFT)
 21 #define ITERATOR_COUNTER        (~ITERATOR_SELECTOR)
 22 
 23 void slow_work_new_thread_desc(struct slow_work *work, struct seq_file *m)
 24 {
 25         seq_puts(m, "Slow-work: New thread");
 26 }
 27 
 28 /*
 29  * Render the time mark field on a work item into a 5-char time with units plus
 30  * a space
 31  */
 32 static void slow_work_print_mark(struct seq_file *m, struct slow_work *work)
 33 {
 34         struct timespec now, diff;
 35 
 36         now = CURRENT_TIME;
 37         diff = timespec_sub(now, work->mark);
 38 
 39         if (diff.tv_sec < 0)
 40                 seq_puts(m, "  -ve ");
 41         else if (diff.tv_sec == 0 && diff.tv_nsec < 1000)
 42                 seq_printf(m, "%3luns ", diff.tv_nsec);
 43         else if (diff.tv_sec == 0 && diff.tv_nsec < 1000000)
 44                 seq_printf(m, "%3luus ", diff.tv_nsec / 1000);
 45         else if (diff.tv_sec == 0 && diff.tv_nsec < 1000000000)
 46                 seq_printf(m, "%3lums ", diff.tv_nsec / 1000000);
 47         else if (diff.tv_sec <= 1)
 48                 seq_puts(m, "   1s ");
 49         else if (diff.tv_sec < 60)
 50                 seq_printf(m, "%4lus ", diff.tv_sec);
 51         else if (diff.tv_sec < 60 * 60)
 52                 seq_printf(m, "%4lum ", diff.tv_sec / 60);
 53         else if (diff.tv_sec < 60 * 60 * 24)
 54                 seq_printf(m, "%4luh ", diff.tv_sec / 3600);
 55         else
 56                 seq_puts(m, "exces ");
 57 }
 58 
 59 /*
 60  * Describe a slow work item for debugfs
 61  */
 62 static int slow_work_runqueue_show(struct seq_file *m, void *v)
 63 {
 64         struct slow_work *work;
 65         struct list_head *p = v;
 66         unsigned long id;
 67 
 68         switch ((unsigned long) v) {
 69         case 1:
 70                 seq_puts(m, "THR PID   ITEM ADDR        FL MARK  DESC\n");
 71                 return 0;
 72         case 2:
 73                 seq_puts(m, "=== ===== ================ == ===== ==========\n");
 74                 return 0;
 75 
 76         case 3 ... 3 + SLOW_WORK_THREAD_LIMIT - 1:
 77                 id = (unsigned long) v - 3;
 78 
 79                 read_lock(&slow_work_execs_lock);
 80                 work = slow_work_execs[id];
 81                 if (work) {
 82                         smp_read_barrier_depends();
 83 
 84                         seq_printf(m, "%3lu %5d %16p %2lx ",
 85                                    id, slow_work_pids[id], work, work->flags);
 86                         slow_work_print_mark(m, work);
 87 
 88                         if (work->ops->desc)
 89                                 work->ops->desc(work, m);
 90                         seq_putc(m, '\n');
 91                 }
 92                 read_unlock(&slow_work_execs_lock);
 93                 return 0;
 94 
 95         default:
 96                 work = list_entry(p, struct slow_work, link);
 97                 seq_printf(m, "%3s     - %16p %2lx ",
 98                            work->flags & SLOW_WORK_VERY_SLOW ? "vsq" : "sq",
 99                            work, work->flags);
100                 slow_work_print_mark(m, work);
101 
102                 if (work->ops->desc)
103                         work->ops->desc(work, m);
104                 seq_putc(m, '\n');
105                 return 0;
106         }
107 }
108 
109 /*
110  * map the iterator to a work item
111  */
112 static void *slow_work_runqueue_index(struct seq_file *m, loff_t *_pos)
113 {
114         struct list_head *p;
115         unsigned long count, id;
116 
117         switch (*_pos >> ITERATOR_SHIFT) {
118         case 0x0:
119                 if (*_pos == 0)
120                         *_pos = 1;
121                 if (*_pos < 3)
122                         return (void *)(unsigned long) *_pos;
123                 if (*_pos < 3 + SLOW_WORK_THREAD_LIMIT)
124                         for (id = *_pos - 3;
125                              id < SLOW_WORK_THREAD_LIMIT;
126                              id++, (*_pos)++)
127                                 if (slow_work_execs[id])
128                                         return (void *)(unsigned long) *_pos;
129                 *_pos = 0x1UL << ITERATOR_SHIFT;
130 
131         case 0x1:
132                 count = *_pos & ITERATOR_COUNTER;
133                 list_for_each(p, &slow_work_queue) {
134                         if (count == 0)
135                                 return p;
136                         count--;
137                 }
138                 *_pos = 0x2UL << ITERATOR_SHIFT;
139 
140         case 0x2:
141                 count = *_pos & ITERATOR_COUNTER;
142                 list_for_each(p, &vslow_work_queue) {
143                         if (count == 0)
144                                 return p;
145                         count--;
146                 }
147                 *_pos = 0x3UL << ITERATOR_SHIFT;
148 
149         default:
150                 return NULL;
151         }
152 }
153 
154 /*
155  * set up the iterator to start reading from the first line
156  */
157 static void *slow_work_runqueue_start(struct seq_file *m, loff_t *_pos)
158 {
159         spin_lock_irq(&slow_work_queue_lock);
160         return slow_work_runqueue_index(m, _pos);
161 }
162 
163 /*
164  * move to the next line
165  */
166 static void *slow_work_runqueue_next(struct seq_file *m, void *v, loff_t *_pos)
167 {
168         struct list_head *p = v;
169         unsigned long selector = *_pos >> ITERATOR_SHIFT;
170 
171         (*_pos)++;
172         switch (selector) {
173         case 0x0:
174                 return slow_work_runqueue_index(m, _pos);
175 
176         case 0x1:
177                 if (*_pos >> ITERATOR_SHIFT == 0x1) {
178                         p = p->next;
179                         if (p != &slow_work_queue)
180                                 return p;
181                 }
182                 *_pos = 0x2UL << ITERATOR_SHIFT;
183                 p = &vslow_work_queue;
184 
185         case 0x2:
186                 if (*_pos >> ITERATOR_SHIFT == 0x2) {
187                         p = p->next;
188                         if (p != &vslow_work_queue)
189                                 return p;
190                 }
191                 *_pos = 0x3UL << ITERATOR_SHIFT;
192 
193         default:
194                 return NULL;
195         }
196 }
197 
198 /*
199  * clean up after reading
200  */
201 static void slow_work_runqueue_stop(struct seq_file *m, void *v)
202 {
203         spin_unlock_irq(&slow_work_queue_lock);
204 }
205 
206 static const struct seq_operations slow_work_runqueue_ops = {
207         .start          = slow_work_runqueue_start,
208         .stop           = slow_work_runqueue_stop,
209         .next           = slow_work_runqueue_next,
210         .show           = slow_work_runqueue_show,
211 };
212 
213 /*
214  * open "/sys/kernel/debug/slow_work/runqueue" to list queue contents
215  */
216 static int slow_work_runqueue_open(struct inode *inode, struct file *file)
217 {
218         return seq_open(file, &slow_work_runqueue_ops);
219 }
220 
221 const struct file_operations slow_work_runqueue_fops = {
222         .owner          = THIS_MODULE,
223         .open           = slow_work_runqueue_open,
224         .read           = seq_read,
225         .llseek         = seq_lseek,
226         .release        = seq_release,
227 };
228 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp