aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrea Bastoni <bastoni@cs.unc.edu>2010-02-10 19:08:50 -0500
committerAndrea Bastoni <bastoni@cs.unc.edu>2010-02-10 19:08:50 -0500
commit851baec36d80e7ee279c69677b113428d20562c8 (patch)
treec54caa78e40fdcb7d446005e3f81fd9fd66e6159
parent7a5b2e2906fdc575bf7fc93f954419c5d54bb0a5 (diff)
Bugfix: PSN-EDF task_block flow-path may race with schedule()
The task block flow-path in PSN-EDF may race with schedule() (e.g., fast task release, hrtimer, etc.). As psnedf_task_block does not reset the pedf->scheduled field, the BUG_ON(pedf->scheduled != prev) condition in psnedf_schedule() fires. Setting pedf-> schedule to NULL in psnedf_task_block() is not enough as we may loose a rescheduling point (as we skip the check for new real-time tasks) We need therefore to trace the block event in the first rescheduling point. The BUG was first reported by Glenn: [ 46.986089] kernel BUG at litmus/sched_psn_edf.c:138! [ 46.986089] invalid opcode: 0000 [#1] 0P TtaEsEk_MmoPdTe( LISMP MUS_RT_T[AS K) o k46.986089] last sysfs file: /sys/devices/pci0000:00/0000:00:01.1/ide0/0.0/block/hda/size [ 46.986089] CPU 1 . [ 4] Wai[ ti ng 4f6.986089] Modules linked in: 6r T[S re lea se4. .986089] Pid: 1488, comm: longtest Not tainted 2.6.32-litmus2010 #3 [ 46.986089] RIP: 0010:[<ffffffff811f3f40>] [<ffffffff811f3f40>] psnedf_schedule+0x360/0x370 [ 46.986089] RSP: 0018:ffff88007bf7fd18 EFLAGS: 00010087 [ 46.986089] RAX: 000000000000f5f5 RBX: ffffffff814412c0 RCX: ffff88007befef90 [ 46.986089] RDX: ffff88007befc830 RSI: ffff88007befef90 RDI: ffff880001850a40 [ 46.986089] RBP: ffff88007bf7fd58 R08: 0000000000000000 R09: ffff88000180dc50 [ 46.986089] R10: 0000000000000000 R11: 0000000000000000 R12: ffff880001850a40 [ 46.986089] R13: ffff88007befef90 R14: ffff88000186cec0 R15: ffff88007befef90 [ 46.986089] FS: 00007fc0694e4910(0000) GS:ffff880001840000(0000) knlGS:0000000000000000 [ 46.986089] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 46.986089] CR2: 00000000006dc2d8 CR3: 000000007b2ed000 CR4: 00000000000006a0 [ 46.986089] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 46.986089] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 [ 46.986089] Process longtest (pid: 1488, threadinfo ffff88007bf7e000, task ffff88007befef90) [ 46.986089] Stack: [ 46.986089] 0000000000000000 0000000000000000 0000000000000000 ffffffff814412c0 [ 46.986089] <0> 0000000000000000 ffff88007befef90 ffff88000186cec0 ffff88000184db08 [ 46.986089] <0> ffff88007bf7fdb8 ffffffff81035f64 0000000000000000 0000000000000000 [ 46.986089] Call Trace: [ 46.986089] [<ffffffff81035f64>] pick_next_task_litmus+0x44/0x400 [ 46.986089] [<ffffffff814381e9>] schedule+0x239/0x356 [ 46.986089] [<ffffffff810cf1b7>] ? nameidata_to_filp+0x57/0x70 [ 46.986089] [<ffffffff8143a515>] __down_write_nested+0x85/0xd0 [ 46.986089] [<ffffffff8143a56b>] __down_write+0xb/0x10 [ 46.986089] [<ffffffff81439c2e>] down_write+0xe/0x10 [ 46.986089] [<ffffffff810103cd>] sys_mmap+0xdd/0x120 [ 46.986089] [<ffffffff8100b2ab>] system_call_fastpath+0x16/0x1b [ 46.986089] Code: c0 83 c6 01 48 c7 c7 80 07 55 81 e8 eb 44 00 00 48 8b 83 50 06 00 00 c7 40 04 01 00 00 00 e9 d5 fd ff ff 0f 0b eb fe 0f 1f 40 00 <0 [ 46.986089] RIP [<ffffffff811f3f40>] psnedf_schedule+0x360/0x370 [ 46.986089] RSP <ffff88007bf7fd18> [ 46.986089] ---[ end trace 6205a69dc6b27ca5 ]---
-rw-r--r--litmus/sched_psn_edf.c52
1 files changed, 41 insertions, 11 deletions
diff --git a/litmus/sched_psn_edf.c b/litmus/sched_psn_edf.c
index 3a93124e24f6..4829653b8f76 100644
--- a/litmus/sched_psn_edf.c
+++ b/litmus/sched_psn_edf.c
@@ -26,6 +26,13 @@ typedef struct {
26 int cpu; 26 int cpu;
27 struct task_struct* scheduled; /* only RT tasks */ 27 struct task_struct* scheduled; /* only RT tasks */
28/* 28/*
29 * A block event (mainly during synchronous release) may race
30 * with other releases or with triggering of the schedule() function.
31 * We need to trace a previous blocking event in the first execution of
32 * schedule()
33 */
34 int block;
35/*
29 * scheduling lock slock 36 * scheduling lock slock
30 * protects the domain and serializes scheduling decisions 37 * protects the domain and serializes scheduling decisions
31 */ 38 */
@@ -51,6 +58,7 @@ static void psnedf_domain_init(psnedf_domain_t* pedf,
51 edf_domain_init(&pedf->domain, check, release); 58 edf_domain_init(&pedf->domain, check, release);
52 pedf->cpu = cpu; 59 pedf->cpu = cpu;
53 pedf->scheduled = NULL; 60 pedf->scheduled = NULL;
61 pedf->block = 0;
54} 62}
55 63
56static void requeue(struct task_struct* t, rt_domain_t *edf) 64static void requeue(struct task_struct* t, rt_domain_t *edf)
@@ -140,22 +148,36 @@ static struct task_struct* psnedf_schedule(struct task_struct * prev)
140 148
141 /* (0) Determine state */ 149 /* (0) Determine state */
142 exists = pedf->scheduled != NULL; 150 exists = pedf->scheduled != NULL;
143 blocks = exists && !is_running(pedf->scheduled); 151 /* a task may block if 1) the task exists but is no more running
152 * 2) the task blocked and this schedule is racing with it while
153 * it is going to sleep. In this case pedf->schedule != prev (and we
154 * already reset pedf->schedule to NULL), but nonetheless we want to
155 * pick a real-time task as next (if such a task exists in the ready
156 * queue).
157 */
158 blocks = pedf->block || (exists && !is_running(pedf->scheduled));
144 out_of_time = exists && budget_exhausted(pedf->scheduled); 159 out_of_time = exists && budget_exhausted(pedf->scheduled);
145 np = exists && is_np(pedf->scheduled); 160 np = exists && is_np(pedf->scheduled);
146 sleep = exists && get_rt_flags(pedf->scheduled) == RT_F_SLEEP; 161 sleep = exists && get_rt_flags(pedf->scheduled) == RT_F_SLEEP;
147 preempt = edf_preemption_needed(edf, prev); 162 preempt = edf_preemption_needed(edf, prev);
148 163
149 /* If we need to preempt do so.
150 * The following checks set resched to 1 in case of special
151 * circumstances.
152 */
153 resched = preempt;
154 164
155 /* If a task blocks we have no choice but to reschedule. 165 /* If a task blocks we have no choice but to reschedule.
156 */ 166 */
157 if (blocks) 167 if (blocks) {
168
158 resched = 1; 169 resched = 1;
170 /* reset the block flag, we are about to reschedule */
171 pedf->block = 0;
172 } else {
173
174 /* If we need to preempt do so.
175 * The following checks set resched to 1 in case of special
176 * circumstances.
177 */
178 resched = preempt;
179 }
180
159 181
160 /* Request a sys_exit_np() call if we would like to preempt but cannot. 182 /* Request a sys_exit_np() call if we would like to preempt but cannot.
161 * Multiple calls to request_exit_np() don't hurt. 183 * Multiple calls to request_exit_np() don't hurt.
@@ -266,6 +288,7 @@ static void psnedf_task_wake_up(struct task_struct *task)
266static void psnedf_task_block(struct task_struct *t) 288static void psnedf_task_block(struct task_struct *t)
267{ 289{
268 psnedf_domain_t *pedf = task_pedf(t); 290 psnedf_domain_t *pedf = task_pedf(t);
291 unsigned long flags;
269 292
270 /* only running tasks can block, thus t is in no queue */ 293 /* only running tasks can block, thus t is in no queue */
271 TRACE_TASK(t, "block at %llu, state=%d\n", litmus_clock(), t->state); 294 TRACE_TASK(t, "block at %llu, state=%d\n", litmus_clock(), t->state);
@@ -273,12 +296,18 @@ static void psnedf_task_block(struct task_struct *t)
273 BUG_ON(!is_realtime(t)); 296 BUG_ON(!is_realtime(t));
274 BUG_ON(is_queued(t)); 297 BUG_ON(is_queued(t));
275 298
276 /* if this task is dead, then we need to reset pedf->schedule now 299 /* if this task is no more runnable, then we need to reset pedf->schedule
277 * as we might get rescheduled before task_exit executes 300 * and set the block flag as another schedule() may race wotj is while
301 * we are going to sleep
278 */ 302 */
279 if(unlikely(t->state == TASK_DEAD)) { 303 if(likely(t->state != TASK_RUNNING)) {
280 TRACE_TASK(t, "Dead, setting scheduled = NULL\n"); 304
305 TRACE_TASK(t, "psnedf_task_block, setting block flag\n");
306
307 spin_lock_irqsave(&pedf->slock, flags);
308 pedf->block = 1;
281 pedf->scheduled = NULL; 309 pedf->scheduled = NULL;
310 spin_unlock_irqrestore(&pedf->slock, flags);
282 } 311 }
283} 312}
284 313
@@ -347,6 +376,7 @@ static long psnedf_pi_block(struct pi_semaphore *sem,
347 376
348 spin_unlock(&pedf->slock); 377 spin_unlock(&pedf->slock);
349 } 378 }
379 TRACE_TASK(sem->holder, "psnedf_pi_block\n");
350 380
351 return 0; 381 return 0;
352} 382}