From: Tejun Heo <tj@kernel.org>
To: Tejun Heo <tj@kernel.org>
Cc: torvalds@linux-foundation.org, mingo@elte.hu,
peterz@infradead.org, awalls@radix.net,
linux-kernel@vger.kernel.org, jeff@garzik.org,
akpm@linux-foundation.org, jens.axboe@oracle.com,
rusty@rustcorp.com.au, cl@linux-foundation.org,
dhowells@redhat.com, arjan@linux.intel.com, avi@redhat.com,
johannes@sipsolutions.net, andi@firstfloor.org,
Oleg Nesterov <oleg@redhat.com>,
Anton Blanchard <anton@samba.org>
Subject: [PATCH UPDATED 34/43] workqueue: implement DEBUGFS/workqueue
Date: Sun, 28 Feb 2010 16:13:03 +0900 [thread overview]
Message-ID: <4B8A177F.5030001@kernel.org> (raw)
In-Reply-To: <1267187000-18791-35-git-send-email-tj@kernel.org>
Implement DEBUGFS/workqueue which lists all workers and works for
debugging. Workqueues can also have ->show_work() callback which
describes a pending or running work in custom way. If ->show_work()
is missing or returns %false, wchan is printed.
# cat /sys/kernel/debug/workqueue
CPU ID PID WORK ADDR WORKQUEUE TIME DESC
==== ==== ===== ================ ============ ===== ============================
0 0 15 ffffffffa0004708 test-wq-04 1 s test_work_fn+0x469/0x690 [test_wq]
0 2 4146 <IDLE> 0us
0 1 21 <IDLE> 4 s
0 DELA ffffffffa00047b0 test-wq-04 1 s test work 2
1 1 418 <IDLE> 780ms
1 0 16 <IDLE> 40 s
1 2 443 <IDLE> 40 s
Workqueue debugfs support is suggested by David Howells and
implementation mostly mimics that of slow-work.
* Anton Blanchard spotted that ITER_* constants are overflowing w/
high cpu configuration. This was caused by using
powerup_power_of_two() where order_base_2() should have been used.
Fixed.
Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: David Howells <dhowells@redhat.com>
Cc: Anton Blanchard <anton@samba.org>
---
Silly bug which caused bit positions to overflow with larger NR_CPUS
fixed. The git tree and patchset tarball are updated accordingly.
The new commit is ad66f6442f165fccf3b17f0fb0434272a6286f31.
git://git.kernel.org/pub/scm/linux/kernel/git/tj/wq.git review-cmwq
http://master.kernel.org/~tj/patches/review-cmwq.tar.gz
Thanks.
include/linux/workqueue.h | 12 ++
kernel/workqueue.c | 369 ++++++++++++++++++++++++++++++++++++++++++++-
lib/Kconfig.debug | 7 +
3 files changed, 384 insertions(+), 4 deletions(-)
diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index e8c3410..850942a 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -17,6 +17,10 @@ struct workqueue_struct;
struct work_struct;
typedef void (*work_func_t)(struct work_struct *work);
+struct seq_file;
+typedef bool (*show_work_func_t)(struct seq_file *m, struct work_struct *work,
+ bool running);
+
/*
* The first word is the work queue pointer and the flags rolled into
* one
@@ -70,6 +74,9 @@ struct work_struct {
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
+#ifdef CONFIG_WORKQUEUE_DEBUGFS
+ unsigned long timestamp; /* timestamp for debugfs */
+#endif
};
#define WORK_DATA_INIT() ATOMIC_LONG_INIT(WORK_STRUCT_NO_CPU)
@@ -282,6 +289,11 @@ __create_workqueue_key(const char *name, unsigned int flags, int max_active,
#define create_singlethread_workqueue(name) \
__create_workqueue((name), WQ_SINGLE_CPU | WQ_RESCUER, 1)
+#ifdef CONFIG_WORKQUEUE_DEBUGFS
+extern void workqueue_set_show_work(struct workqueue_struct *wq,
+ show_work_func_t show);
+#endif
+
extern void destroy_workqueue(struct workqueue_struct *wq);
extern int queue_work(struct workqueue_struct *wq, struct work_struct *work);
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 7264ae7..c4cb082 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -117,7 +117,7 @@ struct worker {
struct list_head scheduled; /* L: scheduled works */
struct task_struct *task; /* I: worker task */
struct global_cwq *gcwq; /* I: the associated gcwq */
- unsigned long last_active; /* L: last active timestamp */
+ unsigned long timestamp; /* L: last active timestamp */
/* 64 bytes boundary on 64bit, 32 on 32bit */
struct sched_notifier sched_notifier; /* I: scheduler notifier */
unsigned int flags; /* ?: flags */
@@ -152,6 +152,9 @@ struct global_cwq {
unsigned int trustee_state; /* L: trustee state */
wait_queue_head_t trustee_wait; /* trustee wait */
struct worker *first_idle; /* L: first idle worker */
+#ifdef CONFIG_WORKQUEUE_DEBUGFS
+ struct worker *manager; /* L: the current manager */
+#endif
} ____cacheline_aligned_in_smp;
/*
@@ -207,6 +210,9 @@ struct workqueue_struct {
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
+#ifdef CONFIG_WORKQUEUE_DEBUGFS
+ show_work_func_t show_work; /* I: show work to debugfs */
+#endif
};
struct workqueue_struct *system_wq __read_mostly;
@@ -330,6 +336,27 @@ static inline void debug_work_activate(struct work_struct *work) { }
static inline void debug_work_deactivate(struct work_struct *work) { }
#endif
+#ifdef CONFIG_WORKQUEUE_DEBUGFS
+static void work_set_queued_at(struct work_struct *work)
+{
+ work->timestamp = jiffies;
+}
+
+static void worker_set_started_at(struct worker *worker)
+{
+ worker->timestamp = jiffies;
+}
+
+static void gcwq_set_manager(struct global_cwq *gcwq, struct worker *worker)
+{
+ gcwq->manager = worker;
+}
+#else
+static void work_set_queued_at(struct work_struct *work) { }
+static void worker_set_started_at(struct worker *worker) { }
+static void gcwq_set_manager(struct global_cwq *gcwq, struct worker *worker) { }
+#endif
+
/* Serializes the accesses to the list of workqueues. */
static DEFINE_SPINLOCK(workqueue_lock);
static LIST_HEAD(workqueues);
@@ -692,6 +719,8 @@ static void insert_work(struct cpu_workqueue_struct *cwq,
{
struct global_cwq *gcwq = cwq->gcwq;
+ work_set_queued_at(work);
+
/* we own @work, set data and link */
set_work_cwq(work, cwq, extra_flags);
@@ -971,7 +1000,7 @@ static void worker_enter_idle(struct worker *worker)
worker->flags |= WORKER_IDLE;
gcwq->nr_idle++;
- worker->last_active = jiffies;
+ worker->timestamp = jiffies;
/* idle_list is LIFO */
list_add(&worker->entry, &gcwq->idle_list);
@@ -1144,7 +1173,7 @@ static void idle_worker_timeout(unsigned long __gcwq)
/* idle_list is kept in LIFO order, check the last one */
worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
- expires = worker->last_active + IDLE_WORKER_TIMEOUT;
+ expires = worker->timestamp + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires))
mod_timer(&gcwq->idle_timer, expires);
@@ -1282,7 +1311,7 @@ static bool maybe_destroy_workers(struct global_cwq *gcwq)
unsigned long expires;
worker = list_entry(gcwq->idle_list.prev, struct worker, entry);
- expires = worker->last_active + IDLE_WORKER_TIMEOUT;
+ expires = worker->timestamp + IDLE_WORKER_TIMEOUT;
if (time_before(jiffies, expires)) {
mod_timer(&gcwq->idle_timer, expires);
@@ -1326,6 +1355,7 @@ static bool manage_workers(struct worker *worker)
gcwq->flags &= ~GCWQ_MANAGE_WORKERS;
gcwq->flags |= GCWQ_MANAGING_WORKERS;
+ gcwq_set_manager(gcwq, worker);
/*
* Destroy and then create so that may_start_working() is true
@@ -1335,6 +1365,7 @@ static bool manage_workers(struct worker *worker)
ret |= maybe_create_worker(gcwq);
gcwq->flags &= ~GCWQ_MANAGING_WORKERS;
+ gcwq_set_manager(gcwq, NULL);
/*
* The trustee might be waiting to take over the manager
@@ -1500,6 +1531,8 @@ static void process_one_work(struct worker *worker, struct work_struct *work)
set_work_cpu(work, gcwq->cpu);
list_del_init(&work->entry);
+ worker_set_started_at(worker);
+
spin_unlock_irq(&gcwq->lock);
work_clear_pending(work);
@@ -3131,6 +3164,334 @@ out_unlock:
}
#endif /* CONFIG_FREEZER */
+#ifdef CONFIG_WORKQUEUE_DEBUGFS
+
+#include <linux/seq_file.h>
+#include <linux/log2.h>
+#include <linux/debugfs.h>
+
+/**
+ * workqueue_set_show_work - set show_work callback for a workqueue
+ * @wq: workqueue of interest
+ * @show: show_work callback
+ *
+ * Set show_work callback of @wq to @show. This is used by workqueue
+ * debugfs support to allow workqueue users to describe the work with
+ * specific details.
+ *
+ * bool (*@show)(struct seq_file *m, struct work_struct *work, bool running);
+ *
+ * It should print to @m without new line. If @running is set, @show
+ * is responsible for ensuring @work is still accessible. %true
+ * return suppresses wchan printout.
+ */
+void workqueue_set_show_work(struct workqueue_struct *wq, show_work_func_t show)
+{
+ wq->show_work = show;
+}
+EXPORT_SYMBOL_GPL(workqueue_set_show_work);
+
+enum {
+ ITER_TYPE_MANAGER = 0,
+ ITER_TYPE_BUSY_WORKER,
+ ITER_TYPE_IDLE_WORKER,
+ ITER_TYPE_PENDING_WORK,
+ ITER_TYPE_DELAYED_WORK,
+ ITER_NR_TYPES,
+
+ /* iter: sign [started bit] [cpu bits] [type bits] [idx bits] */
+ ITER_CPU_BITS = order_base_2(NR_CPUS),
+ ITER_CPU_MASK = ((loff_t)1 << ITER_CPU_BITS) - 1,
+ ITER_TYPE_BITS = order_base_2(ITER_NR_TYPES),
+ ITER_TYPE_MASK = ((loff_t)1 << ITER_TYPE_BITS) - 1,
+
+ ITER_BITS = BITS_PER_BYTE * sizeof(loff_t) - 1,
+ ITER_STARTED_BIT = ITER_BITS - 1,
+ ITER_CPU_SHIFT = ITER_STARTED_BIT - ITER_CPU_BITS,
+ ITER_TYPE_SHIFT = ITER_CPU_SHIFT - ITER_TYPE_BITS,
+
+ ITER_IDX_MASK = ((loff_t)1 << ITER_TYPE_SHIFT) - 1,
+};
+
+struct wq_debugfs_token {
+ struct global_cwq *gcwq;
+ struct worker *worker;
+ struct work_struct *work;
+ bool work_delayed;
+};
+
+static void wq_debugfs_decode_pos(loff_t pos, unsigned int *cpup, int *typep,
+ int *idxp)
+{
+ *cpup = (pos >> ITER_CPU_SHIFT) & ITER_CPU_MASK;
+ *typep = (pos >> ITER_TYPE_SHIFT) & ITER_TYPE_MASK;
+ *idxp = pos & ITER_IDX_MASK;
+}
+
+/* try to dereference @pos and set @tok accordingly, %true if successful */
+static bool wq_debugfs_deref_pos(loff_t pos, struct wq_debugfs_token *tok)
+{
+ int type, idx, i;
+ unsigned int cpu;
+ struct global_cwq *gcwq;
+ struct worker *worker;
+ struct work_struct *work;
+ struct hlist_node *hnode;
+ struct workqueue_struct *wq;
+ struct cpu_workqueue_struct *cwq;
+
+ wq_debugfs_decode_pos(pos, &cpu, &type, &idx);
+
+ /* make sure the right gcwq is locked and init @tok */
+ gcwq = get_gcwq(cpu);
+ if (tok->gcwq != gcwq) {
+ if (tok->gcwq)
+ spin_unlock_irq(&tok->gcwq->lock);
+ if (gcwq)
+ spin_lock_irq(&gcwq->lock);
+ }
+ memset(tok, 0, sizeof(*tok));
+ tok->gcwq = gcwq;
+
+ /* dereference index@type and record it in @tok */
+ switch (type) {
+ case ITER_TYPE_MANAGER:
+ if (!idx)
+ tok->worker = gcwq->manager;
+ return tok->worker;
+
+ case ITER_TYPE_BUSY_WORKER:
+ if (idx < gcwq->nr_workers - gcwq->nr_idle)
+ for_each_busy_worker(worker, i, hnode, gcwq)
+ if (!idx--) {
+ tok->worker = worker;
+ return true;
+ }
+ break;
+
+ case ITER_TYPE_IDLE_WORKER:
+ if (idx < gcwq->nr_idle)
+ list_for_each_entry(worker, &gcwq->idle_list, entry)
+ if (!idx--) {
+ tok->worker = worker;
+ return true;
+ }
+ break;
+
+ case ITER_TYPE_PENDING_WORK:
+ list_for_each_entry(work, &gcwq->worklist, entry)
+ if (!idx--) {
+ tok->work = work;
+ return true;
+ }
+ break;
+
+ case ITER_TYPE_DELAYED_WORK:
+ list_for_each_entry(wq, &workqueues, list) {
+ cwq = get_cwq(gcwq->cpu, wq);
+ list_for_each_entry(work, &cwq->delayed_works, entry)
+ if (!idx--) {
+ tok->work = work;
+ tok->work_delayed = true;
+ return true;
+ }
+ }
+ break;
+ }
+ return false;
+}
+
+static bool wq_debugfs_next_pos(loff_t *ppos, bool next_type)
+{
+ int type, idx;
+ unsigned int cpu;
+
+ wq_debugfs_decode_pos(*ppos, &cpu, &type, &idx);
+
+ if (next_type) {
+ /* proceed to the next type */
+ if (++type >= ITER_NR_TYPES) {
+ /* oops, was the last type, to the next cpu */
+ cpu = cpumask_next(cpu, cpu_possible_mask);
+ if (cpu >= nr_cpu_ids)
+ return false;
+ type = ITER_TYPE_MANAGER;
+ }
+ idx = 0;
+ } else /* bump up the index */
+ idx++;
+
+ *ppos = ((loff_t)1 << ITER_STARTED_BIT) |
+ ((loff_t)cpu << ITER_CPU_SHIFT) |
+ ((loff_t)type << ITER_TYPE_SHIFT) | idx;
+ return true;
+}
+
+static void wq_debugfs_free_tok(struct wq_debugfs_token *tok)
+{
+ if (tok && tok->gcwq)
+ spin_unlock_irq(&tok->gcwq->lock);
+ kfree(tok);
+}
+
+static void *wq_debugfs_start(struct seq_file *m, loff_t *ppos)
+{
+ struct wq_debugfs_token *tok;
+
+ if (*ppos == 0) {
+ seq_puts(m, "CPU ID PID WORK ADDR WORKQUEUE TIME DESC\n");
+ seq_puts(m, "==== ==== ===== ================ ============ ===== ============================\n");
+ *ppos = (loff_t)1 << ITER_STARTED_BIT |
+ (loff_t)cpumask_first(cpu_possible_mask) << ITER_CPU_BITS;
+ }
+
+ tok = kzalloc(sizeof(*tok), GFP_KERNEL);
+ if (!tok)
+ return ERR_PTR(-ENOMEM);
+
+ spin_lock(&workqueue_lock);
+
+ while (!wq_debugfs_deref_pos(*ppos, tok)) {
+ if (!wq_debugfs_next_pos(ppos, true)) {
+ wq_debugfs_free_tok(tok);
+ return NULL;
+ }
+ }
+ return tok;
+}
+
+static void *wq_debugfs_next(struct seq_file *m, void *p, loff_t *ppos)
+{
+ struct wq_debugfs_token *tok = p;
+
+ wq_debugfs_next_pos(ppos, false);
+
+ while (!wq_debugfs_deref_pos(*ppos, tok)) {
+ if (!wq_debugfs_next_pos(ppos, true)) {
+ wq_debugfs_free_tok(tok);
+ return NULL;
+ }
+ }
+ return tok;
+}
+
+static void wq_debugfs_stop(struct seq_file *m, void *p)
+{
+ wq_debugfs_free_tok(p);
+ spin_unlock(&workqueue_lock);
+}
+
+static void wq_debugfs_print_duration(struct seq_file *m,
+ unsigned long timestamp)
+{
+ const char *units[] = { "us", "ms", " s", " m", " h", " d" };
+ const int factors[] = { 1000, 1000, 60, 60, 24, 0 };
+ unsigned long v = jiffies_to_usecs(jiffies - timestamp);
+ int i;
+
+ for (i = 0; v > 999 && i < ARRAY_SIZE(units) - 1; i++)
+ v /= factors[i];
+
+ seq_printf(m, "%3lu%s ", v, units[i]);
+}
+
+static int wq_debugfs_show(struct seq_file *m, void *p)
+{
+ struct wq_debugfs_token *tok = p;
+ struct worker *worker = NULL;
+ struct global_cwq *gcwq;
+ struct work_struct *work;
+ struct workqueue_struct *wq;
+ const char *name;
+ unsigned long timestamp;
+ char id_buf[11] = "", pid_buf[11] = "", addr_buf[17] = "";
+ bool showed = false;
+
+ if (tok->work) {
+ work = tok->work;
+ gcwq = get_work_gcwq(work);
+ wq = get_work_cwq(work)->wq;
+ name = wq->name;
+ timestamp = work->timestamp;
+
+ if (tok->work_delayed)
+ strncpy(id_buf, "DELA", sizeof(id_buf));
+ else
+ strncpy(id_buf, "PEND", sizeof(id_buf));
+ } else {
+ worker = tok->worker;
+ gcwq = worker->gcwq;
+ work = worker->current_work;
+ timestamp = worker->timestamp;
+
+ snprintf(id_buf, sizeof(id_buf), "%4d", worker->id);
+ snprintf(pid_buf, sizeof(pid_buf), "%4d",
+ task_pid_nr(worker->task));
+
+ if (work) {
+ wq = worker->current_cwq->wq;
+ name = wq->name;
+ } else {
+ wq = NULL;
+ if (worker->gcwq->manager == worker)
+ name = "<MANAGER>";
+ else
+ name = "<IDLE>";
+ }
+ }
+
+ if (work)
+ snprintf(addr_buf, sizeof(addr_buf), "%16p", work);
+
+ seq_printf(m, "%4d %4s %5s %16s %-12s ",
+ gcwq->cpu, id_buf, pid_buf, addr_buf, name);
+
+ wq_debugfs_print_duration(m, timestamp);
+
+ if (wq && work && wq->show_work)
+ showed = wq->show_work(m, work, worker != NULL);
+ if (!showed && worker && work) {
+ char buf[KSYM_SYMBOL_LEN];
+
+ sprint_symbol(buf, get_wchan(worker->task));
+ seq_printf(m, "%s", buf);
+ }
+
+ seq_putc(m, '\n');
+
+ return 0;
+}
+
+static const struct seq_operations wq_debugfs_ops = {
+ .start = wq_debugfs_start,
+ .next = wq_debugfs_next,
+ .stop = wq_debugfs_stop,
+ .show = wq_debugfs_show,
+};
+
+static int wq_debugfs_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &wq_debugfs_ops);
+}
+
+static const struct file_operations wq_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = wq_debugfs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+static int __init init_workqueue_debugfs(void)
+{
+ debugfs_create_file("workqueue", S_IFREG | 0400, NULL, NULL,
+ &wq_debugfs_fops);
+ return 0;
+}
+late_initcall(init_workqueue_debugfs);
+
+#endif /* CONFIG_WORKQUEUE_DEBUGFS */
+
void __init init_workqueues(void)
{
unsigned int cpu;
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 25c3ed5..5e9c683 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1054,6 +1054,13 @@ config DMA_API_DEBUG
This option causes a performance degredation. Use only if you want
to debug device drivers. If unsure, say N.
+config WORKQUEUE_DEBUGFS
+ bool "Enable workqueue debugging info via debugfs"
+ depends on DEBUG_FS
+ help
+ Enable debug FS support for workqueue. Information about all the
+ current workers and works is available through <debugfs>/workqueue.
+
source "samples/Kconfig"
source "lib/Kconfig.kgdb"
--
1.6.4.2
next prev parent reply other threads:[~2010-02-28 7:03 UTC|newest]
Thread overview: 86+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-02-26 12:22 [PATCHSET] workqueue: concurrency managed workqueue, take#4 Tejun Heo
2010-02-26 12:22 ` [PATCH 01/43] sched: consult online mask instead of active in select_fallback_rq() Tejun Heo
2010-02-26 12:22 ` [PATCH 02/43] sched: rename preempt_notifiers to sched_notifiers and refactor implementation Tejun Heo
2010-02-26 12:22 ` [PATCH 03/43] sched: refactor try_to_wake_up() Tejun Heo
2010-02-26 12:22 ` [PATCH 04/43] sched: implement __set_cpus_allowed() Tejun Heo
2010-02-26 12:22 ` [PATCH 05/43] sched: make sched_notifiers unconditional Tejun Heo
2010-02-26 12:22 ` [PATCH 06/43] sched: add wakeup/sleep sched_notifiers and allow NULL notifier ops Tejun Heo
2010-02-26 12:22 ` [PATCH 07/43] sched: implement try_to_wake_up_local() Tejun Heo
2010-02-28 12:33 ` Oleg Nesterov
2010-03-01 14:22 ` Tejun Heo
2010-02-26 12:22 ` [PATCH 08/43] workqueue: change cancel_work_sync() to clear work->data Tejun Heo
2010-02-26 12:22 ` [PATCH 09/43] acpi: use queue_work_on() instead of binding workqueue worker to cpu0 Tejun Heo
2010-02-26 12:22 ` [PATCH 10/43] stop_machine: reimplement without using workqueue Tejun Heo
2010-02-28 14:11 ` Oleg Nesterov
2010-03-01 15:07 ` Tejun Heo
2010-03-01 15:37 ` Oleg Nesterov
2010-03-01 16:36 ` Tejun Heo
2010-03-01 16:50 ` Oleg Nesterov
2010-03-01 18:02 ` Tejun Heo
2010-02-28 14:34 ` Oleg Nesterov
2010-03-01 15:11 ` Tejun Heo
2010-03-01 15:41 ` Oleg Nesterov
2010-02-26 12:22 ` [PATCH 11/43] workqueue: misc/cosmetic updates Tejun Heo
2010-02-26 12:22 ` [PATCH 12/43] workqueue: merge feature parameters into flags Tejun Heo
2010-02-26 12:22 ` [PATCH 13/43] workqueue: define masks for work flags and conditionalize STATIC flags Tejun Heo
2010-02-26 12:22 ` [PATCH 14/43] workqueue: separate out process_one_work() Tejun Heo
2010-02-26 12:22 ` [PATCH 15/43] workqueue: temporarily disable workqueue tracing Tejun Heo
2010-02-26 12:22 ` [PATCH 16/43] workqueue: kill cpu_populated_map Tejun Heo
2010-02-28 16:00 ` Oleg Nesterov
2010-03-01 15:32 ` Tejun Heo
2010-03-01 15:50 ` Oleg Nesterov
2010-03-01 16:19 ` Tejun Heo
2010-02-26 12:22 ` [PATCH 17/43] workqueue: update cwq alignement Tejun Heo
2010-02-28 17:12 ` Oleg Nesterov
2010-03-01 16:40 ` Tejun Heo
2010-02-26 12:22 ` [PATCH 18/43] workqueue: reimplement workqueue flushing using color coded works Tejun Heo
2010-02-28 20:31 ` Oleg Nesterov
2010-03-01 17:33 ` Tejun Heo
2010-03-01 19:47 ` Oleg Nesterov
2010-02-26 12:22 ` [PATCH 19/43] workqueue: introduce worker Tejun Heo
2010-02-26 12:22 ` [PATCH 20/43] workqueue: reimplement work flushing using linked works Tejun Heo
2010-03-01 14:53 ` Oleg Nesterov
2010-03-01 18:00 ` Tejun Heo
2010-03-01 18:51 ` Oleg Nesterov
2010-02-26 12:22 ` [PATCH 21/43] workqueue: implement per-cwq active work limit Tejun Heo
2010-02-26 12:22 ` [PATCH 22/43] workqueue: reimplement workqueue freeze using max_active Tejun Heo
2010-02-26 12:23 ` [PATCH 23/43] workqueue: introduce global cwq and unify cwq locks Tejun Heo
2010-02-26 12:23 ` [PATCH 24/43] workqueue: implement worker states Tejun Heo
2010-02-26 12:23 ` [PATCH 25/43] workqueue: reimplement CPU hotplugging support using trustee Tejun Heo
2010-02-26 12:23 ` [PATCH 26/43] workqueue: make single thread workqueue shared worker pool friendly Tejun Heo
2010-02-26 12:23 ` [PATCH 27/43] workqueue: add find_worker_executing_work() and track current_cwq Tejun Heo
2010-02-26 12:23 ` [PATCH 28/43] workqueue: carry cpu number in work data once execution starts Tejun Heo
2010-02-28 7:08 ` [PATCH UPDATED " Tejun Heo
2010-02-26 12:23 ` [PATCH 29/43] workqueue: implement WQ_NON_REENTRANT Tejun Heo
2010-02-26 12:23 ` [PATCH 30/43] workqueue: use shared worklist and pool all workers per cpu Tejun Heo
2010-02-26 12:23 ` [PATCH 31/43] workqueue: implement concurrency managed dynamic worker pool Tejun Heo
2010-02-26 12:23 ` [PATCH 32/43] workqueue: increase max_active of keventd and kill current_is_keventd() Tejun Heo
2010-02-26 12:23 ` [PATCH 33/43] workqueue: add system_wq, system_long_wq and system_nrt_wq Tejun Heo
2010-02-26 12:23 ` [PATCH 34/43] workqueue: implement DEBUGFS/workqueue Tejun Heo
2010-02-28 7:13 ` Tejun Heo [this message]
2010-02-26 12:23 ` [PATCH 35/43] workqueue: implement several utility APIs Tejun Heo
2010-02-28 7:15 ` [PATCH UPDATED " Tejun Heo
2010-02-26 12:23 ` [PATCH 36/43] libata: take advantage of cmwq and remove concurrency limitations Tejun Heo
2010-02-26 12:23 ` [PATCH 37/43] async: use workqueue for worker pool Tejun Heo
2010-02-26 12:23 ` [PATCH 38/43] fscache: convert object to use workqueue instead of slow-work Tejun Heo
2010-02-26 12:23 ` [PATCH 39/43] fscache: convert operation " Tejun Heo
2010-02-26 12:23 ` [PATCH 40/43] fscache: drop references to slow-work Tejun Heo
2010-02-26 12:23 ` [PATCH 41/43] cifs: use workqueue instead of slow-work Tejun Heo
2010-02-28 7:09 ` [PATCH UPDATED " Tejun Heo
2010-02-26 12:23 ` [PATCH 42/43] gfs2: " Tejun Heo
2010-02-28 7:10 ` [PATCH UPDATED " Tejun Heo
2010-02-26 12:23 ` [PATCH 43/43] slow-work: kill it Tejun Heo
2010-02-27 22:52 ` [PATCH] workqueue: Fix build on PowerPC Anton Blanchard
2010-02-28 6:08 ` Tejun Heo
2010-02-28 1:00 ` [PATCH] workqueue: Fix a compile warning in work_busy Anton Blanchard
2010-02-28 6:18 ` Tejun Heo
2010-02-28 1:11 ` [PATCHSET] workqueue: concurrency managed workqueue, take#4 Anton Blanchard
2010-02-28 6:32 ` Tejun Heo
2010-03-10 14:52 ` David Howells
2010-03-12 5:03 ` Tejun Heo
2010-03-12 11:23 ` David Howells
2010-03-12 22:55 ` Tejun Heo
2010-03-16 14:38 ` David Howells
2010-03-16 16:03 ` Tejun Heo
2010-03-16 17:18 ` David Howells
2010-04-25 8:09 ` [PATCHSET UPDATED] " Tejun Heo
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4B8A177F.5030001@kernel.org \
--to=tj@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=andi@firstfloor.org \
--cc=anton@samba.org \
--cc=arjan@linux.intel.com \
--cc=avi@redhat.com \
--cc=awalls@radix.net \
--cc=cl@linux-foundation.org \
--cc=dhowells@redhat.com \
--cc=jeff@garzik.org \
--cc=jens.axboe@oracle.com \
--cc=johannes@sipsolutions.net \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=rusty@rustcorp.com.au \
--cc=torvalds@linux-foundation.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.