For this POC, this (ab)uses the "nice" attribute. It's of course not exactly pretty, but it avoids the problem of "what to show in the xyz file when using SCHED_NORMAL, and what to show in the nice file when using SCHED_RR/SCHED_FIFO". It's backwards-compatible, in that a bare integer is interpreted as a nice value, while an integer prefixed by "fifo:" or "rr:" chooses that RT scheduling policy with the associated value as the priority. The show method of course reflects what the store method accepts. Signed-off-by: Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx> --- kernel/workqueue.c | 54 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 7 deletions(-) diff --git a/kernel/workqueue.c b/kernel/workqueue.c index 9eb2ff7bcc04..a97f1aff809e 100644 --- a/kernel/workqueue.c +++ b/kernel/workqueue.c @@ -5538,13 +5538,34 @@ static ssize_t wq_nice_show(struct device *dev, struct device_attribute *attr, char *buf) { struct workqueue_struct *wq = dev_to_wq(dev); - int written; + struct workqueue_attrs *wqattrs; + const char *pfx; + int val; mutex_lock(&wq->mutex); - written = scnprintf(buf, PAGE_SIZE, "%d\n", wq->unbound_attrs->nice); + wqattrs = wq->unbound_attrs; + switch (wqattrs->policy) { + case SCHED_NORMAL: + pfx = ""; + val = wqattrs->nice; + break; + case SCHED_FIFO: + pfx = "fifo:"; + val = wqattrs->priority; + break; + case SCHED_RR: + pfx = "rr:"; + val = wqattrs->priority; + break; + default: + /* Shouldn't happen. */ + pfx = NULL; + } mutex_unlock(&wq->mutex); - return written; + if (!pfx) + return -EIO; + return scnprintf(buf, PAGE_SIZE, "%s%d\n", pfx, val); } /* prepare workqueue_attrs for sysfs store operations */ @@ -5568,6 +5589,24 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr, struct workqueue_struct *wq = dev_to_wq(dev); struct workqueue_attrs *attrs; int ret = -ENOMEM; + int policy, val; + + if (sscanf(buf, "fifo:%d", &val) == 1) + policy = SCHED_FIFO; + else if (sscanf(buf, "rr:%d", &val) == 1) + policy = SCHED_RR; + else if (sscanf(buf, "%d", &val) == 1) + policy = SCHED_NORMAL; + else + return -EINVAL; + + if (policy == SCHED_NORMAL) { + if (val < MIN_NICE || val > MAX_NICE) + return -EINVAL; + } else { + if (val <= 0 || val >= MAX_RT_PRIO) + return -EINVAL; + } apply_wqattrs_lock(); @@ -5575,11 +5614,12 @@ static ssize_t wq_nice_store(struct device *dev, struct device_attribute *attr, if (!attrs) goto out_unlock; - if (sscanf(buf, "%d", &attrs->nice) == 1 && - attrs->nice >= MIN_NICE && attrs->nice <= MAX_NICE) - ret = apply_workqueue_attrs_locked(wq, attrs); + attrs->policy = policy; + if (policy == SCHED_NORMAL) + attrs->nice = val; else - ret = -EINVAL; + attrs->priority = val; + ret = apply_workqueue_attrs_locked(wq, attrs); out_unlock: apply_wqattrs_unlock(); -- 2.31.1