diff options
author | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-19 17:31:52 -0400 |
---|---|---|
committer | Jonathan Herman <hermanjl@cs.unc.edu> | 2013-04-19 17:31:52 -0400 |
commit | f70a290e8a889caa905ab7650c696f2bb299be1a (patch) | |
tree | 56f0886d839499e9f522f189999024b3e86f9be2 /litmus/litmus_proc.c | |
parent | fcc9d2e5a6c89d22b8b773a64fb4ad21ac318446 (diff) | |
parent | 7ef4a793a624c6e66c16ca1051847f75161f5bec (diff) |
Merge branch 'wip-nested-locking' into tegra-nested-lockingwip-nested-locking
Conflicts:
Makefile
include/linux/fs.h
Diffstat (limited to 'litmus/litmus_proc.c')
-rw-r--r-- | litmus/litmus_proc.c | 347 |
1 files changed, 347 insertions, 0 deletions
diff --git a/litmus/litmus_proc.c b/litmus/litmus_proc.c new file mode 100644 index 00000000000..4bf725a36c9 --- /dev/null +++ b/litmus/litmus_proc.c | |||
@@ -0,0 +1,347 @@ | |||
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 | |||
8 | #include <litmus/litmus.h> | ||
9 | #include <litmus/litmus_proc.h> | ||
10 | |||
11 | #include <litmus/clustered.h> | ||
12 | |||
13 | /* in litmus/litmus.c */ | ||
14 | extern atomic_t rt_task_count; | ||
15 | |||
16 | static struct proc_dir_entry *litmus_dir = NULL, | ||
17 | *curr_file = NULL, | ||
18 | *stat_file = NULL, | ||
19 | *plugs_dir = NULL, | ||
20 | #ifdef CONFIG_RELEASE_MASTER | ||
21 | *release_master_file = NULL, | ||
22 | #endif | ||
23 | *plugs_file = NULL; | ||
24 | |||
25 | /* in litmus/sync.c */ | ||
26 | int count_tasks_waiting_for_release(void); | ||
27 | |||
28 | static int proc_read_stats(char *page, char **start, | ||
29 | off_t off, int count, | ||
30 | int *eof, void *data) | ||
31 | { | ||
32 | int len; | ||
33 | |||
34 | len = snprintf(page, PAGE_SIZE, | ||
35 | "real-time tasks = %d\n" | ||
36 | "ready for release = %d\n", | ||
37 | atomic_read(&rt_task_count), | ||
38 | count_tasks_waiting_for_release()); | ||
39 | return len; | ||
40 | } | ||
41 | |||
42 | static int proc_read_plugins(char *page, char **start, | ||
43 | off_t off, int count, | ||
44 | int *eof, void *data) | ||
45 | { | ||
46 | int len; | ||
47 | |||
48 | len = print_sched_plugins(page, PAGE_SIZE); | ||
49 | return len; | ||
50 | } | ||
51 | |||
52 | static int proc_read_curr(char *page, char **start, | ||
53 | off_t off, int count, | ||
54 | int *eof, void *data) | ||
55 | { | ||
56 | int len; | ||
57 | |||
58 | len = snprintf(page, PAGE_SIZE, "%s\n", litmus->plugin_name); | ||
59 | return len; | ||
60 | } | ||
61 | |||
62 | /* in litmus/litmus.c */ | ||
63 | int switch_sched_plugin(struct sched_plugin*); | ||
64 | |||
65 | static int proc_write_curr(struct file *file, | ||
66 | const char *buffer, | ||
67 | unsigned long count, | ||
68 | void *data) | ||
69 | { | ||
70 | int len, ret; | ||
71 | char name[65]; | ||
72 | struct sched_plugin* found; | ||
73 | |||
74 | len = copy_and_chomp(name, sizeof(name), buffer, count); | ||
75 | if (len < 0) | ||
76 | return len; | ||
77 | |||
78 | found = find_sched_plugin(name); | ||
79 | |||
80 | if (found) { | ||
81 | ret = switch_sched_plugin(found); | ||
82 | if (ret != 0) | ||
83 | printk(KERN_INFO "Could not switch plugin: %d\n", ret); | ||
84 | } else | ||
85 | printk(KERN_INFO "Plugin '%s' is unknown.\n", name); | ||
86 | |||
87 | return len; | ||
88 | } | ||
89 | |||
90 | #ifdef CONFIG_RELEASE_MASTER | ||
91 | static int proc_read_release_master(char *page, char **start, | ||
92 | off_t off, int count, | ||
93 | int *eof, void *data) | ||
94 | { | ||
95 | int len, master; | ||
96 | master = atomic_read(&release_master_cpu); | ||
97 | if (master == NO_CPU) | ||
98 | len = snprintf(page, PAGE_SIZE, "NO_CPU\n"); | ||
99 | else | ||
100 | len = snprintf(page, PAGE_SIZE, "%d\n", master); | ||
101 | return len; | ||
102 | } | ||
103 | |||
104 | static int proc_write_release_master(struct file *file, | ||
105 | const char *buffer, | ||
106 | unsigned long count, | ||
107 | void *data) | ||
108 | { | ||
109 | int cpu, err, len, online = 0; | ||
110 | char msg[64]; | ||
111 | |||
112 | len = copy_and_chomp(msg, sizeof(msg), buffer, count); | ||
113 | |||
114 | if (len < 0) | ||
115 | return len; | ||
116 | |||
117 | if (strcmp(msg, "NO_CPU") == 0) | ||
118 | atomic_set(&release_master_cpu, NO_CPU); | ||
119 | else { | ||
120 | err = sscanf(msg, "%d", &cpu); | ||
121 | if (err == 1 && cpu >= 0 && (online = cpu_online(cpu))) { | ||
122 | atomic_set(&release_master_cpu, cpu); | ||
123 | } else { | ||
124 | TRACE("invalid release master: '%s' " | ||
125 | "(err:%d cpu:%d online:%d)\n", | ||
126 | msg, err, cpu, online); | ||
127 | len = -EINVAL; | ||
128 | } | ||
129 | } | ||
130 | return len; | ||
131 | } | ||
132 | #endif | ||
133 | |||
134 | int __init init_litmus_proc(void) | ||
135 | { | ||
136 | litmus_dir = proc_mkdir("litmus", NULL); | ||
137 | if (!litmus_dir) { | ||
138 | printk(KERN_ERR "Could not allocate LITMUS^RT procfs entry.\n"); | ||
139 | return -ENOMEM; | ||
140 | } | ||
141 | |||
142 | curr_file = create_proc_entry("active_plugin", | ||
143 | 0644, litmus_dir); | ||
144 | if (!curr_file) { | ||
145 | printk(KERN_ERR "Could not allocate active_plugin " | ||
146 | "procfs entry.\n"); | ||
147 | return -ENOMEM; | ||
148 | } | ||
149 | curr_file->read_proc = proc_read_curr; | ||
150 | curr_file->write_proc = proc_write_curr; | ||
151 | |||
152 | #ifdef CONFIG_RELEASE_MASTER | ||
153 | release_master_file = create_proc_entry("release_master", | ||
154 | 0644, litmus_dir); | ||
155 | if (!release_master_file) { | ||
156 | printk(KERN_ERR "Could not allocate release_master " | ||
157 | "procfs entry.\n"); | ||
158 | return -ENOMEM; | ||
159 | } | ||
160 | release_master_file->read_proc = proc_read_release_master; | ||
161 | release_master_file->write_proc = proc_write_release_master; | ||
162 | #endif | ||
163 | |||
164 | stat_file = create_proc_read_entry("stats", 0444, litmus_dir, | ||
165 | proc_read_stats, NULL); | ||
166 | |||
167 | plugs_dir = proc_mkdir("plugins", litmus_dir); | ||
168 | if (!plugs_dir){ | ||
169 | printk(KERN_ERR "Could not allocate plugins directory " | ||
170 | "procfs entry.\n"); | ||
171 | return -ENOMEM; | ||
172 | } | ||
173 | |||
174 | plugs_file = create_proc_read_entry("loaded", 0444, plugs_dir, | ||
175 | proc_read_plugins, NULL); | ||
176 | |||
177 | return 0; | ||
178 | } | ||
179 | |||
180 | void exit_litmus_proc(void) | ||
181 | { | ||
182 | if (plugs_file) | ||
183 | remove_proc_entry("loaded", plugs_dir); | ||
184 | if (plugs_dir) | ||
185 | remove_proc_entry("plugins", litmus_dir); | ||
186 | if (stat_file) | ||
187 | remove_proc_entry("stats", litmus_dir); | ||
188 | if (curr_file) | ||
189 | remove_proc_entry("active_plugin", litmus_dir); | ||
190 | #ifdef CONFIG_RELEASE_MASTER | ||
191 | if (release_master_file) | ||
192 | remove_proc_entry("release_master", litmus_dir); | ||
193 | #endif | ||
194 | if (litmus_dir) | ||
195 | remove_proc_entry("litmus", NULL); | ||
196 | } | ||
197 | |||
198 | long make_plugin_proc_dir(struct sched_plugin* plugin, | ||
199 | struct proc_dir_entry** pde_in) | ||
200 | { | ||
201 | struct proc_dir_entry *pde_new = NULL; | ||
202 | long rv; | ||
203 | |||
204 | if (!plugin || !plugin->plugin_name){ | ||
205 | printk(KERN_ERR "Invalid plugin struct passed to %s.\n", | ||
206 | __func__); | ||
207 | rv = -EINVAL; | ||
208 | goto out_no_pde; | ||
209 | } | ||
210 | |||
211 | if (!plugs_dir){ | ||
212 | printk(KERN_ERR "Could not make plugin sub-directory, because " | ||
213 | "/proc/litmus/plugins does not exist.\n"); | ||
214 | rv = -ENOENT; | ||
215 | goto out_no_pde; | ||
216 | } | ||
217 | |||
218 | pde_new = proc_mkdir(plugin->plugin_name, plugs_dir); | ||
219 | if (!pde_new){ | ||
220 | printk(KERN_ERR "Could not make plugin sub-directory: " | ||
221 | "out of memory?.\n"); | ||
222 | rv = -ENOMEM; | ||
223 | goto out_no_pde; | ||
224 | } | ||
225 | |||
226 | rv = 0; | ||
227 | *pde_in = pde_new; | ||
228 | goto out_ok; | ||
229 | |||
230 | out_no_pde: | ||
231 | *pde_in = NULL; | ||
232 | out_ok: | ||
233 | return rv; | ||
234 | } | ||
235 | |||
236 | void remove_plugin_proc_dir(struct sched_plugin* plugin) | ||
237 | { | ||
238 | if (!plugin || !plugin->plugin_name){ | ||
239 | printk(KERN_ERR "Invalid plugin struct passed to %s.\n", | ||
240 | __func__); | ||
241 | return; | ||
242 | } | ||
243 | remove_proc_entry(plugin->plugin_name, plugs_dir); | ||
244 | } | ||
245 | |||
246 | |||
247 | |||
248 | /* misc. I/O helper functions */ | ||
249 | |||
250 | int copy_and_chomp(char *kbuf, unsigned long ksize, | ||
251 | __user const char* ubuf, unsigned long ulength) | ||
252 | { | ||
253 | /* caller must provide buffer space */ | ||
254 | BUG_ON(!ksize); | ||
255 | |||
256 | ksize--; /* leave space for null byte */ | ||
257 | |||
258 | if (ksize > ulength) | ||
259 | ksize = ulength; | ||
260 | |||
261 | if(copy_from_user(kbuf, ubuf, ksize)) | ||
262 | return -EFAULT; | ||
263 | |||
264 | kbuf[ksize] = '\0'; | ||
265 | |||
266 | /* chomp kbuf */ | ||
267 | if (ksize > 0 && kbuf[ksize - 1] == '\n') | ||
268 | kbuf[ksize - 1] = '\0'; | ||
269 | |||
270 | return ksize; | ||
271 | } | ||
272 | |||
273 | /* helper functions for clustered plugins */ | ||
274 | static const char* cache_level_names[] = { | ||
275 | "ALL", | ||
276 | "L1", | ||
277 | "L2", | ||
278 | "L3", | ||
279 | }; | ||
280 | |||
281 | int parse_cache_level(const char *cache_name, enum cache_level *level) | ||
282 | { | ||
283 | int err = -EINVAL; | ||
284 | int i; | ||
285 | /* do a quick and dirty comparison to find the cluster size */ | ||
286 | for (i = GLOBAL_CLUSTER; i <= L3_CLUSTER; i++) | ||
287 | if (!strcmp(cache_name, cache_level_names[i])) { | ||
288 | *level = (enum cache_level) i; | ||
289 | err = 0; | ||
290 | break; | ||
291 | } | ||
292 | return err; | ||
293 | } | ||
294 | |||
295 | const char* cache_level_name(enum cache_level level) | ||
296 | { | ||
297 | int idx = level; | ||
298 | |||
299 | if (idx >= GLOBAL_CLUSTER && idx <= L3_CLUSTER) | ||
300 | return cache_level_names[idx]; | ||
301 | else | ||
302 | return "INVALID"; | ||
303 | } | ||
304 | |||
305 | |||
306 | /* proc file interface to configure the cluster size */ | ||
307 | static int proc_read_cluster_size(char *page, char **start, | ||
308 | off_t off, int count, | ||
309 | int *eof, void *data) | ||
310 | { | ||
311 | return snprintf(page, PAGE_SIZE, "%s\n", | ||
312 | cache_level_name(*((enum cache_level*) data)));; | ||
313 | } | ||
314 | |||
315 | static int proc_write_cluster_size(struct file *file, | ||
316 | const char *buffer, | ||
317 | unsigned long count, | ||
318 | void *data) | ||
319 | { | ||
320 | int len; | ||
321 | char cache_name[8]; | ||
322 | |||
323 | len = copy_and_chomp(cache_name, sizeof(cache_name), buffer, count); | ||
324 | |||
325 | if (len > 0 && parse_cache_level(cache_name, (enum cache_level*) data)) | ||
326 | printk(KERN_INFO "Cluster '%s' is unknown.\n", cache_name); | ||
327 | |||
328 | return len; | ||
329 | } | ||
330 | |||
331 | struct proc_dir_entry* create_cluster_file(struct proc_dir_entry* parent, | ||
332 | enum cache_level* level) | ||
333 | { | ||
334 | struct proc_dir_entry* cluster_file; | ||
335 | |||
336 | cluster_file = create_proc_entry("cluster", 0644, parent); | ||
337 | if (!cluster_file) { | ||
338 | printk(KERN_ERR "Could not allocate %s/cluster " | ||
339 | "procfs entry.\n", parent->name); | ||
340 | } else { | ||
341 | cluster_file->read_proc = proc_read_cluster_size; | ||
342 | cluster_file->write_proc = proc_write_cluster_size; | ||
343 | cluster_file->data = level; | ||
344 | } | ||
345 | return cluster_file; | ||
346 | } | ||
347 | |||