diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2010-10-22 21:04:34 -0400 |
---|---|---|
committer | Bjoern B. Brandenburg <bbb@cs.unc.edu> | 2010-10-23 01:35:14 -0400 |
commit | e06e8374b5c04aeaddf14e9686842011f80f5664 (patch) | |
tree | 773c14713dbca67b5ea4cf4f7864dbc324ae9e44 | |
parent | 98f56816fcb5c97e0afd21a6e242bb72d5b7a551 (diff) |
Litmus core: refactor the implementation of /proc
-rw-r--r-- | include/litmus/litmus.h | 16 | ||||
-rw-r--r-- | include/litmus/litmus_proc.h | 19 | ||||
-rw-r--r-- | litmus/Makefile | 1 | ||||
-rw-r--r-- | litmus/litmus.c | 313 | ||||
-rw-r--r-- | litmus/litmus_proc.c | 324 |
5 files changed, 346 insertions, 327 deletions
diff --git a/include/litmus/litmus.h b/include/litmus/litmus.h index ccb6b137952b..5d20276e44f4 100644 --- a/include/litmus/litmus.h +++ b/include/litmus/litmus.h | |||
@@ -9,9 +9,6 @@ | |||
9 | #include <linux/jiffies.h> | 9 | #include <linux/jiffies.h> |
10 | #include <litmus/sched_trace.h> | 10 | #include <litmus/sched_trace.h> |
11 | 11 | ||
12 | #include <litmus/sched_plugin.h> | ||
13 | #include <linux/proc_fs.h> | ||
14 | |||
15 | #ifdef CONFIG_RELEASE_MASTER | 12 | #ifdef CONFIG_RELEASE_MASTER |
16 | extern atomic_t release_master_cpu; | 13 | extern atomic_t release_master_cpu; |
17 | #endif | 14 | #endif |
@@ -65,19 +62,6 @@ void exit_litmus(struct task_struct *dead_tsk); | |||
65 | long litmus_admit_task(struct task_struct *tsk); | 62 | long litmus_admit_task(struct task_struct *tsk); |
66 | void litmus_exit_task(struct task_struct *tsk); | 63 | void litmus_exit_task(struct task_struct *tsk); |
67 | 64 | ||
68 | /* | ||
69 | * On success, returns 0 and sets the pointer to the location of the new | ||
70 | * proc dir entry, otherwise returns an error code and sets pde to NULL. | ||
71 | */ | ||
72 | long make_plugin_proc_dir(struct sched_plugin* plugin, | ||
73 | struct proc_dir_entry** pde); | ||
74 | |||
75 | /* | ||
76 | * Plugins should deallocate all child proc directory entries before | ||
77 | * calling this, to avoid memory leaks. | ||
78 | */ | ||
79 | void remove_plugin_proc_dir(struct sched_plugin* plugin); | ||
80 | |||
81 | #define is_realtime(t) ((t)->policy == SCHED_LITMUS) | 65 | #define is_realtime(t) ((t)->policy == SCHED_LITMUS) |
82 | #define rt_transition_pending(t) \ | 66 | #define rt_transition_pending(t) \ |
83 | ((t)->rt_param.transition_pending) | 67 | ((t)->rt_param.transition_pending) |
diff --git a/include/litmus/litmus_proc.h b/include/litmus/litmus_proc.h new file mode 100644 index 000000000000..fbc0082b2d21 --- /dev/null +++ b/include/litmus/litmus_proc.h | |||
@@ -0,0 +1,19 @@ | |||
1 | #include <litmus/sched_plugin.h> | ||
2 | #include <linux/proc_fs.h> | ||
3 | |||
4 | int __init init_litmus_proc(void); | ||
5 | void exit_litmus_proc(void); | ||
6 | |||
7 | /* | ||
8 | * On success, returns 0 and sets the pointer to the location of the new | ||
9 | * proc dir entry, otherwise returns an error code and sets pde to NULL. | ||
10 | */ | ||
11 | long make_plugin_proc_dir(struct sched_plugin* plugin, | ||
12 | struct proc_dir_entry** pde); | ||
13 | |||
14 | /* | ||
15 | * Plugins should deallocate all child proc directory entries before | ||
16 | * calling this, to avoid memory leaks. | ||
17 | */ | ||
18 | void remove_plugin_proc_dir(struct sched_plugin* plugin); | ||
19 | |||
diff --git a/litmus/Makefile b/litmus/Makefile index f301d2842e43..7bd1abdcb84a 100644 --- a/litmus/Makefile +++ b/litmus/Makefile | |||
@@ -3,6 +3,7 @@ | |||
3 | # | 3 | # |
4 | 4 | ||
5 | obj-y = sched_plugin.o litmus.o \ | 5 | obj-y = sched_plugin.o litmus.o \ |
6 | litmus_proc.o \ | ||
6 | budget.o \ | 7 | budget.o \ |
7 | jobs.o \ | 8 | jobs.o \ |
8 | sync.o \ | 9 | sync.o \ |
diff --git a/litmus/litmus.c b/litmus/litmus.c index 3b73b39ffbbf..99c35ac99870 100644 --- a/litmus/litmus.c +++ b/litmus/litmus.c | |||
@@ -19,6 +19,8 @@ | |||
19 | 19 | ||
20 | #include <litmus/rt_domain.h> | 20 | #include <litmus/rt_domain.h> |
21 | 21 | ||
22 | #include <litmus/litmus_proc.h> | ||
23 | |||
22 | /* Number of RT tasks that exist in the system */ | 24 | /* Number of RT tasks that exist in the system */ |
23 | atomic_t rt_task_count = ATOMIC_INIT(0); | 25 | atomic_t rt_task_count = ATOMIC_INIT(0); |
24 | static DEFINE_RAW_SPINLOCK(task_transition_lock); | 26 | static DEFINE_RAW_SPINLOCK(task_transition_lock); |
@@ -505,317 +507,6 @@ static struct sysrq_key_op sysrq_kill_rt_tasks_op = { | |||
505 | }; | 507 | }; |
506 | #endif | 508 | #endif |
507 | 509 | ||
508 | /* in litmus/sync.c */ | ||
509 | int count_tasks_waiting_for_release(void); | ||
510 | |||
511 | static int proc_read_stats(char *page, char **start, | ||
512 | off_t off, int count, | ||
513 | int *eof, void *data) | ||
514 | { | ||
515 | int len; | ||
516 | |||
517 | len = snprintf(page, PAGE_SIZE, | ||
518 | "real-time tasks = %d\n" | ||
519 | "ready for release = %d\n", | ||
520 | atomic_read(&rt_task_count), | ||
521 | count_tasks_waiting_for_release()); | ||
522 | return len; | ||
523 | } | ||
524 | |||
525 | static int proc_read_plugins(char *page, char **start, | ||
526 | off_t off, int count, | ||
527 | int *eof, void *data) | ||
528 | { | ||
529 | int len; | ||
530 | |||
531 | len = print_sched_plugins(page, PAGE_SIZE); | ||
532 | return len; | ||
533 | } | ||
534 | |||
535 | static int proc_read_curr(char *page, char **start, | ||
536 | off_t off, int count, | ||
537 | int *eof, void *data) | ||
538 | { | ||
539 | int len; | ||
540 | |||
541 | len = snprintf(page, PAGE_SIZE, "%s\n", litmus->plugin_name); | ||
542 | return len; | ||
543 | } | ||
544 | |||
545 | static int proc_write_curr(struct file *file, | ||
546 | const char *buffer, | ||
547 | unsigned long count, | ||
548 | void *data) | ||
549 | { | ||
550 | int len, ret; | ||
551 | char name[65]; | ||
552 | struct sched_plugin* found; | ||
553 | |||
554 | if(count > 64) | ||
555 | len = 64; | ||
556 | else | ||
557 | len = count; | ||
558 | |||
559 | if(copy_from_user(name, buffer, len)) | ||
560 | return -EFAULT; | ||
561 | |||
562 | name[len] = '\0'; | ||
563 | /* chomp name */ | ||
564 | if (len > 1 && name[len - 1] == '\n') | ||
565 | name[len - 1] = '\0'; | ||
566 | |||
567 | found = find_sched_plugin(name); | ||
568 | |||
569 | if (found) { | ||
570 | ret = switch_sched_plugin(found); | ||
571 | if (ret != 0) | ||
572 | printk(KERN_INFO "Could not switch plugin: %d\n", ret); | ||
573 | } else | ||
574 | printk(KERN_INFO "Plugin '%s' is unknown.\n", name); | ||
575 | |||
576 | return len; | ||
577 | } | ||
578 | |||
579 | static int proc_read_cluster_size(char *page, char **start, | ||
580 | off_t off, int count, | ||
581 | int *eof, void *data) | ||
582 | { | ||
583 | int len; | ||
584 | if (cluster_cache_index == 2) | ||
585 | len = snprintf(page, PAGE_SIZE, "L2\n"); | ||
586 | else if (cluster_cache_index == 3) | ||
587 | len = snprintf(page, PAGE_SIZE, "L3\n"); | ||
588 | else if (cluster_cache_index == 1) | ||
589 | len = snprintf(page, PAGE_SIZE, "L1\n"); | ||
590 | else | ||
591 | len = snprintf(page, PAGE_SIZE, "ALL\n"); | ||
592 | |||
593 | return len; | ||
594 | } | ||
595 | |||
596 | static int proc_write_cluster_size(struct file *file, | ||
597 | const char *buffer, | ||
598 | unsigned long count, | ||
599 | void *data) | ||
600 | { | ||
601 | int len; | ||
602 | /* L2, L3 */ | ||
603 | char cache_name[33]; | ||
604 | |||
605 | if(count > 32) | ||
606 | len = 32; | ||
607 | else | ||
608 | len = count; | ||
609 | |||
610 | if(copy_from_user(cache_name, buffer, len)) | ||
611 | return -EFAULT; | ||
612 | |||
613 | cache_name[len] = '\0'; | ||
614 | /* chomp name */ | ||
615 | if (len > 1 && cache_name[len - 1] == '\n') | ||
616 | cache_name[len - 1] = '\0'; | ||
617 | |||
618 | /* do a quick and dirty comparison to find the cluster size */ | ||
619 | if (!strcmp(cache_name, "L2")) | ||
620 | cluster_cache_index = 2; | ||
621 | else if (!strcmp(cache_name, "L3")) | ||
622 | cluster_cache_index = 3; | ||
623 | else if (!strcmp(cache_name, "L1")) | ||
624 | cluster_cache_index = 1; | ||
625 | else if (!strcmp(cache_name, "ALL")) | ||
626 | cluster_cache_index = num_online_cpus(); | ||
627 | else | ||
628 | printk(KERN_INFO "Cluster '%s' is unknown.\n", cache_name); | ||
629 | |||
630 | return len; | ||
631 | } | ||
632 | |||
633 | #ifdef CONFIG_RELEASE_MASTER | ||
634 | static int proc_read_release_master(char *page, char **start, | ||
635 | off_t off, int count, | ||
636 | int *eof, void *data) | ||
637 | { | ||
638 | int len, master; | ||
639 | master = atomic_read(&release_master_cpu); | ||
640 | if (master == NO_CPU) | ||
641 | len = snprintf(page, PAGE_SIZE, "NO_CPU\n"); | ||
642 | else | ||
643 | len = snprintf(page, PAGE_SIZE, "%d\n", master); | ||
644 | return len; | ||
645 | } | ||
646 | |||
647 | static int proc_write_release_master(struct file *file, | ||
648 | const char *buffer, | ||
649 | unsigned long count, | ||
650 | void *data) | ||
651 | { | ||
652 | int cpu, err, online = 0; | ||
653 | char msg[64]; | ||
654 | |||
655 | if (count > 63) | ||
656 | return -EINVAL; | ||
657 | |||
658 | if (copy_from_user(msg, buffer, count)) | ||
659 | return -EFAULT; | ||
660 | |||
661 | /* terminate */ | ||
662 | msg[count] = '\0'; | ||
663 | /* chomp */ | ||
664 | if (count > 1 && msg[count - 1] == '\n') | ||
665 | msg[count - 1] = '\0'; | ||
666 | |||
667 | if (strcmp(msg, "NO_CPU") == 0) { | ||
668 | atomic_set(&release_master_cpu, NO_CPU); | ||
669 | return count; | ||
670 | } else { | ||
671 | err = sscanf(msg, "%d", &cpu); | ||
672 | if (err == 1 && cpu >= 0 && (online = cpu_online(cpu))) { | ||
673 | atomic_set(&release_master_cpu, cpu); | ||
674 | return count; | ||
675 | } else { | ||
676 | TRACE("invalid release master: '%s' " | ||
677 | "(err:%d cpu:%d online:%d)\n", | ||
678 | msg, err, cpu, online); | ||
679 | return -EINVAL; | ||
680 | } | ||
681 | } | ||
682 | } | ||
683 | #endif | ||
684 | |||
685 | static struct proc_dir_entry *litmus_dir = NULL, | ||
686 | *curr_file = NULL, | ||
687 | *stat_file = NULL, | ||
688 | *plugs_dir = NULL, | ||
689 | *plugs_file = NULL, | ||
690 | #ifdef CONFIG_RELEASE_MASTER | ||
691 | *release_master_file = NULL, | ||
692 | #endif | ||
693 | *clus_cache_idx_file = NULL; | ||
694 | |||
695 | static int __init init_litmus_proc(void) | ||
696 | { | ||
697 | litmus_dir = proc_mkdir("litmus", NULL); | ||
698 | if (!litmus_dir) { | ||
699 | printk(KERN_ERR "Could not allocate LITMUS^RT procfs entry.\n"); | ||
700 | return -ENOMEM; | ||
701 | } | ||
702 | |||
703 | curr_file = create_proc_entry("active_plugin", | ||
704 | 0644, litmus_dir); | ||
705 | if (!curr_file) { | ||
706 | printk(KERN_ERR "Could not allocate active_plugin " | ||
707 | "procfs entry.\n"); | ||
708 | return -ENOMEM; | ||
709 | } | ||
710 | curr_file->read_proc = proc_read_curr; | ||
711 | curr_file->write_proc = proc_write_curr; | ||
712 | |||
713 | #ifdef CONFIG_RELEASE_MASTER | ||
714 | release_master_file = create_proc_entry("release_master", | ||
715 | 0644, litmus_dir); | ||
716 | if (!release_master_file) { | ||
717 | printk(KERN_ERR "Could not allocate release_master " | ||
718 | "procfs entry.\n"); | ||
719 | return -ENOMEM; | ||
720 | } | ||
721 | release_master_file->read_proc = proc_read_release_master; | ||
722 | release_master_file->write_proc = proc_write_release_master; | ||
723 | #endif | ||
724 | |||
725 | clus_cache_idx_file = create_proc_entry("cluster_cache", | ||
726 | 0644, litmus_dir); | ||
727 | if (!clus_cache_idx_file) { | ||
728 | printk(KERN_ERR "Could not allocate cluster_cache " | ||
729 | "procfs entry.\n"); | ||
730 | return -ENOMEM; | ||
731 | } | ||
732 | clus_cache_idx_file->read_proc = proc_read_cluster_size; | ||
733 | clus_cache_idx_file->write_proc = proc_write_cluster_size; | ||
734 | |||
735 | stat_file = create_proc_read_entry("stats", 0444, litmus_dir, | ||
736 | proc_read_stats, NULL); | ||
737 | |||
738 | plugs_dir = proc_mkdir("plugins", litmus_dir); | ||
739 | if (!plugs_dir){ | ||
740 | printk(KERN_ERR "Could not allocate plugins directory " | ||
741 | "procfs entry.\n"); | ||
742 | return -ENOMEM; | ||
743 | } | ||
744 | |||
745 | plugs_file = create_proc_read_entry("loaded", 0444, plugs_dir, | ||
746 | proc_read_plugins, NULL); | ||
747 | |||
748 | return 0; | ||
749 | } | ||
750 | |||
751 | static void exit_litmus_proc(void) | ||
752 | { | ||
753 | if (plugs_file) | ||
754 | remove_proc_entry("loaded", plugs_dir); | ||
755 | if (plugs_dir) | ||
756 | remove_proc_entry("plugins", litmus_dir); | ||
757 | if (stat_file) | ||
758 | remove_proc_entry("stats", litmus_dir); | ||
759 | if (curr_file) | ||
760 | remove_proc_entry("active_plugin", litmus_dir); | ||
761 | if (clus_cache_idx_file) | ||
762 | remove_proc_entry("cluster_cache", litmus_dir); | ||
763 | #ifdef CONFIG_RELEASE_MASTER | ||
764 | if (release_master_file) | ||
765 | remove_proc_entry("release_master", litmus_dir); | ||
766 | #endif | ||
767 | if (litmus_dir) | ||
768 | remove_proc_entry("litmus", NULL); | ||
769 | } | ||
770 | |||
771 | long make_plugin_proc_dir(struct sched_plugin* plugin, | ||
772 | struct proc_dir_entry** pde_in) | ||
773 | { | ||
774 | struct proc_dir_entry *pde_new = NULL; | ||
775 | long rv; | ||
776 | |||
777 | if (!plugin || !plugin->plugin_name){ | ||
778 | printk(KERN_ERR "Invalid plugin struct passed to %s.\n", | ||
779 | __func__); | ||
780 | rv = -EINVAL; | ||
781 | goto out_no_pde; | ||
782 | } | ||
783 | |||
784 | if (!plugs_dir){ | ||
785 | printk(KERN_ERR "Could not make plugin sub-directory, because " | ||
786 | "/proc/litmus/plugins does not exist.\n"); | ||
787 | rv = -ENOENT; | ||
788 | goto out_no_pde; | ||
789 | } | ||
790 | |||
791 | pde_new = proc_mkdir(plugin->plugin_name, plugs_dir); | ||
792 | if (!pde_new){ | ||
793 | printk(KERN_ERR "Could not make plugin sub-directory: " | ||
794 | "out of memory?.\n"); | ||
795 | rv = -ENOMEM; | ||
796 | goto out_no_pde; | ||
797 | } | ||
798 | |||
799 | rv = 0; | ||
800 | *pde_in = pde_new; | ||
801 | goto out_ok; | ||
802 | |||
803 | out_no_pde: | ||
804 | *pde_in = NULL; | ||
805 | out_ok: | ||
806 | return rv; | ||
807 | } | ||
808 | |||
809 | void remove_plugin_proc_dir(struct sched_plugin* plugin) | ||
810 | { | ||
811 | if (!plugin || !plugin->plugin_name){ | ||
812 | printk(KERN_ERR "Invalid plugin struct passed to %s.\n", | ||
813 | __func__); | ||
814 | return; | ||
815 | } | ||
816 | remove_proc_entry(plugin->plugin_name, plugs_dir); | ||
817 | } | ||
818 | |||
819 | extern struct sched_plugin linux_sched_plugin; | 510 | extern struct sched_plugin linux_sched_plugin; |
820 | 511 | ||
821 | static int __init _init_litmus(void) | 512 | static int __init _init_litmus(void) |
diff --git a/litmus/litmus_proc.c b/litmus/litmus_proc.c new file mode 100644 index 000000000000..ee0ad56d445c --- /dev/null +++ b/litmus/litmus_proc.c | |||
@@ -0,0 +1,324 @@ | |||
1 | /* | ||
2 | * litmus_proc.c -- Implementation of the /proc/litmus directory tree. | ||
3 | */ | ||
4 | |||
5 | #include <linux/uaccess.h> | ||
6 | |||
7 | #include <litmus/litmus_proc.h> | ||
8 | |||
9 | /* in litmus/litmus.c */ | ||
10 | extern atomic_t rt_task_count; | ||
11 | |||
12 | static struct proc_dir_entry *litmus_dir = NULL, | ||
13 | *curr_file = NULL, | ||
14 | *stat_file = NULL, | ||
15 | *plugs_dir = NULL, | ||
16 | *plugs_file = NULL, | ||
17 | #ifdef CONFIG_RELEASE_MASTER | ||
18 | *release_master_file = NULL, | ||
19 | #endif | ||
20 | *clus_cache_idx_file = NULL; | ||
21 | |||
22 | /* in litmus/sync.c */ | ||
23 | int count_tasks_waiting_for_release(void); | ||
24 | |||
25 | static int proc_read_stats(char *page, char **start, | ||
26 | off_t off, int count, | ||
27 | int *eof, void *data) | ||
28 | { | ||
29 | int len; | ||
30 | |||
31 | len = snprintf(page, PAGE_SIZE, | ||
32 | "real-time tasks = %d\n" | ||
33 | "ready for release = %d\n", | ||
34 | atomic_read(&rt_task_count), | ||
35 | count_tasks_waiting_for_release()); | ||
36 | return len; | ||
37 | } | ||
38 | |||
39 | static int proc_read_plugins(char *page, char **start, | ||
40 | off_t off, int count, | ||
41 | int *eof, void *data) | ||
42 | { | ||
43 | int len; | ||
44 | |||
45 | len = print_sched_plugins(page, PAGE_SIZE); | ||
46 | return len; | ||
47 | } | ||
48 | |||
49 | static int proc_read_curr(char *page, char **start, | ||
50 | off_t off, int count, | ||
51 | int *eof, void *data) | ||
52 | { | ||
53 | int len; | ||
54 | |||
55 | len = snprintf(page, PAGE_SIZE, "%s\n", litmus->plugin_name); | ||
56 | return len; | ||
57 | } | ||
58 | |||
59 | /* in litmus/litmus.c */ | ||
60 | int switch_sched_plugin(struct sched_plugin*); | ||
61 | |||
62 | static int proc_write_curr(struct file *file, | ||
63 | const char *buffer, | ||
64 | unsigned long count, | ||
65 | void *data) | ||
66 | { | ||
67 | int len, ret; | ||
68 | char name[65]; | ||
69 | struct sched_plugin* found; | ||
70 | |||
71 | if(count > 64) | ||
72 | len = 64; | ||
73 | else | ||
74 | len = count; | ||
75 | |||
76 | if(copy_from_user(name, buffer, len)) | ||
77 | return -EFAULT; | ||
78 | |||
79 | name[len] = '\0'; | ||
80 | /* chomp name */ | ||
81 | if (len > 1 && name[len - 1] == '\n') | ||
82 | name[len - 1] = '\0'; | ||
83 | |||
84 | found = find_sched_plugin(name); | ||
85 | |||
86 | if (found) { | ||
87 | ret = switch_sched_plugin(found); | ||
88 | if (ret != 0) | ||
89 | printk(KERN_INFO "Could not switch plugin: %d\n", ret); | ||
90 | } else | ||
91 | printk(KERN_INFO "Plugin '%s' is unknown.\n", name); | ||
92 | |||
93 | return len; | ||
94 | } | ||
95 | |||
96 | static int proc_read_cluster_size(char *page, char **start, | ||
97 | off_t off, int count, | ||
98 | int *eof, void *data) | ||
99 | { | ||
100 | int len; | ||
101 | if (cluster_cache_index == 2) | ||
102 | len = snprintf(page, PAGE_SIZE, "L2\n"); | ||
103 | else if (cluster_cache_index == 3) | ||
104 | len = snprintf(page, PAGE_SIZE, "L3\n"); | ||
105 | else if (cluster_cache_index == 1) | ||
106 | len = snprintf(page, PAGE_SIZE, "L1\n"); | ||
107 | else | ||
108 | len = snprintf(page, PAGE_SIZE, "ALL\n"); | ||
109 | |||
110 | return len; | ||
111 | } | ||
112 | |||
113 | static int proc_write_cluster_size(struct file *file, | ||
114 | const char *buffer, | ||
115 | unsigned long count, | ||
116 | void *data) | ||
117 | { | ||
118 | int len; | ||
119 | /* L2, L3 */ | ||
120 | char cache_name[33]; | ||
121 | |||
122 | if(count > 32) | ||
123 | len = 32; | ||
124 | else | ||
125 | len = count; | ||
126 | |||
127 | if(copy_from_user(cache_name, buffer, len)) | ||
128 | return -EFAULT; | ||
129 | |||
130 | cache_name[len] = '\0'; | ||
131 | /* chomp name */ | ||
132 | if (len > 1 && cache_name[len - 1] == '\n') | ||
133 | cache_name[len - 1] = '\0'; | ||
134 | |||
135 | /* do a quick and dirty comparison to find the cluster size */ | ||
136 | if (!strcmp(cache_name, "L2")) | ||
137 | cluster_cache_index = 2; | ||
138 | else if (!strcmp(cache_name, "L3")) | ||
139 | cluster_cache_index = 3; | ||
140 | else if (!strcmp(cache_name, "L1")) | ||
141 | cluster_cache_index = 1; | ||
142 | else if (!strcmp(cache_name, "ALL")) | ||
143 | cluster_cache_index = num_online_cpus(); | ||
144 | else | ||
145 | printk(KERN_INFO "Cluster '%s' is unknown.\n", cache_name); | ||
146 | |||
147 | return len; | ||
148 | } | ||
149 | |||
150 | #ifdef CONFIG_RELEASE_MASTER | ||
151 | static int proc_read_release_master(char *page, char **start, | ||
152 | off_t off, int count, | ||
153 | int *eof, void *data) | ||
154 | { | ||
155 | int len, master; | ||
156 | master = atomic_read(&release_master_cpu); | ||
157 | if (master == NO_CPU) | ||
158 | len = snprintf(page, PAGE_SIZE, "NO_CPU\n"); | ||
159 | else | ||
160 | len = snprintf(page, PAGE_SIZE, "%d\n", master); | ||
161 | return len; | ||
162 | } | ||
163 | |||
164 | static int proc_write_release_master(struct file *file, | ||
165 | const char *buffer, | ||
166 | unsigned long count, | ||
167 | void *data) | ||
168 | { | ||
169 | int cpu, err, online = 0; | ||
170 | char msg[64]; | ||
171 | |||
172 | if (count > 63) | ||
173 | return -EINVAL; | ||
174 | |||
175 | if (copy_from_user(msg, buffer, count)) | ||
176 | return -EFAULT; | ||
177 | |||
178 | /* terminate */ | ||
179 | msg[count] = '\0'; | ||
180 | /* chomp */ | ||
181 | if (count > 1 && msg[count - 1] == '\n') | ||
182 | msg[count - 1] = '\0'; | ||
183 | |||
184 | if (strcmp(msg, "NO_CPU") == 0) { | ||
185 | atomic_set(&release_master_cpu, NO_CPU); | ||
186 | return count; | ||
187 | } else { | ||
188 | err = sscanf(msg, "%d", &cpu); | ||
189 | if (err == 1 && cpu >= 0 && (online = cpu_online(cpu))) { | ||
190 | atomic_set(&release_master_cpu, cpu); | ||
191 | return count; | ||
192 | } else { | ||
193 | TRACE("invalid release master: '%s' " | ||
194 | "(err:%d cpu:%d online:%d)\n", | ||
195 | msg, err, cpu, online); | ||
196 | return -EINVAL; | ||
197 | } | ||
198 | } | ||
199 | } | ||
200 | #endif | ||
201 | |||
202 | int __init init_litmus_proc(void) | ||
203 | { | ||
204 | litmus_dir = proc_mkdir("litmus", NULL); | ||
205 | if (!litmus_dir) { | ||
206 | printk(KERN_ERR "Could not allocate LITMUS^RT procfs entry.\n"); | ||
207 | return -ENOMEM; | ||
208 | } | ||
209 | |||
210 | curr_file = create_proc_entry("active_plugin", | ||
211 | 0644, litmus_dir); | ||
212 | if (!curr_file) { | ||
213 | printk(KERN_ERR "Could not allocate active_plugin " | ||
214 | "procfs entry.\n"); | ||
215 | return -ENOMEM; | ||
216 | } | ||
217 | curr_file->read_proc = proc_read_curr; | ||
218 | curr_file->write_proc = proc_write_curr; | ||
219 | |||
220 | #ifdef CONFIG_RELEASE_MASTER | ||
221 | release_master_file = create_proc_entry("release_master", | ||
222 | 0644, litmus_dir); | ||
223 | if (!release_master_file) { | ||
224 | printk(KERN_ERR "Could not allocate release_master " | ||
225 | "procfs entry.\n"); | ||
226 | return -ENOMEM; | ||
227 | } | ||
228 | release_master_file->read_proc = proc_read_release_master; | ||
229 | release_master_file->write_proc = proc_write_release_master; | ||
230 | #endif | ||
231 | |||
232 | clus_cache_idx_file = create_proc_entry("cluster_cache", | ||
233 | 0644, litmus_dir); | ||
234 | if (!clus_cache_idx_file) { | ||
235 | printk(KERN_ERR "Could not allocate cluster_cache " | ||
236 | "procfs entry.\n"); | ||
237 | return -ENOMEM; | ||
238 | } | ||
239 | clus_cache_idx_file->read_proc = proc_read_cluster_size; | ||
240 | clus_cache_idx_file->write_proc = proc_write_cluster_size; | ||
241 | |||
242 | stat_file = create_proc_read_entry("stats", 0444, litmus_dir, | ||
243 | proc_read_stats, NULL); | ||
244 | |||
245 | plugs_dir = proc_mkdir("plugins", litmus_dir); | ||
246 | if (!plugs_dir){ | ||
247 | printk(KERN_ERR "Could not allocate plugins directory " | ||
248 | "procfs entry.\n"); | ||
249 | return -ENOMEM; | ||
250 | } | ||
251 | |||
252 | plugs_file = create_proc_read_entry("loaded", 0444, plugs_dir, | ||
253 | proc_read_plugins, NULL); | ||
254 | |||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | void exit_litmus_proc(void) | ||
259 | { | ||
260 | if (plugs_file) | ||
261 | remove_proc_entry("loaded", plugs_dir); | ||
262 | if (plugs_dir) | ||
263 | remove_proc_entry("plugins", litmus_dir); | ||
264 | if (stat_file) | ||
265 | remove_proc_entry("stats", litmus_dir); | ||
266 | if (curr_file) | ||
267 | remove_proc_entry("active_plugin", litmus_dir); | ||
268 | if (clus_cache_idx_file) | ||
269 | remove_proc_entry("cluster_cache", litmus_dir); | ||
270 | #ifdef CONFIG_RELEASE_MASTER | ||
271 | if (release_master_file) | ||
272 | remove_proc_entry("release_master", litmus_dir); | ||
273 | #endif | ||
274 | if (litmus_dir) | ||
275 | remove_proc_entry("litmus", NULL); | ||
276 | } | ||
277 | |||
278 | long make_plugin_proc_dir(struct sched_plugin* plugin, | ||
279 | struct proc_dir_entry** pde_in) | ||
280 | { | ||
281 | struct proc_dir_entry *pde_new = NULL; | ||
282 | long rv; | ||
283 | |||
284 | if (!plugin || !plugin->plugin_name){ | ||
285 | printk(KERN_ERR "Invalid plugin struct passed to %s.\n", | ||
286 | __func__); | ||
287 | rv = -EINVAL; | ||
288 | goto out_no_pde; | ||
289 | } | ||
290 | |||
291 | if (!plugs_dir){ | ||
292 | printk(KERN_ERR "Could not make plugin sub-directory, because " | ||
293 | "/proc/litmus/plugins does not exist.\n"); | ||
294 | rv = -ENOENT; | ||
295 | goto out_no_pde; | ||
296 | } | ||
297 | |||
298 | pde_new = proc_mkdir(plugin->plugin_name, plugs_dir); | ||
299 | if (!pde_new){ | ||
300 | printk(KERN_ERR "Could not make plugin sub-directory: " | ||
301 | "out of memory?.\n"); | ||
302 | rv = -ENOMEM; | ||
303 | goto out_no_pde; | ||
304 | } | ||
305 | |||
306 | rv = 0; | ||
307 | *pde_in = pde_new; | ||
308 | goto out_ok; | ||
309 | |||
310 | out_no_pde: | ||
311 | *pde_in = NULL; | ||
312 | out_ok: | ||
313 | return rv; | ||
314 | } | ||
315 | |||
316 | void remove_plugin_proc_dir(struct sched_plugin* plugin) | ||
317 | { | ||
318 | if (!plugin || !plugin->plugin_name){ | ||
319 | printk(KERN_ERR "Invalid plugin struct passed to %s.\n", | ||
320 | __func__); | ||
321 | return; | ||
322 | } | ||
323 | remove_proc_entry(plugin->plugin_name, plugs_dir); | ||
324 | } | ||