Subject: Re: [resend] vs2.2.0.x and scheduler getting stuck
From: "Grzegorz Nosek" <grzegorz.nosek@gmail.com>
Date: Sat, 17 May 2008 11:59:19 +0200
Sat, 17 May 2008 11:59:19 +0200
2008/5/17, Grzegorz Nosek <grzegorz.nosek@gmail.com>:
> I've been experiencing some weird hangs (boom and it's dead, no panic,
> not even a softlockup or lockdep warning).

(...)

> I think that the solution would be to get some feedback from
> vx_try_unhold about whether any progress can be made at all (e.g. if the
> hold_queue is empty, vx_try_unhold will never change anything and
> vx_try_skip will just keep updating rq->idle_time).

And here's a preliminary patch (compile-tested only) - attached,
unless gmail screws something up.

BTW, any chance of reviving the idea of git.linux-vserver.org?

Best regards,
 Grzegorz Nosek


commit b1c3a5c25d9b9301ab197a65247c3f495135fd60
Author: Grzegorz Nosek <root@localdomain.pl>
Date:   Sat May 17 10:56:19 2008 +0200

    Don't loop forever in scheduler

diff --git a/kernel/sched.c b/kernel/sched.c
index a111b42..218ccdf 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -3627,6 +3627,7 @@ asmlinkage void __sched schedule(void)
 	int cpu, idx, new_prio;
 	long *switch_count;
 	struct rq *rq;
+	int can_progress;
 
 	/*
 	 * Test if we are atomic.  Since do_exit() needs to call into
@@ -3695,12 +3696,17 @@ need_resched_nonpreemptible:
 	cpu = smp_processor_id();
 	vx_set_rq_time(rq, jiffies);
 try_unhold:
-	vx_try_unhold(rq, cpu);
+	can_progress = vx_try_unhold(rq, cpu);
 pick_next:
 
 	if (unlikely(!rq->nr_running)) {
-		/* can we skip idle time? */
-		if (vx_try_skip(rq, cpu))
+		/*
+		 * can we skip idle time?
+		 *
+		 * if there are no held tasks, trying to unhold one
+		 * will never succeed
+		 */
+		if (can_progress && vx_try_skip(rq, cpu))
 			goto try_unhold;
 
 		idle_balance(cpu, rq);
diff --git a/kernel/sched_hard.h b/kernel/sched_hard.h
index 0e95990..0710af5 100644
--- a/kernel/sched_hard.h
+++ b/kernel/sched_hard.h
@@ -171,16 +171,17 @@ int vx_need_resched(struct task_struct *p, int slice, int cpu)
 
 
 static inline
-void vx_try_unhold(struct rq *rq, int cpu)
+int vx_try_unhold(struct rq *rq, int cpu)
 {
 	struct vx_info *vxi = NULL;
 	struct list_head *l, *n;
 	int maxidle = HZ;
 	int minskip = 0;
+	int can_progress = 0;
 
 	/* nothing to do? what about pause? */
 	if (list_empty(&rq->hold_queue))
-		return;
+		return 0;
 
 	list_for_each_safe(l, n, &rq->hold_queue) {
 		int ret, delta_min[2];
@@ -205,6 +206,9 @@ void vx_try_unhold(struct rq *rq, int cpu)
 			&rq->norm_time, &rq->idle_time, delta_min);
 		vxm_tokens_recalc(sched_pc, rq, vxi, cpu);
 
+		/* a task will eventually be runnable, maybe even now */
+		can_progress = 1;
+
 		if (ret > 0) {
 			/* we found a runable context */
 			vx_unhold_task(p, rq);
@@ -216,6 +220,8 @@ void vx_try_unhold(struct rq *rq, int cpu)
 	vx_set_rq_max_idle(rq, maxidle);
 	vx_set_rq_min_skip(rq, minskip);
 	vxm_rq_max_min(rq, cpu);
+
+	return can_progress;
 }