aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristopher Kenna <cjk@cs.unc.edu>2011-09-21 00:09:18 -0400
committerChristopher Kenna <cjk@cs.unc.edu>2011-09-21 00:10:41 -0400
commit536d91a595c116ca869b3a07a35873cbeff37db3 (patch)
treedd3b32db071e7c7af24dff5c59c87c94e2af51d8
parent313bcb226f88d17b193f9e7db7ecb4f57320a596 (diff)
Passes simple tests.
-rw-r--r--include/litmus/sched_mc.h2
-rw-r--r--litmus/litmus.c2
-rw-r--r--litmus/sched_mc_ce.c198
3 files changed, 138 insertions, 64 deletions
diff --git a/include/litmus/sched_mc.h b/include/litmus/sched_mc.h
index 32ef68150c81..94ec895afca0 100644
--- a/include/litmus/sched_mc.h
+++ b/include/litmus/sched_mc.h
@@ -21,6 +21,8 @@ struct mc_task {
21struct mc_job { 21struct mc_job {
22 int is_ghost:1; 22 int is_ghost:1;
23 lt_t ghost_budget; 23 lt_t ghost_budget;
24 /* which invocation of the CE is this */
25 unsigned int expected_job;
24}; 26};
25 27
26#ifdef __KERNEL__ 28#ifdef __KERNEL__
diff --git a/litmus/litmus.c b/litmus/litmus.c
index 7db9fdadc7db..272fa8419a8a 100644
--- a/litmus/litmus.c
+++ b/litmus/litmus.c
@@ -288,7 +288,7 @@ asmlinkage long sys_set_rt_task_mc_param(pid_t pid, struct mc_task __user *param
288 struct task_struct *target; 288 struct task_struct *target;
289 int retval = -EINVAL; 289 int retval = -EINVAL;
290 290
291 printk("Setting up mixed-criicality task parameters for process %d.\n", 291 printk("Setting up mixed-criticality task parameters for process %d.\n",
292 pid); 292 pid);
293 293
294 if (pid < 0 || param == 0) { 294 if (pid < 0 || param == 0) {
diff --git a/litmus/sched_mc_ce.c b/litmus/sched_mc_ce.c
index 1fdca7a7d3aa..32865c2d9c22 100644
--- a/litmus/sched_mc_ce.c
+++ b/litmus/sched_mc_ce.c
@@ -21,6 +21,7 @@
21#include <litmus/rt_param.h> 21#include <litmus/rt_param.h>
22#include <litmus/sched_mc.h> 22#include <litmus/sched_mc.h>
23#include <litmus/litmus_proc.h> 23#include <litmus/litmus_proc.h>
24#include <litmus/sched_trace.h>
24 25
25static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp; 26static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp;
26 27
@@ -31,7 +32,6 @@ static struct sched_plugin mc_ce_plugin __cacheline_aligned_in_smp;
31static atomic_t start_time_set = ATOMIC_INIT(0); 32static atomic_t start_time_set = ATOMIC_INIT(0);
32static atomic64_t start_time = ATOMIC64_INIT(0); 33static atomic64_t start_time = ATOMIC64_INIT(0);
33static struct proc_dir_entry *mc_ce_dir = NULL, *ce_file = NULL; 34static struct proc_dir_entry *mc_ce_dir = NULL, *ce_file = NULL;
34static DEFINE_RAW_SPINLOCK(activate_lock);
35 35
36/* 36/*
37 * Cache the budget along with the struct PID for a task so that we don't need 37 * Cache the budget along with the struct PID for a task so that we don't need
@@ -40,9 +40,8 @@ static DEFINE_RAW_SPINLOCK(activate_lock);
40 */ 40 */
41struct ce_dom_pid_entry { 41struct ce_dom_pid_entry {
42 struct pid *pid; 42 struct pid *pid;
43 /* execution cost (sometimes called budget) */ 43 lt_t budget;
44 lt_t exec_cost; 44 /* accumulated (summed) budgets, including this one */
45 /* accumulated (summed) exec costs, including this one */
46 lt_t acc_time; 45 lt_t acc_time;
47}; 46};
48 47
@@ -64,22 +63,29 @@ DEFINE_PER_CPU(domain_t, mc_ce_doms);
64DEFINE_PER_CPU(struct ce_dom_data, _mc_ce_dom_data); 63DEFINE_PER_CPU(struct ce_dom_data, _mc_ce_dom_data);
65 64
66/* 65/*
66 * Get the offset into the cycle taking the start time into account.
67 */
68static inline lt_t get_cycle_offset(const lt_t when, const lt_t cycle_time)
69{
70 return (when - atomic64_read(&start_time)) % cycle_time;
71}
72
73/*
67 * Return the index into the PID entries table of what to schedule next. 74 * Return the index into the PID entries table of what to schedule next.
68 * Don't call if the table is empty. Assumes the caller has the domain lock. 75 * Don't call if the table is empty. Assumes the caller has the domain lock.
76 * The offset parameter is the offset into the cycle.
69 * 77 *
70 * TODO Currently O(n) in the number of tasks on the CPU. Binary search? 78 * TODO Currently O(n) in the number of tasks on the CPU. Binary search?
71 */ 79 */
72static int mc_ce_schedule_at(const lt_t when, const domain_t *dom) 80static int mc_ce_schedule_at(const domain_t *dom, lt_t offset)
73{ 81{
74 const struct ce_dom_data *ce_data = dom->data; 82 const struct ce_dom_data *ce_data = dom->data;
75 const struct ce_dom_pid_entry *pid_entry = NULL; 83 const struct ce_dom_pid_entry *pid_entry = NULL;
76 lt_t offset;
77 int i; 84 int i;
78 85
79 BUG_ON(ce_data->cycle_time < 1); 86 BUG_ON(ce_data->cycle_time < 1);
80 BUG_ON(ce_data->num_pid_entries < 1); 87 BUG_ON(ce_data->num_pid_entries < 1);
81 88
82 offset = (when - atomic64_read(&start_time)) % ce_data->cycle_time;
83 for (i = 0; i < ce_data->num_pid_entries; ++i) { 89 for (i = 0; i < ce_data->num_pid_entries; ++i) {
84 pid_entry = &ce_data->pid_entries[i]; 90 pid_entry = &ce_data->pid_entries[i];
85 if (offset < pid_entry->acc_time) { 91 if (offset < pid_entry->acc_time) {
@@ -89,6 +95,7 @@ static int mc_ce_schedule_at(const lt_t when, const domain_t *dom)
89 } 95 }
90 /* can only happen if cycle_time is not right */ 96 /* can only happen if cycle_time is not right */
91 BUG_ON(pid_entry->acc_time > ce_data->cycle_time); 97 BUG_ON(pid_entry->acc_time > ce_data->cycle_time);
98 TRACE("MC-CE schedule at returned task %d for CPU %d\n", i, ce_data->cpu);
92 return i; 99 return i;
93} 100}
94 101
@@ -117,11 +124,14 @@ static struct task_struct *mc_ce_schedule(struct task_struct *prev)
117 request_exit_np(ce_data->scheduled); 124 request_exit_np(ce_data->scheduled);
118 next = prev; 125 next = prev;
119 } else if (ce_data->should_schedule && 126 } else if (ce_data->should_schedule &&
120 is_running(ce_data->should_schedule)) { 127 is_running(ce_data->should_schedule) &&
121 /* schedule the task for this period if it's not blocked */ 128 RT_F_SLEEP != get_rt_flags(ce_data->should_schedule)) {
122 next = ce_data->should_schedule; 129 /*
130 * schedule the task that should be executing in the cyclic
131 * schedule if it is not blocked and not sleeping
132 */
133 next = ce_data->should_schedule;
123 } 134 }
124
125 sched_state_task_picked(); 135 sched_state_task_picked();
126 raw_spin_unlock(dom->lock); 136 raw_spin_unlock(dom->lock);
127 return next; 137 return next;
@@ -211,11 +221,11 @@ static long mc_ce_admit_task(struct task_struct *ts)
211 lvl_a_id, get_partition(ts)); 221 lvl_a_id, get_partition(ts));
212 goto out_put_pid_unlock; 222 goto out_put_pid_unlock;
213 } 223 }
214 if (get_exec_cost(ts) != ce_data->pid_entries[lvl_a_id].exec_cost) { 224 if (get_exec_cost(ts) >= ce_data->pid_entries[lvl_a_id].budget) {
215 printk(KERN_INFO "litmus: saved exec cost %llu and task exec " 225 printk(KERN_INFO "litmus: execution cost %llu is larger than "
216 "cost %llu differ\n", 226 "the budget %llu\n",
217 ce_data->pid_entries[lvl_a_id].exec_cost, 227 get_exec_cost(ts),
218 get_exec_cost(ts)); 228 ce_data->pid_entries[lvl_a_id].budget);
219 goto out_put_pid_unlock; 229 goto out_put_pid_unlock;
220 } 230 }
221 ce_data->pid_entries[lvl_a_id].pid = pid; 231 ce_data->pid_entries[lvl_a_id].pid = pid;
@@ -243,12 +253,19 @@ static void mc_ce_task_new(struct task_struct *ts, int on_rq, int running)
243 struct pid *pid_should_be_running; 253 struct pid *pid_should_be_running;
244 unsigned long flags; 254 unsigned long flags;
245 int idx, should_be_running; 255 int idx, should_be_running;
256 lt_t offset;
246 257
247 /* have to call mc_ce_schedule_at because the task only gets a PID 258 /* have to call mc_ce_schedule_at because the task only gets a PID
248 * entry after calling admit_task */ 259 * entry after calling admit_task */
249 260
250 raw_spin_lock_irqsave(dom->lock, flags); 261 raw_spin_lock_irqsave(dom->lock, flags);
251 idx = mc_ce_schedule_at(litmus_clock(), dom); 262 /* initialize some task state */
263 set_rt_flags(ts, RT_F_RUNNING);
264 tsk_rt(ts)->job_params.job_no = 0;
265 tsk_mc_data(ts)->mc_job.expected_job = 0;
266
267 offset = get_cycle_offset(litmus_clock(), ce_data->cycle_time);
268 idx = mc_ce_schedule_at(dom, offset);
252 pid_should_be_running = ce_data->pid_entries[idx].pid; 269 pid_should_be_running = ce_data->pid_entries[idx].pid;
253 rcu_read_lock(); 270 rcu_read_lock();
254 should_be_running = (ts == pid_task(pid_should_be_running, PIDTYPE_PID)); 271 should_be_running = (ts == pid_task(pid_should_be_running, PIDTYPE_PID));
@@ -301,9 +318,13 @@ static void mc_ce_task_block(struct task_struct *ts)
301 */ 318 */
302static long mc_ce_complete_job(void) 319static long mc_ce_complete_job(void)
303{ 320{
304 /* TODO */ 321 /* mark that the task wishes to sleep */
305 printk(KERN_EMERG "complete job called TODO\n"); 322 set_rt_flags(current, RT_F_SLEEP);
306 BUG(); 323 tsk_rt(current)->job_params.job_no++;
324 /* call schedule, this will return when a new job arrives
325 * it also takes care of preparing for the next release
326 */
327 schedule();
307 return 0; 328 return 0;
308} 329}
309 330
@@ -327,6 +348,10 @@ static void mc_ce_task_exit(struct task_struct *ts)
327 BUG_ON(!pid); 348 BUG_ON(!pid);
328 put_pid(pid); 349 put_pid(pid);
329 ce_data->pid_entries[lvl_a_id].pid = NULL; 350 ce_data->pid_entries[lvl_a_id].pid = NULL;
351 if (ce_data->scheduled == ts)
352 ce_data->scheduled = NULL;
353 if (ce_data->should_schedule == ts)
354 ce_data->should_schedule = NULL;
330 raw_spin_unlock_irqrestore(dom->lock, flags); 355 raw_spin_unlock_irqrestore(dom->lock, flags);
331} 356}
332 357
@@ -340,28 +365,64 @@ static void mc_ce_task_exit(struct task_struct *ts)
340 */ 365 */
341static enum hrtimer_restart timer_callback(struct hrtimer *timer) 366static enum hrtimer_restart timer_callback(struct hrtimer *timer)
342{ 367{
343 struct ce_dom_data *ce_data = container_of(timer,
344 struct ce_dom_data, timer);
345 domain_t *dom = &per_cpu(mc_ce_doms, ce_data->cpu);
346 /* relative and absolute times for cycles */ 368 /* relative and absolute times for cycles */
347 lt_t now, offset_rel, cycle_start_abs, next_timer_abs; 369 lt_t now, offset_rel, cycle_start_abs, next_timer_abs;
370 struct task_struct *should_schedule;
348 struct ce_dom_pid_entry *pid_entry; 371 struct ce_dom_pid_entry *pid_entry;
372 struct ce_dom_data *ce_data;
349 unsigned long flags; 373 unsigned long flags;
374 domain_t *dom;
350 int idx; 375 int idx;
351 376
377 ce_data = container_of(timer, struct ce_dom_data, timer);
378 dom = &per_cpu(mc_ce_doms, ce_data->cpu);
379
352 raw_spin_lock_irqsave(dom->lock, flags); 380 raw_spin_lock_irqsave(dom->lock, flags);
353 381
354 now = litmus_clock(); 382 now = litmus_clock();
355 offset_rel = (now - atomic64_read(&start_time)) % ce_data->cycle_time; 383 TRACE("timer callback at %llu on CPU %d\n", now, ce_data->cpu);
384 /* Based off of the current time, figure out the offset into the cycle
385 * and the cycle's start time, and determine what should be scheduled.
386 */
387 offset_rel = get_cycle_offset(now, ce_data->cycle_time);
356 cycle_start_abs = now - offset_rel; 388 cycle_start_abs = now - offset_rel;
357 idx = mc_ce_schedule_at(now, dom); 389 idx = mc_ce_schedule_at(dom, offset_rel);
358 pid_entry = &ce_data->pid_entries[idx]; 390 pid_entry = &ce_data->pid_entries[idx];
391 /* set the timer to fire at the next cycle start */
359 next_timer_abs = cycle_start_abs + pid_entry->acc_time; 392 next_timer_abs = cycle_start_abs + pid_entry->acc_time;
360 hrtimer_set_expires(timer, ns_to_ktime(next_timer_abs)); 393 hrtimer_set_expires(timer, ns_to_ktime(next_timer_abs));
394
361 /* get the task_struct (pid_task can accept a NULL) */ 395 /* get the task_struct (pid_task can accept a NULL) */
362 rcu_read_lock(); 396 rcu_read_lock();
363 ce_data->should_schedule = pid_task(pid_entry->pid, PIDTYPE_PID); 397 should_schedule = pid_task(pid_entry->pid, PIDTYPE_PID);
364 rcu_read_unlock(); 398 rcu_read_unlock();
399 ce_data->should_schedule = should_schedule;
400
401 if (should_schedule && atomic_read(&start_time_set)) {
402 /* we only start tracking this after the job release syscall */
403 tsk_mc_data(should_schedule)->mc_job.expected_job++;
404 /*
405 * If jobs are not overrunning their budgets, then this
406 * should not happen.
407 */
408 WARN(tsk_mc_data(should_schedule)->mc_job.expected_job !=
409 tsk_rt(should_schedule)->job_params.job_no,
410 "LITMUS MC-CE level A timer fired, "
411 "but the task %d seems to be "
412 "overrunning its budget\n",
413 should_schedule->pid);
414 }
415
416 if (ce_data->should_schedule) {
417 tsk_rt(should_schedule)->job_params.deadline =
418 cycle_start_abs + pid_entry->acc_time;
419 tsk_rt(should_schedule)->job_params.release =
420 tsk_rt(should_schedule)->job_params.deadline -
421 pid_entry->budget;
422 tsk_rt(should_schedule)->job_params.exec_time = 0;
423 sched_trace_task_release(should_schedule);
424 set_rt_flags(ce_data->should_schedule, RT_F_RUNNING);
425 }
365 if (ce_data->scheduled != ce_data->should_schedule) 426 if (ce_data->scheduled != ce_data->should_schedule)
366 preempt_if_preemptable(ce_data->scheduled, ce_data->cpu); 427 preempt_if_preemptable(ce_data->scheduled, ce_data->cpu);
367 428
@@ -377,12 +438,13 @@ static int cancel_all_timers(void)
377{ 438{
378 struct ce_dom_data *ce_data; 439 struct ce_dom_data *ce_data;
379 domain_t *dom; 440 domain_t *dom;
380 int cpu, ret = 0; 441 int cpu, ret = 0, cancel_res;
381 442
382 for_each_online_cpu(cpu) { 443 for_each_online_cpu(cpu) {
383 dom = &per_cpu(mc_ce_doms, cpu); 444 dom = &per_cpu(mc_ce_doms, cpu);
384 ce_data = dom->data; 445 ce_data = dom->data;
385 ret = ret || hrtimer_cancel(&ce_data->timer); 446 cancel_res = hrtimer_cancel(&ce_data->timer);
447 ret = ret || cancel_res;
386 } 448 }
387 return ret; 449 return ret;
388} 450}
@@ -410,9 +472,9 @@ static void arm_all_timers(void)
410} 472}
411 473
412/* 474/*
413 * There are no real releases in the CE, but the task releasing code will 475 * There are no real releases in the CE, but the task releease syscall will
414 * call this. We can re-set our notion of the CE period start to make 476 * call this. We can re-set our notion of the CE period start to make
415 * the schedule line up. 477 * the schedule look pretty.
416 */ 478 */
417static void mc_ce_release_at(struct task_struct *ts, lt_t start) 479static void mc_ce_release_at(struct task_struct *ts, lt_t start)
418{ 480{
@@ -431,8 +493,6 @@ static long mc_ce_activate_plugin(void)
431 domain_t *dom; 493 domain_t *dom;
432 int cpu; 494 int cpu;
433 495
434 raw_spin_lock(&activate_lock);
435
436 for_each_online_cpu(cpu) { 496 for_each_online_cpu(cpu) {
437 dom = &per_cpu(mc_ce_doms, cpu); 497 dom = &per_cpu(mc_ce_doms, cpu);
438 ce_data = dom->data; 498 ce_data = dom->data;
@@ -443,7 +503,6 @@ static long mc_ce_activate_plugin(void)
443 atomic_set(&start_time_set, 0); 503 atomic_set(&start_time_set, 0);
444 atomic64_set(&start_time, litmus_clock()); 504 atomic64_set(&start_time, litmus_clock());
445 arm_all_timers(); 505 arm_all_timers();
446 raw_spin_unlock(&activate_lock);
447 return 0; 506 return 0;
448} 507}
449 508
@@ -464,13 +523,12 @@ static void clear_pid_entries(void)
464 put_pid(ce_data->pid_entries[entry].pid); 523 put_pid(ce_data->pid_entries[entry].pid);
465 ce_data->pid_entries[entry].pid = NULL; 524 ce_data->pid_entries[entry].pid = NULL;
466 } 525 }
467 ce_data->pid_entries[entry].exec_cost = 0; 526 ce_data->pid_entries[entry].budget = 0;
468 ce_data->pid_entries[entry].acc_time = 0; 527 ce_data->pid_entries[entry].acc_time = 0;
469 } 528 }
470 } 529 }
471} 530}
472 531
473static void tear_down_proc(void);
474static long mc_ce_deactivate_plugin(void) 532static long mc_ce_deactivate_plugin(void)
475{ 533{
476 domain_t *dom; 534 domain_t *dom;
@@ -484,8 +542,6 @@ static long mc_ce_deactivate_plugin(void)
484 atomic_set(&ce_data->timer_info.state, 542 atomic_set(&ce_data->timer_info.state,
485 HRTIMER_START_ON_INACTIVE); 543 HRTIMER_START_ON_INACTIVE);
486 } 544 }
487 clear_pid_entries();
488 tear_down_proc();
489 return 0; 545 return 0;
490} 546}
491 547
@@ -513,7 +569,6 @@ static int __init init_sched_mc_ce(void)
513 domain_t *dom; 569 domain_t *dom;
514 int cpu, err; 570 int cpu, err;
515 571
516 clear_pid_entries();
517 for_each_online_cpu(cpu) { 572 for_each_online_cpu(cpu) {
518 dom = &per_cpu(mc_ce_doms, cpu); 573 dom = &per_cpu(mc_ce_doms, cpu);
519 pd_domain_init(dom, NULL, NULL, NULL, NULL, NULL); 574 pd_domain_init(dom, NULL, NULL, NULL, NULL, NULL);
@@ -524,6 +579,7 @@ static int __init init_sched_mc_ce(void)
524 ce_data->cpu = cpu; 579 ce_data->cpu = cpu;
525 ce_data->timer.function = timer_callback; 580 ce_data->timer.function = timer_callback;
526 } 581 }
582 clear_pid_entries();
527 err = setup_proc(); 583 err = setup_proc();
528 if (!err) 584 if (!err)
529 err = register_sched_plugin(&mc_ce_plugin); 585 err = register_sched_plugin(&mc_ce_plugin);
@@ -537,15 +593,18 @@ static int write_into_proc(char *proc_buf, const int proc_size, char *fmt, ...)
537 int n; 593 int n;
538 va_list args; 594 va_list args;
539 595
596 /* When writing to procfs, we don't care about the trailing null that
597 * is not included in the count returned by vscnprintf.
598 */
540 va_start(args, fmt); 599 va_start(args, fmt);
541 n = vscnprintf(buf, BUF_SIZE, fmt, args); 600 n = vsnprintf(buf, BUF_SIZE, fmt, args);
542 va_end(args); 601 va_end(args);
543 if (BUF_SIZE <= n || proc_size <= n - 1) { 602 if (BUF_SIZE <= n || proc_size <= n) {
544 /* too big for formatting buffer or proc (less null byte) */ 603 /* too big for formatting buffer or proc (less null byte) */
545 n = -EINVAL; 604 n = -EINVAL;
546 goto out; 605 goto out;
547 } 606 }
548 memcpy(proc_buf, buf, n - 1); 607 memcpy(proc_buf, buf, n);
549out: 608out:
550 return n; 609 return n;
551} 610}
@@ -553,6 +612,9 @@ out:
553 612
554/* 613/*
555 * Writes a PID entry to the procfs. 614 * Writes a PID entry to the procfs.
615 *
616 * @page buffer to write into.
617 * @count bytes available in the buffer
556 */ 618 */
557#define PID_SPACE 15 619#define PID_SPACE 15
558#define TASK_INFO_BUF (PID_SPACE + TASK_COMM_LEN) 620#define TASK_INFO_BUF (PID_SPACE + TASK_COMM_LEN)
@@ -579,28 +641,28 @@ static int write_pid_entry(char *page, const int count, const int cpu,
579 *ti_b = ' '; /* nuke the null byte */ 641 *ti_b = ' '; /* nuke the null byte */
580 ti_b++; 642 ti_b++;
581 get_task_comm(ti_b, ts); 643 get_task_comm(ti_b, ts);
582 task_info[TASK_INFO_BUF - 1] = '\0';
583 } else { 644 } else {
584 const char *msg = "pid_task() failed :("; 645 strncpy(task_info, "pid_task() failed :(",
585 strncpy(task_info, msg, sizeof(msg)); 646 TASK_INFO_BUF);
586 } 647 }
587 648
588 } else 649 } else
589 strncpy(task_info, "no", 3); 650 strncpy(task_info, "no", TASK_INFO_BUF);
651 task_info[TASK_INFO_BUF - 1] = '\0'; /* just to be sure */
590 652
591 err = write_into_proc(page, count - n, "# task: %s\n", task_info); 653 err = write_into_proc(page + n, count - n, "# task: %s\n", task_info);
592 if (err < 0) { 654 if (err < 0) {
593 n = -ENOSPC; 655 n = -ENOSPC;
594 goto out; 656 goto out;
595 } 657 }
596 n += err; 658 n += err;
597 err = write_into_proc(page, count - n, "%d, %d, %llu\n", 659 err = write_into_proc(page + n, count - n, "%d, %d, %llu\n",
598 cpu, task, pid_entry->exec_cost); 660 cpu, task, pid_entry->budget);
599 if (err < 0) { 661 if (err < 0) {
600 n = -ENOSPC; 662 n = -ENOSPC;
601 goto out; 663 goto out;
602 } 664 }
603 n =+ err; 665 n += err;
604out: 666out:
605 return n; 667 return n;
606} 668}
@@ -618,15 +680,15 @@ static int proc_read_ce_file(char *page, char **start, off_t off, int count,
618 domain_t *dom; 680 domain_t *dom;
619 681
620 if (off > 0) { 682 if (off > 0) {
621 *eof = 1; 683 printk(KERN_INFO "litmus: MC-CE called read with off > 0\n");
622 return 0; 684 goto out;
623 } 685 }
624 686
625 for_each_online_cpu(cpu) { 687 for_each_online_cpu(cpu) {
626 dom = &per_cpu(mc_ce_doms, cpu); 688 dom = &per_cpu(mc_ce_doms, cpu);
627 ce_data = dom->data; 689 ce_data = dom->data;
628 for (t = 0; t < ce_data->num_pid_entries; ++t) { 690 for (t = 0; t < ce_data->num_pid_entries; ++t) {
629 err = write_pid_entry(page, count - n, 691 err = write_pid_entry(page + n, count - n,
630 cpu, t, &ce_data->pid_entries[t]); 692 cpu, t, &ce_data->pid_entries[t]);
631 if (err < 0) { 693 if (err < 0) {
632 n = -ENOSPC; 694 n = -ENOSPC;
@@ -635,8 +697,8 @@ static int proc_read_ce_file(char *page, char **start, off_t off, int count,
635 n += err; 697 n += err;
636 } 698 }
637 } 699 }
638 *eof = 1;
639out: 700out:
701 *eof = 1;
640 return n; 702 return n;
641} 703}
642 704
@@ -660,8 +722,8 @@ static int skip_comment(const char *buf, const unsigned long max)
660 return i; 722 return i;
661} 723}
662 724
663/* a budget of 1 millisecond is probably reasonable */ 725/* a budget of 5 milliseconds is probably reasonable */
664#define BUDGET_THRESHOLD 1000000ULL 726#define BUDGET_THRESHOLD 5000000ULL
665static int setup_pid_entry(const int cpu, const int task, const lt_t budget) 727static int setup_pid_entry(const int cpu, const int task, const lt_t budget)
666{ 728{
667 domain_t *dom = &per_cpu(mc_ce_doms, cpu); 729 domain_t *dom = &per_cpu(mc_ce_doms, cpu);
@@ -670,9 +732,10 @@ static int setup_pid_entry(const int cpu, const int task, const lt_t budget)
670 int err = 0; 732 int err = 0;
671 733
672 /* check the inputs */ 734 /* check the inputs */
673 if (cpu < 0 || cpu >= NR_CPUS || task < 1 || task > PID_MAX_DEFAULT || 735 if (cpu < 0 || NR_CPUS <= cpu || task < 0 ||
736 CONFIG_PLUGIN_MC_LEVEL_A_MAX_TASKS <= task ||
674 budget < 1) { 737 budget < 1) {
675 printk(KERN_INFO "litmus: bad cpu or task ID sent to " 738 printk(KERN_INFO "litmus: bad cpu, task ID, or budget sent to "
676 "MC-CE proc\n"); 739 "MC-CE proc\n");
677 err = -EINVAL; 740 err = -EINVAL;
678 goto out; 741 goto out;
@@ -692,7 +755,7 @@ static int setup_pid_entry(const int cpu, const int task, const lt_t budget)
692 /* add the new entry */ 755 /* add the new entry */
693 new_entry = &ce_data->pid_entries[ce_data->num_pid_entries]; 756 new_entry = &ce_data->pid_entries[ce_data->num_pid_entries];
694 BUG_ON(NULL != new_entry->pid); 757 BUG_ON(NULL != new_entry->pid);
695 new_entry->exec_cost = budget; 758 new_entry->budget = budget;
696 new_entry->acc_time = ce_data->cycle_time + budget; 759 new_entry->acc_time = ce_data->cycle_time + budget;
697 /* update the domain entry */ 760 /* update the domain entry */
698 ce_data->cycle_time += budget; 761 ce_data->cycle_time += budget;
@@ -717,8 +780,6 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer,
717 int cpu, task, cnt = 0, chars_read, converted, err; 780 int cpu, task, cnt = 0, chars_read, converted, err;
718 lt_t budget; 781 lt_t budget;
719 782
720 raw_spin_lock(&activate_lock);
721
722 if (is_active_plugin()) { 783 if (is_active_plugin()) {
723 printk(KERN_INFO "litmus: can't edit MC-CE proc when plugin " 784 printk(KERN_INFO "litmus: can't edit MC-CE proc when plugin "
724 "active\n"); 785 "active\n");
@@ -727,11 +788,15 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer,
727 } 788 }
728 789
729 if (count > PROCFS_MAX_SIZE) { 790 if (count > PROCFS_MAX_SIZE) {
791 printk(KERN_INFO "litmus: MC-CE procfs got too many bytes "
792 "from user-space.\n");
730 cnt = -EINVAL; 793 cnt = -EINVAL;
731 goto out; 794 goto out;
732 } 795 }
733 796
734 if (copy_from_user(kbuf, buffer, count)) { 797 if (copy_from_user(kbuf, buffer, count)) {
798 printk(KERN_INFO "litmus: couldn't copy from user %s\n",
799 __FUNCTION__);
735 cnt = -EFAULT; 800 cnt = -EFAULT;
736 goto out; 801 goto out;
737 } 802 }
@@ -750,9 +815,11 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer,
750 c += chars_read; 815 c += chars_read;
751 continue; 816 continue;
752 } 817 }
753 chars_read = sscanf(c, "%d, %d, %llu%n", &cpu, &task, &budget, 818 converted = sscanf(c, "%d, %d, %llu%n", &cpu, &task, &budget,
754 &converted); 819 &chars_read);
755 if (3 != converted) { 820 if (3 != converted) {
821 printk(KERN_INFO "litmus: MC-CE procfs expected three "
822 "arguments, but got %d.\n", converted);
756 cnt = -EINVAL; 823 cnt = -EINVAL;
757 goto out; 824 goto out;
758 } 825 }
@@ -765,7 +832,6 @@ static int proc_write_ce_file(struct file *file, const char __user *buffer,
765 } 832 }
766 } 833 }
767out: 834out:
768 raw_spin_unlock(&activate_lock);
769 return cnt; 835 return cnt;
770} 836}
771#undef PROCFS_MAX_SIZE 837#undef PROCFS_MAX_SIZE
@@ -803,4 +869,10 @@ out:
803} 869}
804#undef CE_FILE_PROC_NAME 870#undef CE_FILE_PROC_NAME
805 871
872static void clean_sched_mc_ce(void)
873{
874 tear_down_proc();
875}
876
806module_init(init_sched_mc_ce); 877module_init(init_sched_mc_ce);
878module_exit(clean_sched_mc_ce);