Re: [PATCH 2/3] workqueue: Add an API to create a singlethread workqueue attached to the current task's cgroup
From: Sridhar Samudrala <hidden>
Date: 2010-05-27 16:24:30
Also in:
kvm, lkml
On Thu, 2010-05-27 at 14:44 +0200, Oleg Nesterov wrote:
On 05/27, Michael S. Tsirkin wrote:quoted
On Tue, May 18, 2010 at 05:04:51PM -0700, Sridhar Samudrala wrote:quoted
Add a new kernel API to create a singlethread workqueue and attach it's task to current task's cgroup and cpumask. Signed-off-by: Sridhar Samudrala <redacted>Could someone familiar with workqueue code please comment on whether this patch is suitable for 2.6.35? It is needed to fix the case where vhost user might cause a kernel thread to consume more CPU than allowed by the cgroup. Should I merge it through the vhost tree? Ack for this?I don't understand the reasons for this patch, but this doesn't matter. I don't really see any need to change workqueue.c,quoted
quoted
+static struct task_struct *get_singlethread_wq_task(struct workqueue_struct *wq) +{ + return (per_cpu_ptr(wq->cpu_wq, singlethread_cpu))->thread; +}(Not sure this trivial static helper with the single caller makes sense, but see below)quoted
quoted
+/* Create a singlethread workqueue and attach it's task to the current task's + * cgroup and set it's cpumask to the current task's cpumask. + */ +struct workqueue_struct *create_singlethread_workqueue_in_current_cg(char *name) +{ + struct workqueue_struct *wq; + struct task_struct *task; + cpumask_var_t mask; + + wq = create_singlethread_workqueue(name); + if (!wq) + goto out; + + if (!alloc_cpumask_var(&mask, GFP_KERNEL)) + goto err; + + if (sched_getaffinity(current->pid, mask)) + goto err; + + task = get_singlethread_wq_task(wq); + if (sched_setaffinity(task->pid, mask)) + goto err; + + if (cgroup_attach_task_current_cg(task)) + goto err; +out: + return wq; +err: + destroy_workqueue(wq); + wq = NULL; + goto out; +}Instead, cgroup.c (or whoever needs this) can do struct move_struct { struct work_struct work; int ret; }; static void move_func(struct work_struct *work) { struct move_struct *move = container_of(...); if (cgroup_attach_task_current_cg(current))
We are trying to attach the task associated with workqueue to the current task's cgroup. So what we need is cgroup_attach_task_current_cg(wq->task); However there is no interface currently that exports the task associated with a workqueue. It is hidden in cpu_workqueue_struct and is only accessible within workqueue.c.
ret = -EANY;
}
static struct workqueue_struct *create_singlethread_workqueue_in_current_cg(char *name)
{
struct workqueue_struct *wq;
struct move_struct move = {
.work = __WORK_INITIALIZER(move_func);
};
wq = create_singlethread_workqueue(name);
if (!wq)
return NULL;
queue_work(&move.work);
flush_work(&move.work);
if (move.ret) {
destroy_workqueue(wq);
wq = NULL;
}
return wq;
}
Or. Just export wq_per_cpu() from workqueue.c (probably with a better name) and
use it like the patch does.This requires that struct cpu_workqueue_struct and struct workqueue_struct are made externally visible by moving them to kernel/workqueue.h. Instead what about adding the simple helper get_singlethread_wq_task() in workqueue.c and exporting it. I can add create_singlethread_workqueue_in_current_cg() to cgroup.c using this helper routine. Thanks Sridhar