Commit 8fba10a42d191de612e60e7009c8f0313f90a9b3

Authored by David Howells
1 parent 6b8268b17a

SLOW_WORK: Allow the work items to be viewed through a /proc file

Allow the executing and queued work items to be viewed through a /proc file
for debugging purposes.  The contents look something like the following:

    THR PID   ITEM ADDR        FL MARK  DESC
    === ===== ================ == ===== ==========
      0  3005 ffff880023f52348  a 952ms FSC: OBJ17d3: LOOK
      1  3006 ffff880024e33668  2 160ms FSC: OBJ17e5 OP60d3b: Write1/Store fl=2
      2  3165 ffff8800296dd180  a 424ms FSC: OBJ17e4: LOOK
      3  4089 ffff8800262c8d78  a 212ms FSC: OBJ17ea: CRTN
      4  4090 ffff88002792bed8  2 388ms FSC: OBJ17e8 OP60d36: Write1/Store fl=2
      5  4092 ffff88002a0ef308  2 388ms FSC: OBJ17e7 OP60d2e: Write1/Store fl=2
      6  4094 ffff88002abaf4b8  2 132ms FSC: OBJ17e2 OP60d4e: Write1/Store fl=2
      7  4095 ffff88002bb188e0  a 388ms FSC: OBJ17e9: CRTN
    vsq     - ffff880023d99668  1 308ms FSC: OBJ17e0 OP60f91: Write1/EnQ fl=2
    vsq     - ffff8800295d1740  1 212ms FSC: OBJ16be OP4d4b6: Write1/EnQ fl=2
    vsq     - ffff880025ba3308  1 160ms FSC: OBJ179a OP58dec: Write1/EnQ fl=2
    vsq     - ffff880024ec83e0  1 160ms FSC: OBJ17ae OP599f2: Write1/EnQ fl=2
    vsq     - ffff880026618e00  1 160ms FSC: OBJ17e6 OP60d33: Write1/EnQ fl=2
    vsq     - ffff880025a2a4b8  1 132ms FSC: OBJ16a2 OP4d583: Write1/EnQ fl=2
    vsq     - ffff880023cbe6d8  9 212ms FSC: OBJ17eb: LOOK
    vsq     - ffff880024d37590  9 212ms FSC: OBJ17ec: LOOK
    vsq     - ffff880027746cb0  9 212ms FSC: OBJ17ed: LOOK
    vsq     - ffff880024d37ae8  9 212ms FSC: OBJ17ee: LOOK
    vsq     - ffff880024d37cb0  9 212ms FSC: OBJ17ef: LOOK
    vsq     - ffff880025036550  9 212ms FSC: OBJ17f0: LOOK
    vsq     - ffff8800250368e0  9 212ms FSC: OBJ17f1: LOOK
    vsq     - ffff880025036aa8  9 212ms FSC: OBJ17f2: LOOK

In the 'THR' column, executing items show the thread they're occupying and
queued threads indicate which queue they're on.  'PID' shows the process ID of
a slow-work thread that's executing something.  'FL' shows the work item flags.
'MARK' indicates how long since an item was queued or began executing.  Lastly,
the 'DESC' column permits the owner of an item to give some information.

Signed-off-by: David Howells <dhowells@redhat.com>

Showing 7 changed files with 413 additions and 12 deletions Side-by-side Diff

Documentation/slow-work.txt
... ... @@ -149,7 +149,8 @@
149 149 ===============
150 150  
151 151 Each work item requires a table of operations of type struct slow_work_ops.
152   -Only ->execute() is required, getting and putting of a reference are optional.
  152 +Only ->execute() is required; the getting and putting of a reference and the
  153 +describing of an item are all optional.
153 154  
154 155 (*) Get a reference on an item:
155 156  
156 157  
... ... @@ -179,7 +180,17 @@
179 180 This should perform the work required of the item. It may sleep, it may
180 181 perform disk I/O and it may wait for locks.
181 182  
  183 + (*) View an item through /proc:
