[git pull] scheduler fixes

Ingo Molnar
2007-12-04T16:18:52Z

* Ingo Molnar <mingo@elte.hu> wrote:

> The problem is on SMP: if sched_rr_get_interval() gets a task from an
> otherwise idle runqueue, then rq->load.weight is 0. Normally
> sched_slice() is only used on a busy runqueue. So the correct fixup
> site is not in sched_slice() but in sys_sched_rr_get_interval() - i'm
> working on the right fix, i hope to be able to send a pull request in
> a few minutes.

the problem is on UP too - if there are no SCHED_OTHER tasks. I've
tested the fix and it solves the problem for various combinations of
crash.c. I've updated sched.git, please pull it from:

git://git.kernel.org/pub/scm/linux/kernel/git/mingo/linux-2.6-sched.git

It has another commit besides this fix. Thanks,

Ingo

------------------>

Ingo Molnar (2):
sched: fix crash in sys_sched_rr_get_interval()
sched: default to more agressive yield for SCHED_BATCH tasks

sched.c | 14 +++++++++-----
sched_fair.c | 7 ++++---
2 files changed, 13 insertions(+), 8 deletions(-)

diff --git a/kernel/sched.c b/kernel/sched.c
index 59ff6b1..b062856 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -4850,17 +4850,21 @@ long sys_sched_rr_get_interval(pid_t pid, struct timespec __user *interval)
if (retval)
goto out_unlock;

- if (p->policy == SCHED_FIFO)
- time_slice = 0;
- else if (p->policy == SCHED_RR)
+ /*
+ * Time slice is 0 for SCHED_FIFO tasks and for SCHED_OTHER
+ * tasks that are on an otherwise idle runqueue:
+ */
+ time_slice = 0;
+ if (p->policy == SCHED_RR) {
time_slice = DEF_TIMESLICE;
- else {
+ } else {
struct sched_entity *se = &p->se;
unsigned long flags;
struct rq *rq;

rq = task_rq_lock(p, &flags);
- time_slice = NS_TO_JIFFIES(sched_slice(cfs_rq_of(se), se));
+ if (rq->cfs.load.weight)
+ time_slice = NS_TO_JIFFIES(sched_slice(&rq->cfs, se));
task_rq_unlock(rq, &flags);
}
read_unlock(&tasklist_lock);
diff --git a/kernel/sched_fair.c b/kernel/sched_fair.c
index 37bb265..c33f0ce 100644
--- a/kernel/sched_fair.c
+++ b/kernel/sched_fair.c
@@ -799,8 +799,9 @@ static void dequeue_task_fair(struct rq *rq, struct task_struct *p, int sleep)
*/
static void yield_task_fair(struct rq *rq)
{
- struct cfs_rq *cfs_rq = task_cfs_rq(rq->curr);
- struct sched_entity *rightmost, *se = &rq->curr->se;
+ struct task_struct *curr = rq->curr;
+ struct cfs_rq *cfs_rq = task_cfs_rq(curr);
+ struct sched_entity *rightmost, *se = &curr->se;

/*
* Are we the only task in the tree?
@@ -808,7 +809,7 @@ static void yield_task_fair(struct rq *rq)
if (unlikely(cfs_rq->nr_running == 1))
return;

- if (likely(!sysctl_sched_compat_yield)) {
+ if (likely(!sysctl_sched_compat_yield) && curr->policy != SCHED_BATCH) {
__update_rq_clock(rq);
/*
* Update run-time statistics of the 'current'.