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
@@ -303,6 +303,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,
@@ -347,7 +361,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];
 
 		/*
@@ -360,7 +373,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,
 				     housekeeping_cpumask(HK_FLAG_KTHREAD));
 	}
@@ -570,6 +586,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;
@@ -589,6 +606,7 @@ int kthreadd(void *unused)
 	ignore_signals(tsk);
 	set_cpus_allowed_ptr(tsk, housekeeping_cpumask(HK_FLAG_KTHREAD));
 	set_mems_allowed(node_states[N_MEMORY]);
+	kthread_set_sched_params(current);
 
 	current->flags |= PF_NOFREEZE;
 	cgroup_init_kthreadd();
@@ -1255,3 +1273,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
@@ -50,6 +50,7 @@
 #include <linux/uaccess.h>
 #include <linux/sched/isolation.h>
 #include <linux/nmi.h>
+#include <uapi/linux/sched/types.h>
 
 #include "workqueue_internal.h"
 
@@ -1828,6 +1829,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
@@ -1941,6 +1951,7 @@ static struct worker *create_worker(stru
 	raw_spin_lock_irq(&pool->lock);
 	worker->pool->nr_workers++;
 	worker_enter_idle(worker);
+	kworker_set_sched_params(worker->task);
 	wake_up_process(worker->task);
 	raw_spin_unlock_irq(&pool->lock);
 
@@ -4219,6 +4230,7 @@ static int init_rescuer(struct workqueue
 
 	wq->rescuer = rescuer;
 	kthread_bind_mask(rescuer->task, cpu_possible_mask);
+	kworker_set_sched_params(rescuer->task);
 	wake_up_process(rescuer->task);
 
 	return 0;
@@ -6033,3 +6045,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);