182 184  
  185 + void (*desc)(struct slow_work *work, struct seq_file *m);
  186 +
  187 + If supplied, this should print to 'm' a small string describing the work
  188 + the item is to do. This should be no more than about 40 characters, and
  189 + shouldn't include a newline character.
  190 +
  191 + See the 'Viewing executing and queued items' section below.
  192 +
  193 +
183 194 ==================
184 195 POOL CONFIGURATION
185 196 ==================
... ... @@ -203,4 +214,50 @@
203 214 is bounded to between 1 and one fewer than the number of active threads.
204 215 This ensures there is always at least one thread that can process very
205 216 slow work items, and always at least one thread that won't.
  217 +
  218 +
  219 +==================================
  220 +VIEWING EXECUTING AND QUEUED ITEMS
  221 +==================================
  222 +
  223 +If CONFIG_SLOW_WORK_PROC is enabled, a proc file is made available:
  224 +
  225 + /proc/slow_work_rq
  226 +
  227 +through which the list of work items being executed and the queues of items to
  228 +be executed may be viewed. The owner of a work item is given the chance to
  229 +add some information of its own.
  230 +
  231 +The contents look something like the following:
  232 +
  233 + THR PID ITEM ADDR FL MARK DESC
  234 + === ===== ================ == ===== ==========
  235 + 0 3005 ffff880023f52348 a 952ms FSC: OBJ17d3: LOOK
  236 + 1 3006 ffff880024e33668 2 160ms FSC: OBJ17e5 OP60d3b: Write1/Store fl=2
  237 + 2 3165 ffff8800296dd180 a 424ms FSC: OBJ17e4: LOOK
  238 + 3 4089 ffff8800262c8d78 a 212ms FSC: OBJ17ea: CRTN
  239 + 4 4090 ffff88002792bed8 2 388ms FSC: OBJ17e8 OP60d36: Write1/Store fl=2
  240 + 5 4092 ffff88002a0ef308 2 388ms FSC: OBJ17e7 OP60d2e: Write1/Store fl=2
  241 + 6 4094 ffff88002abaf4b8 2 132ms FSC: OBJ17e2 OP60d4e: Write1/Store fl=2
  242 + 7 4095 ffff88002bb188e0 a 388ms FSC: OBJ17e9: CRTN
  243 + vsq - ffff880023d99668 1 308ms FSC: OBJ17e0 OP60f91: Write1/EnQ fl=2
  244 + vsq - ffff8800295d1740 1 212ms FSC: OBJ16be OP4d4b6: Write1/EnQ fl=2
  245 + vsq - ffff880025ba3308 1 160ms FSC: OBJ179a OP58dec: Write1/EnQ fl=2
  246 + vsq - ffff880024ec83e0 1 160ms FSC: OBJ17ae OP599f2: Write1/EnQ fl=2
  247 + vsq - ffff880026618e00 1 160ms FSC: OBJ17e6 OP60d33: Write1/EnQ fl=2
  248 + vsq - ffff880025a2a4b8 1 132ms FSC: OBJ16a2 OP4d583: Write1/EnQ fl=2
  249 + vsq - ffff880023cbe6d8 9 212ms FSC: OBJ17eb: LOOK
  250 + vsq - ffff880024d37590 9 212ms FSC: OBJ17ec: LOOK
  251 + vsq - ffff880027746cb0 9 212ms FSC: OBJ17ed: LOOK
  252 + vsq - ffff880024d37ae8 9 212ms FSC: OBJ17ee: LOOK
  253 + vsq - ffff880024d37cb0 9 212ms FSC: OBJ17ef: LOOK
  254 + vsq - ffff880025036550 9 212ms FSC: OBJ17f0: LOOK
  255 + vsq - ffff8800250368e0 9 212ms FSC: OBJ17f1: LOOK
  256 + vsq - ffff880025036aa8 9 212ms FSC: OBJ17f2: LOOK
  257 +
  258 +In the 'THR' column, executing items show the thread they're occupying and
  259 +queued threads indicate which queue they're on. 'PID' shows the process ID of
  260 +a slow-work thread that's executing something. 'FL' shows the work item flags.
  261 +'MARK' indicates how long since an item was queued or began executing. Lastly,
  262 +the 'DESC' column permits the owner of an item to give some information.
