--- arch/i386/kernel/ioport.c | 17 ++++++++++++++--- arch/x86_64/kernel/ioport.c | 12 ++++++++++-- drivers/block/loop.c | 5 ++++- include/linux/sched.h | 7 +++++++ kernel/Kconfig.preempt | 17 +++++++++++++++++ kernel/sched.c | 40 ++++++++++++++++++++++++++++++++++++++++ kernel/workqueue.c | 2 +- mm/oom_kill.c | 4 +++- 8 files changed, 96 insertions(+), 8 deletions(-) Index: linux/arch/i386/kernel/ioport.c =================================================================== --- linux.orig/arch/i386/kernel/ioport.c +++ linux/arch/i386/kernel/ioport.c @@ -64,9 +64,17 @@ asmlinkage long sys_ioperm(unsigned long if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) return -EINVAL; - if (turn_on && !capable(CAP_SYS_RAWIO)) - return -EPERM; - + if (turn_on) { + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; + /* + * Task will be accessing hardware IO ports, + * mark it as special with the scheduler too: + */ +#ifdef CONFIG_BOOST_PRIVILEGED_TASKS + sched_privileged_task(current); +#endif + } /* * If it's the first ioperm() call in this thread's lifetime, set the * IO bitmap up. ioperm() is much less timing critical than clone(), @@ -145,6 +153,9 @@ asmlinkage long sys_iopl(unsigned long u if (level > old) { if (!capable(CAP_SYS_RAWIO)) return -EPERM; +#ifdef CONFIG_BOOST_PRIVILEGED_TASKS + sched_privileged_task(current); +#endif } t->iopl = level << 12; regs->eflags = (regs->eflags & ~X86_EFLAGS_IOPL) | t->iopl; Index: linux/arch/x86_64/kernel/ioport.c =================================================================== --- linux.orig/arch/x86_64/kernel/ioport.c +++ linux/arch/x86_64/kernel/ioport.c @@ -41,8 +41,13 @@ asmlinkage long sys_ioperm(unsigned long if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) return -EINVAL; - if (turn_on && !capable(CAP_SYS_RAWIO)) - return -EPERM; + if (turn_on) { + if (!capable(CAP_SYS_RAWIO)) + return -EPERM; +#ifdef CONFIG_BOOST_PRIVILEGED_TASKS + sched_privileged_task(current); +#endif + } /* * If it's the first ioperm() call in this thread's lifetime, set the @@ -113,6 +118,9 @@ asmlinkage long sys_iopl(unsigned int le if (level > old) { if (!capable(CAP_SYS_RAWIO)) return -EPERM; +#ifdef CONFIG_BOOST_PRIVILEGED_TASKS + sched_privileged_task(current); +#endif } regs->eflags = (regs->eflags &~ X86_EFLAGS_IOPL) | (level << 12); return 0; Index: linux/drivers/block/loop.c =================================================================== --- linux.orig/drivers/block/loop.c +++ linux/drivers/block/loop.c @@ -577,7 +577,12 @@ static int loop_thread(void *data) struct loop_device *lo = data; struct bio *bio; set_user_nice(current, -20); + + /* + * The loop thread is important enough to be given a boost: + */ + sched_privileged_task(current); while (!kthread_should_stop() || lo->lo_bio) { Index: linux/include/linux/sched.h =================================================================== --- linux.orig/include/linux/sched.h +++ linux/include/linux/sched.h @@ -1336,6 +1336,13 @@ static inline int rt_mutex_getprio(struc #endif extern void set_user_nice(struct task_struct *p, long nice); +/* + * Task has special privileges, give it more CPU power: + */ +extern void sched_privileged_task(struct task_struct *p); + +extern int sysctl_sched_privileged_nice_level; + extern int task_prio(const struct task_struct *p); extern int task_nice(const struct task_struct *p); extern int can_nice(const struct task_struct *p, const int nice); Index: linux/kernel/Kconfig.preempt =================================================================== --- linux.orig/kernel/Kconfig.preempt +++ linux/kernel/Kconfig.preempt @@ -63,3 +63,20 @@ config PREEMPT_BKL Say Y here if you are building a kernel for a desktop system. Say N if you are unsure. +config BOOST_PRIVILEGED_TASKS + bool "Boost privileged tasks" + default y + help + This option instructs the kernel to guarantee more CPU time to + some privileged tasks (like X), which is useful if you want to have a + faster desktop even under high system load. + + This option works by automatically boosting task's priority via + renicing it. NOTE: CFS does not suffer from "overscheduling" + problems when some tasks are reniced, so if this is a + predominantly desktop box it makes sense to select this + option. + + Say Y here if you are building a kernel for a desktop system. + Say N if you want X to be treated as a normal task. + Index: linux/kernel/sched.c =================================================================== --- linux.orig/kernel/sched.c +++ linux/kernel/sched.c @@ -3608,6 +3608,53 @@ out_unlock: EXPORT_SYMBOL(set_user_nice); /* + * Nice level for privileged tasks. (can be set to 0 for this + * to be turned off) + */ +int sysctl_sched_privileged_nice_level __read_mostly = -10; + +static int __init privileged_nice_level_setup(char *str) +{ + sysctl_sched_privileged_nice_level = simple_strtol(str, NULL, 0); + return 1; +} +__setup("privileged_nice_level=", privileged_nice_level_setup); + +/* + * Tasks with special privileges call this and gain extra nice + * levels: + */ +void sched_privileged_task(struct task_struct *p) +{ + struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 }; + long new_nice = sysctl_sched_privileged_nice_level; + long old_nice = TASK_NICE(p); + + if (new_nice >= old_nice) + return; + /* + * Setting the sysctl to 0 turns off the boosting: + */ + if (unlikely(!new_nice)) + return; + + if (new_nice < -20) + new_nice = -20; + else if (new_nice > 19) + new_nice = 19; + + set_user_nice(p, new_nice); + + /* Set real-time policy */ + if (!task_has_rt_policy(p)) { + sched_setscheduler(p, SCHED_FIFO, ¶m); + p->ioprio = (IOPRIO_CLASS_RT << IOPRIO_CLASS_SHIFT) | 4; + } +} + +EXPORT_SYMBOL(sched_privileged_task); + +/* * can_nice - check if a task can reduce its nice value * @p: task * @nice: nice value Index: linux/kernel/workqueue.c =================================================================== --- linux.orig/kernel/workqueue.c +++ linux/kernel/workqueue.c @@ -285,7 +285,8 @@ static int worker_thread(void *__cwq) if (cwq->wq->freezeable) set_freezable(); set_user_nice(current, -5); + sched_privileged_task(current); for (;;) { prepare_to_wait(&cwq->more_work, &wait, TASK_INTERRUPTIBLE); Index: linux/mm/oom_kill.c =================================================================== --- linux.orig/mm/oom_kill.c +++ linux/mm/oom_kill.c @@ -295,7 +295,9 @@ static void __oom_kill_task(struct task_ * all the memory it needs. That way it should be able to * exit() and clear out its resources quickly... */ - p->time_slice = HZ; + if (p->policy == SCHED_NORMAL || p->policy == SCHED_BATCH) + sched_privileged_task(p); + set_tsk_thread_flag(p, TIF_MEMDIE); force_sig(SIGKILL, p); Index: linux/fs/jbd/journal.c =================================================================== --- linux.orig/fs/jbd/journal.c +++ linux/fs/jbd/journal.c @@ -131,6 +132,8 @@ static int kjournald(void *arg) printk(KERN_INFO "kjournald starting. Commit interval %ld seconds\n", journal->j_commit_interval / HZ); + sched_privileged_task(current); + /* * And now, wait forever for commit wakeup events. */