[RFC PATCH V4 2/5] workqueue: expose attrs for system workqueues

From: Wen Yang
Date: Thu Jan 25 2018 - 01:57:02 EST


Expose sched_attr for system workqueues, such as:
# cat /sys/devices/virtual/workqueue/system_percpu/sched_attr
policy=0 prio=0 nice=0
cat /sys/devices/virtual/workqueue/system_percpu_highpri/sched_attr
policy=0 prio=0 nice=-20

Signed-off-by: Wen Yang <wen.yang99@xxxxxxxxxx>
Signed-off-by: Jiang Biao <jiang.biao2@xxxxxxxxxx>
Signed-off-by: Tan Hu <tan.hu@xxxxxxxxxx>
Suggested-by: Tejun Heo <tj@xxxxxxxxxx>
Cc: Tejun Heo <tj@xxxxxxxxxx>
Cc: Lai Jiangshan <jiangshanlai@xxxxxxxxx>
Cc: kernel test robot <xiaolong.ye@xxxxxxxxx>
Cc: linux-kernel@xxxxxxxxxxxxxxx
---
include/linux/workqueue.h | 6 ++++++
kernel/workqueue.c | 50 +++++++++++++++++++++++++++++++++++++++++++++--
2 files changed, 54 insertions(+), 2 deletions(-)

diff --git a/include/linux/workqueue.h b/include/linux/workqueue.h
index 4a54ef9..9faaade 100644
--- a/include/linux/workqueue.h
+++ b/include/linux/workqueue.h
@@ -13,6 +13,7 @@
#include <linux/threads.h>
#include <linux/atomic.h>
#include <linux/cpumask.h>
+#include <uapi/linux/sched/types.h>

struct workqueue_struct;

@@ -132,6 +133,11 @@ struct workqueue_attrs {
int nice;

/**
+ * @sched_attr: kworker's scheduling parameters
+ */
+ struct sched_attr sched_attr;
+
+ /**
* @cpumask: allowed CPUs
*/
cpumask_var_t cpumask;
diff --git a/kernel/workqueue.c b/kernel/workqueue.c
index 67b68bb..993f225 100644
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -256,6 +256,7 @@ struct workqueue_struct {
int saved_max_active; /* WQ: saved pwq max_active */

struct workqueue_attrs *unbound_attrs; /* PW: only for unbound wqs */
+ struct workqueue_attrs *attrs;
struct pool_workqueue *dfl_pwq; /* PW: only for unbound wqs */

#ifdef CONFIG_SYSFS
@@ -1699,6 +1700,7 @@ static void worker_attach_to_pool(struct worker *worker,
* online CPUs. It'll be re-applied when any of the CPUs come up.
*/
set_cpus_allowed_ptr(worker->task, pool->attrs->cpumask);
+ sched_setattr(worker->task, &pool->attrs->sched_attr);

/*
* The pool->attach_mutex ensures %POOL_DISASSOCIATED remains
@@ -3166,10 +3168,20 @@ struct workqueue_attrs *alloc_workqueue_attrs(gfp_t gfp_mask)
return NULL;
}

+static void copy_sched_attr(struct sched_attr *to,
+ const struct sched_attr *from)
+{
+ to->sched_policy = from->sched_policy;
+ to->sched_priority = from->sched_priority;
+ to->sched_nice = from->sched_nice;
+ to->sched_flags = from->sched_flags;
+}
+
static void copy_workqueue_attrs(struct workqueue_attrs *to,
const struct workqueue_attrs *from)
{
to->nice = from->nice;
+ copy_sched_attr(&to->sched_attr, &from->sched_attr);
cpumask_copy(to->cpumask, from->cpumask);
/*
* Unlike hash and equality test, this function doesn't ignore
@@ -3250,7 +3262,7 @@ static void rcu_free_wq(struct rcu_head *rcu)
free_percpu(wq->cpu_pwqs);
else
free_workqueue_attrs(wq->unbound_attrs);
-
+ free_workqueue_attrs(wq->attrs);
kfree(wq->rescuer);
kfree(wq);
}
@@ -3979,6 +3991,10 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
goto err_free_wq;
}

+ wq->attrs = alloc_workqueue_attrs(GFP_KERNEL);
+ if (!wq->attrs)
+ goto err_free_wq;
+
va_start(args, lock_name);
vsnprintf(wq->name, sizeof(wq->name), fmt, args);
va_end(args);
@@ -3999,6 +4015,11 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,
lockdep_init_map(&wq->lockdep_map, lock_name, key, 0);
INIT_LIST_HEAD(&wq->list);

+ wq->attrs->sched_attr.sched_policy = SCHED_NORMAL;
+ wq->attrs->sched_attr.sched_priority = 0;
+ wq->attrs->sched_attr.sched_nice = wq->flags & WQ_HIGHPRI ?
+ HIGHPRI_NICE_LEVEL : 0;
+
if (alloc_and_link_pwqs(wq) < 0)
goto err_free_wq;

@@ -4049,6 +4070,7 @@ struct workqueue_struct *__alloc_workqueue_key(const char *fmt,

err_free_wq:
free_workqueue_attrs(wq->unbound_attrs);
+ free_workqueue_attrs(wq->attrs);
kfree(wq);
return NULL;
err_destroy:
@@ -5043,9 +5065,29 @@ static ssize_t max_active_store(struct device *dev,
}
static DEVICE_ATTR_RW(max_active);

+static ssize_t sched_attr_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ size_t written;
+ struct workqueue_struct *wq = dev_to_wq(dev);
+
+ mutex_lock(&wq->mutex);
+ written = scnprintf(buf, PAGE_SIZE,
+ "policy=%u prio=%u nice=%d\n",
+ wq->attrs->sched_attr.sched_policy,
+ wq->attrs->sched_attr.sched_priority,
+ wq->attrs->sched_attr.sched_nice);
+ mutex_unlock(&wq->mutex);
+
+ return written;
+}
+
+static DEVICE_ATTR_RO(sched_attr);
+
static struct attribute *wq_sysfs_attrs[] = {
&dev_attr_per_cpu.attr,
&dev_attr_max_active.attr,
+ &dev_attr_sched_attr.attr,
NULL,
};
ATTRIBUTE_GROUPS(wq_sysfs);
@@ -5254,7 +5296,11 @@ static int __init wq_sysfs_init(void)
if (err)
return err;

- return device_create_file(wq_subsys.dev_root, &wq_sysfs_cpumask_attr);
+ err = device_create_file(wq_subsys.dev_root, &wq_sysfs_cpumask_attr);
+ if (err)
+ return err;
+ return workqueue_sysfs_register(system_wq) ||
+ workqueue_sysfs_register(system_highpri_wq);
}
core_initcall(wq_sysfs_init);

--
1.8.3.1