include/linux/slow-work.h
... ... @@ -20,6 +20,9 @@
20 20 #include <linux/timer.h>
21 21  
22 22 struct slow_work;
  23 +#ifdef CONFIG_SLOW_WORK_PROC
  24 +struct seq_file;
  25 +#endif
23 26  
24 27 /*
25 28 * The operations used to support slow work items
... ... @@ -38,6 +41,11 @@
38 41  
39 42 /* execute a work item */
40 43 void (*execute)(struct slow_work *work);
  44 +
  45 +#ifdef CONFIG_SLOW_WORK_PROC
  46 + /* describe a work item for /proc */
  47 + void (*desc)(struct slow_work *work, struct seq_file *m);
  48 +#endif
41 49 };
42 50  
43 51 /*
... ... @@ -56,6 +64,9 @@
56 64 #define SLOW_WORK_DELAYED 5 /* item is struct delayed_slow_work with active timer */
57 65 const struct slow_work_ops *ops; /* operations table for this item */
58 66 struct list_head link; /* link in queue */
  67 +#ifdef CONFIG_SLOW_WORK_PROC
  68 + struct timespec mark; /* jiffies at which queued or exec begun */
  69 +#endif
59 70 };
60 71  
61 72 struct delayed_slow_work {
... ... @@ -1098,6 +1098,16 @@
1098 1098  
1099 1099 See Documentation/slow-work.txt.
1100 1100  
  1101 +config SLOW_WORK_PROC
  1102 + bool "Slow work debugging through /proc"
  1103 + default n
  1104 + depends on SLOW_WORK && PROC_FS
  1105 + help
  1106 + Display the contents of the slow work run queue through /proc,
  1107 + including items currently executing.
  1108 +
  1109 + See Documentation/slow-work.txt.
  1110 +
1101 1111 endmenu # General setup
1102 1112  
1103 1113 config HAVE_GENERIC_DMA_COHERENT
... ... @@ -94,6 +94,7 @@
94 94 obj-$(CONFIG_RING_BUFFER) += trace/
95 95 obj-$(CONFIG_SMP) += sched_cpupri.o
96 96 obj-$(CONFIG_SLOW_WORK) += slow-work.o
  97 +obj-$(CONFIG_SLOW_WORK_PROC) += slow-work-proc.o
97 98 obj-$(CONFIG_PERF_EVENTS) += perf_event.o
98 99  
99 100 ifneq ($(CONFIG_SCHED_OMIT_FRAME_POINTER),y)
kernel/slow-work-proc.c
  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 /proc
  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 "/proc/slow_work_rq" 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 +};
... ... @@ -16,14 +16,9 @@
16 16 #include <linux/kthread.h>
17 17 #include <linux/freezer.h>
18 18 #include <linux/wait.h>
  19 +#include <linux/proc_fs.h>
  20 +#include "slow-work.h"
