8a811cbafaeed00d33ab3dd2ebd41692fd5ab25f
[linux-2.6.git] / fs / rcfs / magic.c
1 /* 
2  * fs/rcfs/magic.c 
3  *
4  * Copyright (C) Shailabh Nagar,      IBM Corp. 2004
5  *           (C) Vivek Kashyap,       IBM Corp. 2004
6  *           (C) Chandra Seetharaman, IBM Corp. 2004
7  *           (C) Hubertus Franke,     IBM Corp. 2004
8  * 
9  * File operations for common magic files in rcfs, 
10  * the user interface for CKRM. 
11  * 
12  * Latest version, more details at http://ckrm.sf.net
13  * 
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2 of the License, or
17  * (at your option) any later version.
18  */
19
20 /*
21  * Changes
22  *
23  * 23 Apr 2004
24  *        Created from code kept earlier in fs/rcfs/magic_*.c
25  */
26
27 #include <linux/module.h>
28 #include <linux/fs.h>
29 #include <linux/namei.h>
30 #include <linux/namespace.h>
31 #include <linux/dcache.h>
32 #include <linux/seq_file.h>
33 #include <linux/init.h>
34 #include <linux/string.h>
35 #include <linux/smp_lock.h>
36 #include <linux/parser.h>
37 #include <asm/uaccess.h>
38
39 #include <linux/rcfs.h>
40
41 /*
42  * Macros
43  *
44  * generic macros to assist in writing magic fileops
45  *
46  */
47
48 #define MAGIC_SHOW(FUNC)                                               \
49 static int                                                             \
50 FUNC ## _show(struct seq_file *s, void *v)                             \
51 {                                                                      \
52         int rc=0;                                                      \
53         ssize_t precnt;                                                \
54         ckrm_core_class_t *core ;                                      \
55                                                                        \
56         core = (ckrm_core_class_t *)                                   \
57                 (((struct rcfs_inode_info *)s->private)->core);        \
58                                                                        \
59         if (!ckrm_is_core_valid(core)) {                               \
60                 return -EINVAL;                                        \
61         }                                                              \
62         precnt = s->count ;                                            \
63         if (core->classtype->show_ ## FUNC)                            \
64                 rc = (* core->classtype->show_ ## FUNC)(core, s);      \
65                                                                        \
66         if (s->count == precnt)                                        \
67                 seq_printf(s, "No data to display\n");                 \
68         return rc;                                                     \
69 };
70
71 #define MAGIC_OPEN(FUNC)                                               \
72 static int                                                             \
73 FUNC ## _open(struct inode *inode, struct file *file)                  \
74 {                                                                      \
75         struct rcfs_inode_info *ri;                                    \
76         int ret=-EINVAL;                                               \
77                                                                        \
78         if (file->f_dentry && file->f_dentry->d_parent) {              \
79                                                                        \
80                 ri = RCFS_I(file->f_dentry->d_parent->d_inode);        \
81                 ret = single_open(file,FUNC ## _show, (void *)ri);     \
82         }                                                              \
83         return ret;                                                    \
84 }
85
86 #define MAGIC_CLOSE(FUNC)                                              \
87 static int                                                             \
88 FUNC ## _close(struct inode *inode, struct file *file)                 \
89 {                                                                      \
90         return single_release(inode,file);                             \
91 }
92
93 #define MAGIC_PARSE(FUNC)                                              \
94 static int                                                             \
95 FUNC ## _parse(char *options, char **resstr, char **otherstr)          \
96 {                                                                      \
97         char *p;                                                       \
98         *resstr = NULL;                                                \
99                                                                        \
100         if (!options)                                                  \
101                 return 0;                                              \
102                                                                        \
103         while ((p = strsep(&options, ",")) != NULL) {                  \
104                 substring_t args[MAX_OPT_ARGS];                        \
105                 int token;                                             \
106                                                                        \
107                 if (!*p)                                               \
108                         continue;                                      \
109                                                                        \
110                 token = match_token(p, FUNC##_tokens, args);           \
111                 switch (token) {                                       \
112                 case FUNC ## _res_type:                                \
113                         *resstr = match_strdup(args);                  \
114                         if (!strcmp(#FUNC, "config")) {                \
115                                 char *str = p + strlen(p) + 1;         \
116                                 *otherstr = kmalloc(strlen(str) + 1,   \
117                                                          GFP_KERNEL);  \
118                                 if (*otherstr == NULL) {               \
119                                         kfree(*resstr);                \
120                                         *resstr = NULL;                \
121                                         return 0;                      \
122                                 } else {                               \
123                                         strcpy(*otherstr, str);        \
124                                         return 1;                      \
125                                 }                                      \
126                         }                                              \
127                         break;                                         \
128                 case FUNC ## _str:                                     \
129                         *otherstr = match_strdup(args);                \
130                         break;                                         \
131                 default:                                               \
132                         return 0;                                      \
133                 }                                                      \
134         }                                                              \
135         return (*resstr != NULL);                                      \
136 }
137
138 #define MAGIC_WRITE(FUNC,CLSTYPEFUN)                                   \
139 static ssize_t                                                         \
140 FUNC ## _write(struct file *file, const char __user *buf,              \
141                            size_t count, loff_t *ppos)                 \
142 {                                                                      \
143         struct rcfs_inode_info *ri =                                   \
144                 RCFS_I(file->f_dentry->d_parent->d_inode);             \
145         char *optbuf, *otherstr=NULL, *resname=NULL;                   \
146         int done, rc = 0;                                              \
147         ckrm_core_class_t *core ;                                      \
148                                                                        \
149         core = ri->core;                                               \
150         if (!ckrm_is_core_valid(core))                                 \
151                 return -EINVAL;                                        \
152                                                                        \
153         if ((ssize_t) count < 0                                        \
154             || (ssize_t) count > FUNC ## _max_input_size)              \
155                 return -EINVAL;                                        \
156                                                                        \
157         if (!access_ok(VERIFY_READ, buf, count))                       \
158                 return -EFAULT;                                        \
159                                                                        \
160         down(&(ri->vfs_inode.i_sem));                                  \
161                                                                        \
162         optbuf = kmalloc(FUNC ## _max_input_size, GFP_KERNEL);         \
163         __copy_from_user(optbuf, buf, count);                          \
164         if (optbuf[count-1] == '\n')                                   \
165                 optbuf[count-1]='\0';                                  \
166                                                                        \
167         done = FUNC ## _parse(optbuf, &resname, &otherstr);            \
168                                                                        \
169         if (!done) {                                                   \
170                 printk(KERN_ERR "Error parsing FUNC \n");              \
171                 goto FUNC ## _write_out;                               \
172         }                                                              \
173                                                                        \
174         if (core->classtype-> CLSTYPEFUN) {                            \
175                 rc = (*core->classtype->CLSTYPEFUN)                    \
176                         (core, resname, otherstr);                     \
177                 if (rc) {                                              \
178                         printk(KERN_ERR "FUNC_write: CLSTYPEFUN error\n");   \
179                         goto FUNC ## _write_out;                       \
180                 }                                                      \
181         }                                                              \
182                                                                        \
183 FUNC ## _write_out:                                                    \
184         up(&(ri->vfs_inode.i_sem));                                    \
185         kfree(optbuf);                                                 \
186         kfree(otherstr);                                               \
187         kfree(resname);                                                \
188         return rc ? rc : count;                                        \
189 }
190
191 #define MAGIC_RD_FILEOPS(FUNC)                                         \
192 struct file_operations FUNC ## _fileops = {                            \
193         .open           = FUNC ## _open,                               \
194         .read           = seq_read,                                    \
195         .llseek         = seq_lseek,                                   \
196         .release        = FUNC ## _close,                              \
197 };                                                                     \
198 EXPORT_SYMBOL(FUNC ## _fileops);
199
200 #define MAGIC_RDWR_FILEOPS(FUNC)                                       \
201 struct file_operations FUNC ## _fileops = {                            \
202         .open           = FUNC ## _open,                               \
203         .read           = seq_read,                                    \
204         .llseek         = seq_lseek,                                   \
205         .release        = FUNC ## _close,                              \
206         .write          = FUNC ## _write,                              \
207 };                                                                     \
208 EXPORT_SYMBOL(FUNC ## _fileops);
209
210 /*
211  * Shared function used by Members / Reclassify
212  */
213
214 #define MEMBERS_MAX_INPUT_SIZE 100
215
216 static ssize_t
217 members_reclassify_write(struct file *file, const char __user * buf,
218                         size_t count, loff_t * ppos, int manual)
219 {
220         struct rcfs_inode_info *ri = RCFS_I(file->f_dentry->d_inode);
221         char *optbuf;
222         int rc = -EINVAL;
223         ckrm_classtype_t *clstype;
224
225         if ((ssize_t) count < 0 || (ssize_t) count > MEMBERS_MAX_INPUT_SIZE)
226                 return -EINVAL;
227         if (!access_ok(VERIFY_READ, buf, count))
228                 return -EFAULT;
229         down(&(ri->vfs_inode.i_sem));
230         optbuf = kmalloc(MEMBERS_MAX_INPUT_SIZE, GFP_KERNEL);
231         __copy_from_user(optbuf, buf, count);
232         if (optbuf[count - 1] == '\n')
233                 optbuf[count - 1] = '\0';
234         clstype = ri->core->classtype;
235         if (clstype->forced_reclassify)
236                 rc = (*clstype->forced_reclassify) (manual ? ri->core: NULL, optbuf);
237         up(&(ri->vfs_inode.i_sem));
238         kfree(optbuf);
239         return (!rc ? count : rc);
240
241 }
242
243 /*
244  * Reclassify
245  *
246  * pseudo file for reclassification of an object through CE
247  */
248
249 static ssize_t
250 reclassify_write(struct file *file, const char __user * buf,
251                  size_t count, loff_t * ppos)
252 {
253         return members_reclassify_write(file,buf,count,ppos,0);
254 }
255
256 struct file_operations reclassify_fileops = {
257         .write = reclassify_write,
258 };
259
260 EXPORT_SYMBOL_GPL(reclassify_fileops);
261
262 /*
263  * Config
264  *
265  * Set/get configuration parameters of a class. 
266  */
267
268 /*
269  * Currently there are no per-class config parameters defined.
270  * Use existing code as a template
271  */
272
273 #define config_max_input_size  300
274
275 enum config_token_t {
276         config_str, config_res_type, config_err
277 };
278
279 static match_table_t config_tokens = {
280         {config_res_type, "res=%s"},
281         {config_err, NULL},
282 };
283
284 MAGIC_PARSE(config);
285 MAGIC_WRITE(config, set_config);
286 MAGIC_SHOW(config);
287 MAGIC_OPEN(config);
288 MAGIC_CLOSE(config);
289
290 MAGIC_RDWR_FILEOPS(config);
291
292 /*
293  * Members
294  *
295  * List members of a class
296  */
297
298 MAGIC_SHOW(members);
299 MAGIC_OPEN(members);
300 MAGIC_CLOSE(members);
301
302 static ssize_t
303 members_write(struct file *file, const char __user * buf,
304              size_t count, loff_t * ppos)
305 {
306         return members_reclassify_write(file,buf,count,ppos,1);
307 }
308
309 MAGIC_RDWR_FILEOPS(members);
310
311 /*
312  * Stats
313  *
314  * Get/reset class statistics
315  * No standard set of stats defined. Each resource controller chooses
316  * its own set of statistics to maintain and export.
317  */
318
319 #define stats_max_input_size  50
320
321 enum stats_token_t {
322         stats_res_type, stats_str, stats_err
323 };
324
325 static match_table_t stats_tokens = {
326         {stats_res_type, "res=%s"},
327         {stats_str, NULL},
328         {stats_err, NULL},
329 };
330
331 MAGIC_PARSE(stats);
332 MAGIC_WRITE(stats, reset_stats);
333 MAGIC_SHOW(stats);
334 MAGIC_OPEN(stats);
335 MAGIC_CLOSE(stats);
336
337 MAGIC_RDWR_FILEOPS(stats);
338
339 /*
340  * Shares
341  *
342  * Set/get shares of a taskclass.
343  * Share types and semantics are defined by rcfs and ckrm core 
344  */
345
346 #define SHARES_MAX_INPUT_SIZE  300
347
348 /*
349  * The enums for the share types should match the indices expected by
350  * array parameter to ckrm_set_resshare
351  *
352  * Note only the first NUM_SHAREVAL enums correspond to share types,
353  * the remaining ones are for token matching purposes
354  */
355
356 enum share_token_t {
357         MY_GUAR, MY_LIM, TOT_GUAR, MAX_LIM, SHARE_RES_TYPE, SHARE_ERR
358 };
359
360 /* Token matching for parsing input to this magic file */
361 static match_table_t shares_tokens = {
362         {SHARE_RES_TYPE, "res=%s"},
363         {MY_GUAR, "guarantee=%d"},
364         {MY_LIM, "limit=%d"},
365         {TOT_GUAR, "total_guarantee=%d"},
366         {MAX_LIM, "max_limit=%d"},
367         {SHARE_ERR, NULL}
368 };
369
370 static int
371 shares_parse(char *options, char **resstr, struct ckrm_shares *shares)
372 {
373         char *p;
374         int option;
375
376         if (!options)
377                 return 1;
378         while ((p = strsep(&options, ",")) != NULL) {
379                 substring_t args[MAX_OPT_ARGS];
380                 int token;
381
382                 if (!*p)
383                         continue;
384                 token = match_token(p, shares_tokens, args);
385                 switch (token) {
386                 case SHARE_RES_TYPE:
387                         *resstr = match_strdup(args);
388                         break;
389                 case MY_GUAR:
390                         if (match_int(args, &option))
391                                 return 0;
392                         shares->my_guarantee = option;
393                         break;
394                 case MY_LIM:
395                         if (match_int(args, &option))
396                                 return 0;
397                         shares->my_limit = option;
398                         break;
399                 case TOT_GUAR:
400                         if (match_int(args, &option))
401                                 return 0;
402                         shares->total_guarantee = option;
403                         break;
404                 case MAX_LIM:
405                         if (match_int(args, &option))
406                                 return 0;
407                         shares->max_limit = option;
408                         break;
409                 default:
410                         return 0;
411                 }
412         }
413         return 1;
414 }
415
416 static ssize_t
417 shares_write(struct file *file, const char __user * buf,
418              size_t count, loff_t * ppos)
419 {
420         struct inode *inode = file->f_dentry->d_inode;
421         struct rcfs_inode_info *ri;
422         char *optbuf;
423         int rc = 0;
424         struct ckrm_core_class *core;
425         int done;
426         char *resname = NULL;
427
428         struct ckrm_shares newshares = {
429                 CKRM_SHARE_UNCHANGED,
430                 CKRM_SHARE_UNCHANGED,
431                 CKRM_SHARE_UNCHANGED,
432                 CKRM_SHARE_UNCHANGED,
433                 CKRM_SHARE_UNCHANGED,
434                 CKRM_SHARE_UNCHANGED
435         };
436         if ((ssize_t) count < 0 || (ssize_t) count > SHARES_MAX_INPUT_SIZE)
437                 return -EINVAL;
438         if (!access_ok(VERIFY_READ, buf, count))
439                 return -EFAULT;
440         ri = RCFS_I(file->f_dentry->d_parent->d_inode);
441         if (!ri || !ckrm_is_core_valid((ckrm_core_class_t *) (ri->core))) {
442                 printk(KERN_ERR "shares_write: Error accessing core class\n");
443                 return -EFAULT;
444         }
445         down(&inode->i_sem);
446         core = ri->core;
447         optbuf = kmalloc(SHARES_MAX_INPUT_SIZE, GFP_KERNEL);
448         if (!optbuf) {
449                 up(&inode->i_sem);
450                 return -ENOMEM;
451         }
452         __copy_from_user(optbuf, buf, count);
453         if (optbuf[count - 1] == '\n')
454                 optbuf[count - 1] = '\0';
455         done = shares_parse(optbuf, &resname, &newshares);
456         if (!done) {
457                 printk(KERN_ERR "Error parsing shares\n");
458                 rc = -EINVAL;
459                 goto write_out;
460         }
461         if (core->classtype->set_shares) {
462                 rc = (*core->classtype->set_shares) (core, resname, &newshares);
463                 if (rc) {
464                         printk(KERN_ERR
465                                "shares_write: resctlr share set error\n");
466                         goto write_out;
467                 }
468         }
469         printk(KERN_ERR "Set %s shares to %d %d %d %d\n",
470                resname,
471                newshares.my_guarantee,
472                newshares.my_limit,
473                newshares.total_guarantee, newshares.max_limit);
474         rc = count;
475
476 write_out:
477         up(&inode->i_sem);
478         kfree(optbuf);
479         kfree(resname);
480         return rc;
481 }
482
483 MAGIC_SHOW(shares);
484 MAGIC_OPEN(shares);
485 MAGIC_CLOSE(shares);
486
487 MAGIC_RDWR_FILEOPS(shares);
488
489 /*
490  * magic file creation/deletion
491  */
492
493 int rcfs_clear_magic(struct dentry *parent)
494 {
495         struct dentry *mftmp, *mfdentry;
496
497         list_for_each_entry_safe(mfdentry, mftmp, &parent->d_subdirs, d_child) {
498                 if (!rcfs_is_magic(mfdentry))
499                         continue;
500                 if (rcfs_delete_internal(mfdentry))
501                         printk(KERN_ERR
502                                "rcfs_clear_magic: error deleting one\n");
503         }
504         return 0;
505 }
506
507 EXPORT_SYMBOL_GPL(rcfs_clear_magic);
508
509 int rcfs_create_magic(struct dentry *parent, struct rcfs_magf magf[], int count)
510 {
511         int i;
512         struct dentry *mfdentry;
513
514         for (i = 0; i < count; i++) {
515                 mfdentry = rcfs_create_internal(parent, &magf[i], 0);
516                 if (IS_ERR(mfdentry)) {
517                         rcfs_clear_magic(parent);
518                         return -ENOMEM;
519                 }
520                 RCFS_I(mfdentry->d_inode)->core = RCFS_I(parent->d_inode)->core;
521                 mfdentry->d_fsdata = &RCFS_IS_MAGIC;
522                 if (magf[i].i_fop)
523                         mfdentry->d_inode->i_fop = magf[i].i_fop;
524                 if (magf[i].i_op)
525                         mfdentry->d_inode->i_op = magf[i].i_op;
526         }
527         return 0;
528 }
529
530 EXPORT_SYMBOL_GPL(rcfs_create_magic);