aboutsummaryrefslogtreecommitdiffstats
path: root/litmus/litmus_proc.c
diff options
context:
space:
mode:
authorBjoern Brandenburg <bbb@mpi-sws.org>2013-06-25 01:27:07 -0400
committerBjoern Brandenburg <bbb@mpi-sws.org>2013-08-07 03:46:49 -0400
commit543810eb67bea9c3046ecb58388493bca39fe796 (patch)
treecf65010367e53dfbd3e39a9eb6e89dacf92348f3 /litmus/litmus_proc.c
parent1412c8b72e192a14b8dd620f58a75f55a5490783 (diff)
Add LITMUS^RT core implementation
This patch adds the core of LITMUS^RT: - library functionality (heaps, rt_domain, prioritization, etc.) - budget enforcement logic - job management - system call backends - virtual devices (control page, etc.) - scheduler plugin API (and dummy plugin) This code compiles, but is not yet integrated with the rest of Linux.
Diffstat (limited to 'litmus/litmus_proc.c')
-rw-r--r--litmus/litmus_proc.c407
1 files changed, 407 insertions, 0 deletions
diff --git a/litmus/litmus_proc.c b/litmus/litmus_proc.c
new file mode 100644
index 000000000000..1ebf1277f5d3
--- /dev/null
+++ b/litmus/litmus_proc.c
@@ -0,0 +1,407 @@
1/*
2 * litmus_proc.c -- Implementation of the /proc/litmus directory tree.
3 */
4
5#include <linux/sched.h>
6#include <linux/uaccess.h>
7#include <linux/seq_file.h>
8
9#include <litmus/litmus.h>
10#include <litmus/litmus_proc.h>
11
12#include <litmus/clustered.h>
13
14/* in litmus/litmus.c */
15extern atomic_t rt_task_count;
16
17static struct proc_dir_entry *litmus_dir = NULL,
18 *curr_file = NULL,
19 *stat_file = NULL,
20 *plugs_dir = NULL,
21#ifdef CONFIG_RELEASE_MASTER
22 *release_master_file = NULL,
23#endif
24 *plugs_file = NULL;
25
26/* in litmus/sync.c */
27int count_tasks_waiting_for_release(void);
28
29static int litmus_stats_proc_show(struct seq_file *m, void *v)
30{
31 seq_printf(m,
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 0;
37}
38
39static int litmus_stats_proc_open(struct inode *inode, struct file *file)
40{
41 return single_open(file, litmus_stats_proc_show, PDE_DATA(inode));
42}
43
44static const struct file_operations litmus_stats_proc_fops = {
45 .open = litmus_stats_proc_open,
46 .read = seq_read,
47 .llseek = seq_lseek,
48 .release = single_release,
49};
50
51
52static int litmus_loaded_proc_show(struct seq_file *m, void *v)
53{
54 print_sched_plugins(m);
55 return 0;
56}
57
58static int litmus_loaded_proc_open(struct inode *inode, struct file *file)
59{
60 return single_open(file, litmus_loaded_proc_show, PDE_DATA(inode));
61}
62
63static const struct file_operations litmus_loaded_proc_fops = {
64 .open = litmus_loaded_proc_open,
65 .read = seq_read,
66 .llseek = seq_lseek,
67 .release = single_release,
68};
69
70
71
72
73/* in litmus/litmus.c */
74int switch_sched_plugin(struct sched_plugin*);
75
76static ssize_t litmus_active_proc_write(struct file *file,
77 const char __user *buffer, size_t count,
78 loff_t *ppos)
79{
80 char name[65];
81 struct sched_plugin* found;
82 ssize_t ret = -EINVAL;
83 int err;
84
85
86 ret = copy_and_chomp(name, sizeof(name), buffer, count);
87 if (ret < 0)
88 return ret;
89
90 found = find_sched_plugin(name);
91
92 if (found) {
93 err = switch_sched_plugin(found);
94 if (err) {
95 printk(KERN_INFO "Could not switch plugin: %d\n", err);
96 ret = err;
97 }
98 } else {
99 printk(KERN_INFO "Plugin '%s' is unknown.\n", name);
100 ret = -ESRCH;
101 }
102
103 return ret;
104}
105
106static int litmus_active_proc_show(struct seq_file *m, void *v)
107{
108 seq_printf(m, "%s\n", litmus->plugin_name);
109 return 0;
110}
111
112static int litmus_active_proc_open(struct inode *inode, struct file *file)
113{
114 return single_open(file, litmus_active_proc_show, PDE_DATA(inode));
115}
116
117static const struct file_operations litmus_active_proc_fops = {
118 .open = litmus_active_proc_open,
119 .read = seq_read,
120 .llseek = seq_lseek,
121 .release = single_release,
122 .write = litmus_active_proc_write,
123};
124
125
126#ifdef CONFIG_RELEASE_MASTER
127static ssize_t litmus_release_master_proc_write(
128 struct file *file,
129 const char __user *buffer, size_t count,
130 loff_t *ppos)
131{
132 int cpu, err, online = 0;
133 char msg[64];
134 ssize_t len;
135
136 len = copy_and_chomp(msg, sizeof(msg), buffer, count);
137
138 if (len < 0)
139 return len;
140
141 if (strcmp(msg, "NO_CPU") == 0)
142 atomic_set(&release_master_cpu, NO_CPU);
143 else {
144 err = sscanf(msg, "%d", &cpu);
145 if (err == 1 && cpu >= 0 && (online = cpu_online(cpu))) {
146 atomic_set(&release_master_cpu, cpu);
147 } else {
148 TRACE("invalid release master: '%s' "
149 "(err:%d cpu:%d online:%d)\n",
150 msg, err, cpu, online);
151 len = -EINVAL;
152 }
153 }
154 return len;
155}
156
157static int litmus_release_master_proc_show(struct seq_file *m, void *v)
158{
159 int master;
160 master = atomic_read(&release_master_cpu);
161 if (master == NO_CPU)
162 seq_printf(m, "NO_CPU\n");
163 else
164 seq_printf(m, "%d\n", master);
165 return 0;
166}
167
168static int litmus_release_master_proc_open(struct inode *inode, struct file *file)
169{
170 return single_open(file, litmus_release_master_proc_show, PDE_DATA(inode));
171}
172
173static const struct file_operations litmus_release_master_proc_fops = {
174 .open = litmus_release_master_proc_open,
175 .read = seq_read,
176 .llseek = seq_lseek,
177 .release = single_release,
178 .write = litmus_release_master_proc_write,
179};
180#endif
181
182int __init init_litmus_proc(void)
183{
184 litmus_dir = proc_mkdir("litmus", NULL);
185 if (!litmus_dir) {
186 printk(KERN_ERR "Could not allocate LITMUS^RT procfs entry.\n");
187 return -ENOMEM;
188 }
189
190 curr_file = proc_create("active_plugin", 0644, litmus_dir,
191 &litmus_active_proc_fops);
192
193 if (!curr_file) {
194 printk(KERN_ERR "Could not allocate active_plugin "
195 "procfs entry.\n");
196 return -ENOMEM;
197 }
198
199#ifdef CONFIG_RELEASE_MASTER
200 release_master_file = proc_create("release_master", 0644, litmus_dir,
201 &litmus_release_master_proc_fops);
202 if (!release_master_file) {
203 printk(KERN_ERR "Could not allocate release_master "
204 "procfs entry.\n");
205 return -ENOMEM;
206 }
207#endif
208
209 stat_file = proc_create("stats", 0444, litmus_dir, &litmus_stats_proc_fops);
210
211 plugs_dir = proc_mkdir("plugins", litmus_dir);
212 if (!plugs_dir){
213 printk(KERN_ERR "Could not allocate plugins directory "
214 "procfs entry.\n");
215 return -ENOMEM;
216 }
217
218 plugs_file = proc_create("loaded", 0444, plugs_dir,
219 &litmus_loaded_proc_fops);
220
221 return 0;
222}
223
224void exit_litmus_proc(void)
225{
226 if (plugs_file)
227 remove_proc_entry("loaded", plugs_dir);
228 if (plugs_dir)
229 remove_proc_entry("plugins", litmus_dir);
230 if (stat_file)
231 remove_proc_entry("stats", litmus_dir);
232 if (curr_file)
233 remove_proc_entry("active_plugin", litmus_dir);
234#ifdef CONFIG_RELEASE_MASTER
235 if (release_master_file)
236 remove_proc_entry("release_master", litmus_dir);
237#endif
238 if (litmus_dir)
239 remove_proc_entry("litmus", NULL);
240}
241
242long make_plugin_proc_dir(struct sched_plugin* plugin,
243 struct proc_dir_entry** pde_in)
244{
245 struct proc_dir_entry *pde_new = NULL;
246 long rv;
247
248 if (!plugin || !plugin->plugin_name){
249 printk(KERN_ERR "Invalid plugin struct passed to %s.\n",
250 __func__);
251 rv = -EINVAL;
252 goto out_no_pde;
253 }
254
255 if (!plugs_dir){
256 printk(KERN_ERR "Could not make plugin sub-directory, because "
257 "/proc/litmus/plugins does not exist.\n");
258 rv = -ENOENT;
259 goto out_no_pde;
260 }
261
262 pde_new = proc_mkdir(plugin->plugin_name, plugs_dir);
263 if (!pde_new){
264 printk(KERN_ERR "Could not make plugin sub-directory: "
265 "out of memory?.\n");
266 rv = -ENOMEM;
267 goto out_no_pde;
268 }
269
270 rv = 0;
271 *pde_in = pde_new;
272 goto out_ok;
273
274out_no_pde:
275 *pde_in = NULL;
276out_ok:
277 return rv;
278}
279
280void remove_plugin_proc_dir(struct sched_plugin* plugin)
281{
282 if (!plugin || !plugin->plugin_name){
283 printk(KERN_ERR "Invalid plugin struct passed to %s.\n",
284 __func__);
285 return;
286 }
287 remove_proc_entry(plugin->plugin_name, plugs_dir);
288}
289
290
291
292/* misc. I/O helper functions */
293
294int copy_and_chomp(char *kbuf, unsigned long ksize,
295 __user const char* ubuf, unsigned long ulength)
296{
297 /* caller must provide buffer space */
298 BUG_ON(!ksize);
299
300 ksize--; /* leave space for null byte */
301
302 if (ksize > ulength)
303 ksize = ulength;
304
305 if(copy_from_user(kbuf, ubuf, ksize))
306 return -EFAULT;
307
308 kbuf[ksize] = '\0';
309
310 /* chomp kbuf */
311 if (ksize > 0 && kbuf[ksize - 1] == '\n')
312 kbuf[ksize - 1] = '\0';
313
314 return ksize;
315}
316
317/* helper functions for clustered plugins */
318static const char* cache_level_names[] = {
319 "ALL",
320 "L1",
321 "L2",
322 "L3",
323};
324
325int parse_cache_level(const char *cache_name, enum cache_level *level)
326{
327 int err = -EINVAL;
328 int i;
329 /* do a quick and dirty comparison to find the cluster size */
330 for (i = GLOBAL_CLUSTER; i <= L3_CLUSTER; i++)
331 if (!strcmp(cache_name, cache_level_names[i])) {
332 *level = (enum cache_level) i;
333 err = 0;
334 break;
335 }
336 return err;
337}
338
339const char* cache_level_name(enum cache_level level)
340{
341 int idx = level;
342
343 if (idx >= GLOBAL_CLUSTER && idx <= L3_CLUSTER)
344 return cache_level_names[idx];
345 else
346 return "INVALID";
347}
348
349
350
351
352/* proc file interface to configure the cluster size */
353
354static ssize_t litmus_cluster_proc_write(struct file *file,
355 const char __user *buffer, size_t count,
356 loff_t *ppos)
357{
358 enum cache_level *level = (enum cache_level *) PDE_DATA(file_inode(file));
359 ssize_t len;
360 char cache_name[8];
361
362 len = copy_and_chomp(cache_name, sizeof(cache_name), buffer, count);
363
364 if (len > 0 && parse_cache_level(cache_name, level)) {
365 printk(KERN_INFO "Cluster '%s' is unknown.\n", cache_name);
366 len = -EINVAL;
367 }
368
369 return len;
370}
371
372static int litmus_cluster_proc_show(struct seq_file *m, void *v)
373{
374 enum cache_level *level = (enum cache_level *) m->private;
375
376 seq_printf(m, "%s\n", cache_level_name(*level));
377 return 0;
378}
379
380static int litmus_cluster_proc_open(struct inode *inode, struct file *file)
381{
382 return single_open(file, litmus_cluster_proc_show, PDE_DATA(inode));
383}
384
385static const struct file_operations litmus_cluster_proc_fops = {
386 .open = litmus_cluster_proc_open,
387 .read = seq_read,
388 .llseek = seq_lseek,
389 .release = single_release,
390 .write = litmus_cluster_proc_write,
391};
392
393struct proc_dir_entry* create_cluster_file(struct proc_dir_entry* parent,
394 enum cache_level* level)
395{
396 struct proc_dir_entry* cluster_file;
397
398
399 cluster_file = proc_create_data("cluster", 0644, parent,
400 &litmus_cluster_proc_fops,
401 (void *) level);
402 if (!cluster_file) {
403 printk(KERN_ERR
404 "Could not cluster procfs entry.\n");
405 }
406 return cluster_file;
407}