19 21  
20   -#define SLOW_WORK_CULL_TIMEOUT (5 * HZ) /* cull threads 5s after running out of
21   - * things to do */
22   -#define SLOW_WORK_OOM_TIMEOUT (5 * HZ) /* can't start new threads for 5s after
23   - * OOM */
24   -
25   -#define SLOW_WORK_THREAD_LIMIT 255 /* abs maximum number of slow-work threads */
26   -
27 22 static void slow_work_cull_timeout(unsigned long);
28 23 static void slow_work_oom_timeout(unsigned long);
29 24  
... ... @@ -117,6 +112,15 @@
117 112 #endif
118 113  
119 114 /*
  115 + * Data for tracking currently executing items for indication through /proc
  116 + */
  117 +#ifdef CONFIG_SLOW_WORK_PROC
  118 +struct slow_work *slow_work_execs[SLOW_WORK_THREAD_LIMIT];
  119 +pid_t slow_work_pids[SLOW_WORK_THREAD_LIMIT];
  120 +DEFINE_RWLOCK(slow_work_execs_lock);
  121 +#endif
  122 +
  123 +/*
120 124 * The queues of work items and the lock governing access to them. These are
121 125 * shared between all the CPUs. It doesn't make sense to have per-CPU queues
122 126 * as the number of threads bears no relation to the number of CPUs.
... ... @@ -124,9 +128,9 @@
124 128 * There are two queues of work items: one for slow work items, and one for
125 129 * very slow work items.
126 130 */
127   -static LIST_HEAD(slow_work_queue);
128   -static LIST_HEAD(vslow_work_queue);
129   -static DEFINE_SPINLOCK(slow_work_queue_lock);
  131 +LIST_HEAD(slow_work_queue);
  132 +LIST_HEAD(vslow_work_queue);
  133 +DEFINE_SPINLOCK(slow_work_queue_lock);
130 134  
131 135 /*
132 136 * The thread controls. A variable used to signal to the threads that they
... ... @@ -182,7 +186,7 @@
182 186 * Attempt to execute stuff queued on a slow thread. Return true if we managed
183 187 * it, false if there was nothing to do.
184 188 */
185   -static bool slow_work_execute(int id)
  189 +static noinline bool slow_work_execute(int id)
186 190 {
187 191 #ifdef CONFIG_MODULES
188 192 struct module *module;
... ... @@ -227,6 +231,10 @@
227 231 if (work)
228 232 slow_work_thread_processing[id] = work->owner;
229 233 #endif
  234 + if (work) {
  235 + slow_work_mark_time(work);
  236 + slow_work_begin_exec(id, work);
  237 + }
230 238  
231 239 spin_unlock_irq(&slow_work_queue_lock);
232 240  
... ... @@ -247,6 +255,8 @@
247 255 /* wake up anyone waiting for this work to be complete */
248 256 wake_up_bit(&work->flags, SLOW_WORK_EXECUTING);
249 257  
  258 + slow_work_end_exec(id, work);
  259 +
250 260 /* if someone tried to enqueue the item whilst we were executing it,
251 261 * then it'll be left unenqueued to avoid multiple threads trying to
252 262 * execute it simultaneously
... ... @@ -285,6 +295,7 @@
285 295 * - we transfer our ref on the item back to the appropriate queue
286 296 * - don't wake another thread up as we're awake already
287 297 */
  298 + slow_work_mark_time(work);
288 299 if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags))
289 300 list_add_tail(&work->link, &vslow_work_queue);
290 301 else
... ... @@ -368,6 +379,7 @@
368 379 ret = slow_work_get_ref(work);
369 380 if (ret < 0)
370 381 goto failed;
  382 + slow_work_mark_time(work);
371 383 if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags))
372 384 list_add_tail(&work->link, &vslow_work_queue);
373 385 else
... ... @@ -489,6 +501,7 @@
489 501 set_bit(SLOW_WORK_ENQ_DEFERRED, &work->flags);
490 502 put = true;
491 503 } else {
  504 + slow_work_mark_time(work);
492 505 if (test_bit(SLOW_WORK_VERY_SLOW, &work->flags))
493 506 list_add_tail(&work->link, &vslow_work_queue);
494 507 else
... ... @@ -627,6 +640,7 @@
627 640 id = find_first_zero_bit(slow_work_ids, SLOW_WORK_THREAD_LIMIT);
628 641 BUG_ON(id < 0 || id >= SLOW_WORK_THREAD_LIMIT);
629 642 __set_bit(id, slow_work_ids);
  643 + slow_work_set_thread_pid(id, current->pid);
630 644 spin_unlock_irq(&slow_work_queue_lock);
631 645  
632 646 sprintf(current->comm, "kslowd%03u", id);
... ... @@ -669,6 +683,7 @@
669 683 }
670 684  
671 685 spin_lock_irq(&slow_work_queue_lock);
  686 + slow_work_set_thread_pid(id, 0);
