Blob Blame History Raw
Subject: sched: Provide realtime priority kthread and workqueue boot options
From: Mike Galbraith <mgalbraith@suse.de>
Date: Tue Oct  8 06:27:03 CEST 2013
Patch-mainline: Never, RT specific
References: SLE Realtime Extension

Nasty hack to allow users to abuse realtime without starving the kernel,
and reaping the consequences thereof.

Boot box nortsched rtkthreads=N and optionally rtworkqueues=N+1, and the
user can slam a box into the saturation wall without starving the kernel
IFF he restricts userspace to priority < N.

Signed-off-by: Mike Galbraith <mgalbraith@suse.de>
---
 kernel/kthread.c   |   36 ++++++++++++++++++++++++++++++++++--
 kernel/workqueue.c |   26 ++++++++++++++++++++++++++
 2 files changed, 60 insertions(+), 2 deletions(-)

--- a/kernel/kthread.c
+++ b/kernel/kthread.c
@@ -273,6 +273,20 @@ static void create_kthread(struct kthrea
 	}
 }
 
+static struct sched_param fifo_param, normal_param;
+
+static void kthread_set_sched_params(struct task_struct *kthread)
+{
+	if (!fifo_param.sched_priority)
+		return;
+	sched_setscheduler_nocheck(kthread, SCHED_FIFO, &fifo_param);
+}
+
+static void kthread_clr_sched_params(struct task_struct *kthread)
+{
+	sched_setscheduler_nocheck(kthread, SCHED_NORMAL, &normal_param);
+}
+
 static __printf(4, 0)
 struct task_struct *__kthread_create_on_node(int (*threadfn)(void *data),
 						    void *data, int node,
@@ -317,7 +331,6 @@ struct task_struct *__kthread_create_on_
 	}
 	task = create->result;
 	if (!IS_ERR(task)) {
-		static const struct sched_param param = { .sched_priority = 0 };
 		char name[TASK_COMM_LEN];
 
 		/*
@@ -330,7 +343,10 @@ struct task_struct *__kthread_create_on_
 		 * root may have changed our (kthreadd's) priority or CPU mask.
 		 * The kernel thread should not inherit these properties.
 		 */
-		sched_setscheduler_nocheck(task, SCHED_NORMAL, &param);
+		if (!fifo_param.sched_priority)
+			kthread_clr_sched_params(task);
+		else
+			kthread_set_sched_params(task);
 		set_cpus_allowed_ptr(task, cpu_all_mask);
 	}
 	kfree(create);
@@ -533,6 +549,7 @@ int kthread_stop(struct task_struct *k)
 	kthread = to_kthread(k);
 	set_bit(KTHREAD_SHOULD_STOP, &kthread->flags);
 	kthread_unpark(k);
+	kthread_clr_sched_params(k);
 	wake_up_process(k);
 	wait_for_completion(&kthread->exited);
 	ret = k->exit_code;
@@ -552,6 +569,7 @@ int kthreadd(void *unused)
 	ignore_signals(tsk);
 	set_cpus_allowed_ptr(tsk, cpu_all_mask);
 	set_mems_allowed(node_states[N_MEMORY]);
+	kthread_set_sched_params(current);
 
 	current->flags |= PF_NOFREEZE;
 	cgroup_init_kthreadd();
@@ -1218,3 +1236,17 @@ struct cgroup_subsys_state *kthread_blkc
 }
 EXPORT_SYMBOL(kthread_blkcg);
 #endif
+
+static int __init setup_rtkthreads(char *str)
+{
+	int prio;
+
+	if (kstrtoint(str, 0, &prio) || prio < 1 || prio > 99) {
+		prio = 0;
+		pr_warn("Unable to set kthread default priority\n");
+	}
+	fifo_param.sched_priority = prio;
+
+        return 1;
+}
+__setup("rtkthreads=", setup_rtkthreads);
--- a/kernel/workqueue.c
+++ b/kernel/workqueue.c
@@ -51,6 +51,7 @@
 #include <linux/nmi.h>
 #include <linux/locallock.h>
 #include <linux/delay.h>
+#include <uapi/linux/sched/types.h>
 
 #include "workqueue_internal.h"
 
@@ -1754,6 +1755,15 @@ static struct worker *alloc_worker(int n
 	return worker;
 }
 
+static struct sched_param fifo_param;
+
+static void kworker_set_sched_params(struct task_struct *worker)
+{
+	if (!fifo_param.sched_priority)
+		return;
+	sched_setscheduler_nocheck(worker, SCHED_FIFO, &fifo_param);
+}
+
 /**
  * worker_attach_to_pool() - attach a worker to a pool
  * @worker: worker to be attached
@@ -1865,6 +1875,7 @@ static struct worker *create_worker(stru
 	spin_lock_irq(&pool->lock);
 	worker->pool->nr_workers++;
 	worker_enter_idle(worker);
+	kworker_set_sched_params(worker->task);
 	wake_up_process(worker->task);
 	spin_unlock_irq(&pool->lock);
 
@@ -4102,6 +4113,7 @@ struct workqueue_struct *__alloc_workque
 
 		wq->rescuer = rescuer;
 		kthread_bind_mask(rescuer->task, cpu_possible_mask);
+		kworker_set_sched_params(rescuer->task);
 		wake_up_process(rescuer->task);
 	}
 
@@ -5783,3 +5795,17 @@ int __init workqueue_init(void)
 
 	return 0;
 }
+
+static int __init setup_rtworkqueues(char *str)
+{
+	int prio;
+
+	if (kstrtoint(str, 0, &prio) || prio < 1 || prio > 99) {
+		prio = 0;
+		pr_warn("Unable to set kworker default priority\n");
+	}
+	fifo_param.sched_priority = prio;
+
+        return 1;
+}
+__setup("rtworkqueues=", setup_rtworkqueues);