672 687 __clear_bit(id, slow_work_ids);
673 688 spin_unlock_irq(&slow_work_queue_lock);
674 689  
... ... @@ -722,6 +737,9 @@
722 737 static const struct slow_work_ops slow_work_new_thread_ops = {
723 738 .owner = THIS_MODULE,
724 739 .execute = slow_work_new_thread_execute,
  740 +#ifdef CONFIG_SLOW_WORK_PROC
  741 + .desc = slow_work_new_thread_desc,
  742 +#endif
725 743 };
726 744  
727 745 /*
... ... @@ -948,6 +966,10 @@
948 966 #ifdef CONFIG_SYSCTL
949 967 if (slow_work_max_max_threads < nr_cpus * 2)
950 968 slow_work_max_max_threads = nr_cpus * 2;
  969 +#endif
  970 +#ifdef CONFIG_SLOW_WORK_PROC
  971 + proc_create("slow_work_rq", S_IFREG | 0400, NULL,
  972 + &slow_work_runqueue_fops);
951 973 #endif
952 974 return 0;
953 975 }
  1 +/* Slow work private definitions
  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 +#define SLOW_WORK_CULL_TIMEOUT (5 * HZ) /* cull threads 5s after running out of
  13 + * things to do */
  14 +#define SLOW_WORK_OOM_TIMEOUT (5 * HZ) /* can't start new threads for 5s after
  15 + * OOM */
  16 +
  17 +#define SLOW_WORK_THREAD_LIMIT 255 /* abs maximum number of slow-work threads */
  18 +
  19 +/*
  20 + * slow-work.c
  21 + */
  22 +#ifdef CONFIG_SLOW_WORK_PROC
  23 +extern struct slow_work *slow_work_execs[];
  24 +extern pid_t slow_work_pids[];
  25 +extern rwlock_t slow_work_execs_lock;
  26 +#endif
  27 +
  28 +extern struct list_head slow_work_queue;
  29 +extern struct list_head vslow_work_queue;
  30 +extern spinlock_t slow_work_queue_lock;
  31 +
  32 +/*
  33 + * slow-work-proc.c
  34 + */
  35 +#ifdef CONFIG_SLOW_WORK_PROC
  36 +extern const struct file_operations slow_work_runqueue_fops;
  37 +
  38 +extern void slow_work_new_thread_desc(struct slow_work *, struct seq_file *);
  39 +#endif
  40 +
  41 +/*
  42 + * Helper functions
  43 + */
  44 +static inline void slow_work_set_thread_pid(int id, pid_t pid)
  45 +{
  46 +#ifdef CONFIG_SLOW_WORK_PROC
  47 + slow_work_pids[id] = pid;
  48 +#endif
  49 +}
  50 +
  51 +static inline void slow_work_mark_time(struct slow_work *work)
  52 +{
  53 +#ifdef CONFIG_SLOW_WORK_PROC
  54 + work->mark = CURRENT_TIME;
  55 +#endif
  56 +}
  57 +
  58 +static inline void slow_work_begin_exec(int id, struct slow_work *work)
  59 +{
  60 +#ifdef CONFIG_SLOW_WORK_PROC
  61 + slow_work_execs[id] = work;
  62 +#endif
  63 +}
  64 +
  65 +static inline void slow_work_end_exec(int id, struct slow_work *work)
  66 +{
  67 +#ifdef CONFIG_SLOW_WORK_PROC
  68 + write_lock(&slow_work_execs_lock);
  69 + slow_work_execs[id] = NULL;
  70 + write_unlock(&slow_work_execs_lock);
  71 +#endif
  72 +}