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
9 * File operations for common magic files in rcfs,
10 * the user interface for CKRM.
13 * Latest version, more details at http://ckrm.sf.net
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
25 * Created from code kept earlier in fs/rcfs/magic_*.c
29 #include <linux/module.h>
31 #include <linux/namei.h>
32 #include <linux/namespace.h>
33 #include <linux/dcache.h>
34 #include <linux/seq_file.h>
35 #include <linux/init.h>
36 #include <linux/string.h>
37 #include <linux/smp_lock.h>
38 #include <linux/parser.h>
39 #include <asm/uaccess.h>
41 #include <linux/rcfs.h>
43 /******************************************************
46 * generic macros to assist in writing magic fileops
48 *****************************************************/
50 #define MAGIC_SHOW(FUNC) \
52 FUNC ## _show(struct seq_file *s, void *v) \
56 ckrm_core_class_t *core ; \
58 core = (ckrm_core_class_t *) \
59 (((struct rcfs_inode_info *)s->private)->core); \
61 if (!ckrm_is_core_valid(core)) { \
65 if (core->classtype->show_ ## FUNC) \
66 rc = (* core->classtype->show_ ## FUNC)(core, s); \
68 if (s->count == precnt) \
69 seq_printf(s, "No data to display\n"); \
73 #define MAGIC_OPEN(FUNC) \
75 FUNC ## _open(struct inode *inode, struct file *file) \
77 struct rcfs_inode_info *ri; \
80 if (file->f_dentry && file->f_dentry->d_parent) { \
82 ri = RCFS_I(file->f_dentry->d_parent->d_inode); \
83 ret = single_open(file,FUNC ## _show, (void *)ri); \
88 #define MAGIC_CLOSE(FUNC) \
90 FUNC ## _close(struct inode *inode, struct file *file) \
92 return single_release(inode,file); \
95 #define MAGIC_PARSE(FUNC) \
97 FUNC ## _parse(char *options, char **resstr, char **otherstr) \
105 while ((p = strsep(&options, ",")) != NULL) { \
106 substring_t args[MAX_OPT_ARGS]; \
112 token = match_token(p, FUNC##_tokens, args); \
114 case FUNC ## _res_type: \
115 *resstr = match_strdup(args); \
116 if (!strcmp(#FUNC, "config")) { \
117 char *str = p + strlen(p) + 1; \
118 *otherstr = kmalloc(strlen(str) + 1, \
120 if (*otherstr == NULL) { \
125 strcpy(*otherstr, str); \
131 *otherstr = match_strdup(args); \
137 return (*resstr != NULL); \
140 #define MAGIC_WRITE(FUNC,CLSTYPEFUN) \
142 FUNC ## _write(struct file *file, const char __user *buf, \
143 size_t count, loff_t *ppos) \
145 struct rcfs_inode_info *ri = \
146 RCFS_I(file->f_dentry->d_parent->d_inode); \
147 char *optbuf, *otherstr=NULL, *resname=NULL; \
149 ckrm_core_class_t *core ; \
152 if (!ckrm_is_core_valid(core)) \
155 if ((ssize_t) count < 0 \
156 || (ssize_t) count > FUNC ## _max_input_size) \
159 if (!access_ok(VERIFY_READ, buf, count)) \
162 down(&(ri->vfs_inode.i_sem)); \
164 optbuf = kmalloc(FUNC ## _max_input_size, GFP_KERNEL); \
165 __copy_from_user(optbuf, buf, count); \
166 if (optbuf[count-1] == '\n') \
167 optbuf[count-1]='\0'; \
169 done = FUNC ## _parse(optbuf, &resname, &otherstr); \
172 printk(KERN_ERR "Error parsing FUNC \n"); \
173 goto FUNC ## _write_out; \
176 if (core->classtype-> CLSTYPEFUN) { \
177 rc = (*core->classtype->CLSTYPEFUN) \
178 (core, resname, otherstr); \
180 printk(KERN_ERR "FUNC_write: CLSTYPEFUN error\n"); \
181 goto FUNC ## _write_out; \
185 FUNC ## _write_out: \
186 up(&(ri->vfs_inode.i_sem)); \
190 return rc ? rc : count; \
193 #define MAGIC_RD_FILEOPS(FUNC) \
194 struct file_operations FUNC ## _fileops = { \
195 .open = FUNC ## _open, \
197 .llseek = seq_lseek, \
198 .release = FUNC ## _close, \
200 EXPORT_SYMBOL(FUNC ## _fileops);
202 #define MAGIC_RDWR_FILEOPS(FUNC) \
203 struct file_operations FUNC ## _fileops = { \
204 .open = FUNC ## _open, \
206 .llseek = seq_lseek, \
207 .release = FUNC ## _close, \
208 .write = FUNC ## _write, \
210 EXPORT_SYMBOL(FUNC ## _fileops);
212 /******************************************************************************
213 * Shared function used by Target / Reclassify
216 *****************************************************************************/
218 #define TARGET_MAX_INPUT_SIZE 100
221 target_reclassify_write(struct file *file, const char __user * buf,
222 size_t count, loff_t * ppos, int manual)
224 struct rcfs_inode_info *ri = RCFS_I(file->f_dentry->d_inode);
227 ckrm_classtype_t *clstype;
229 if ((ssize_t) count < 0 || (ssize_t) count > TARGET_MAX_INPUT_SIZE)
232 if (!access_ok(VERIFY_READ, buf, count))
235 down(&(ri->vfs_inode.i_sem));
237 optbuf = kmalloc(TARGET_MAX_INPUT_SIZE, GFP_KERNEL);
238 __copy_from_user(optbuf, buf, count);
239 if (optbuf[count - 1] == '\n')
240 optbuf[count - 1] = '\0';
242 clstype = ri->core->classtype;
243 if (clstype->forced_reclassify)
244 rc = (*clstype->forced_reclassify) (manual ? ri->core: NULL, optbuf);
246 up(&(ri->vfs_inode.i_sem));
248 return (!rc ? count : rc);
252 /******************************************************************************
255 * pseudo file for manually reclassifying members to a class
257 *****************************************************************************/
260 target_write(struct file *file, const char __user * buf,
261 size_t count, loff_t * ppos)
263 return target_reclassify_write(file,buf,count,ppos,1);
266 struct file_operations target_fileops = {
267 .write = target_write,
270 EXPORT_SYMBOL(target_fileops);
272 /******************************************************************************
275 * pseudo file for reclassification of an object through CE
277 *****************************************************************************/
280 reclassify_write(struct file *file, const char __user * buf,
281 size_t count, loff_t * ppos)
283 return target_reclassify_write(file,buf,count,ppos,0);
286 struct file_operations reclassify_fileops = {
287 .write = reclassify_write,
290 EXPORT_SYMBOL(reclassify_fileops);
292 /******************************************************************************
295 * Set/get configuration parameters of a class.
297 *****************************************************************************/
299 /* Currently there are no per-class config parameters defined.
300 * Use existing code as a template
303 #define config_max_input_size 300
305 enum config_token_t {
306 config_str, config_res_type, config_err
309 static match_table_t config_tokens = {
310 {config_res_type, "res=%s"},
315 MAGIC_WRITE(config, set_config);
320 MAGIC_RDWR_FILEOPS(config);
322 /******************************************************************************
325 * List members of a class
327 *****************************************************************************/
331 MAGIC_CLOSE(members);
333 MAGIC_RD_FILEOPS(members);
335 /******************************************************************************
338 * Get/reset class statistics
339 * No standard set of stats defined. Each resource controller chooses
340 * its own set of statistics to maintain and export.
342 *****************************************************************************/
344 #define stats_max_input_size 50
347 stats_res_type, stats_str, stats_err
350 static match_table_t stats_tokens = {
351 {stats_res_type, "res=%s"},
357 MAGIC_WRITE(stats, reset_stats);
362 MAGIC_RDWR_FILEOPS(stats);
364 /******************************************************************************
367 * Set/get shares of a taskclass.
368 * Share types and semantics are defined by rcfs and ckrm core
370 *****************************************************************************/
372 #define SHARES_MAX_INPUT_SIZE 300
374 /* The enums for the share types should match the indices expected by
375 array parameter to ckrm_set_resshare */
377 /* Note only the first NUM_SHAREVAL enums correspond to share types,
378 the remaining ones are for token matching purposes */
381 MY_GUAR, MY_LIM, TOT_GUAR, MAX_LIM, SHARE_RES_TYPE, SHARE_ERR
384 /* Token matching for parsing input to this magic file */
385 static match_table_t shares_tokens = {
386 {SHARE_RES_TYPE, "res=%s"},
387 {MY_GUAR, "guarantee=%d"},
388 {MY_LIM, "limit=%d"},
389 {TOT_GUAR, "total_guarantee=%d"},
390 {MAX_LIM, "max_limit=%d"},
395 shares_parse(char *options, char **resstr, struct ckrm_shares *shares)
403 while ((p = strsep(&options, ",")) != NULL) {
405 substring_t args[MAX_OPT_ARGS];
411 token = match_token(p, shares_tokens, args);
414 *resstr = match_strdup(args);
417 if (match_int(args, &option))
419 shares->my_guarantee = option;
422 if (match_int(args, &option))
424 shares->my_limit = option;
427 if (match_int(args, &option))
429 shares->total_guarantee = option;
432 if (match_int(args, &option))
434 shares->max_limit = option;
445 shares_write(struct file *file, const char __user * buf,
446 size_t count, loff_t * ppos)
448 struct inode *inode = file->f_dentry->d_inode;
449 struct rcfs_inode_info *ri;
452 struct ckrm_core_class *core;
454 char *resname = NULL;
456 struct ckrm_shares newshares = {
457 CKRM_SHARE_UNCHANGED,
458 CKRM_SHARE_UNCHANGED,
459 CKRM_SHARE_UNCHANGED,
460 CKRM_SHARE_UNCHANGED,
461 CKRM_SHARE_UNCHANGED,
465 if ((ssize_t) count < 0 || (ssize_t) count > SHARES_MAX_INPUT_SIZE)
468 if (!access_ok(VERIFY_READ, buf, count))
471 ri = RCFS_I(file->f_dentry->d_parent->d_inode);
473 if (!ri || !ckrm_is_core_valid((ckrm_core_class_t *) (ri->core))) {
474 printk(KERN_ERR "shares_write: Error accessing core class\n");
481 optbuf = kmalloc(SHARES_MAX_INPUT_SIZE, GFP_KERNEL);
487 __copy_from_user(optbuf, buf, count);
488 if (optbuf[count - 1] == '\n')
489 optbuf[count - 1] = '\0';
491 done = shares_parse(optbuf, &resname, &newshares);
493 printk(KERN_ERR "Error parsing shares\n");
498 if (core->classtype->set_shares) {
499 rc = (*core->classtype->set_shares) (core, resname, &newshares);
502 "shares_write: resctlr share set error\n");
507 printk(KERN_DEBUG "Set %s shares to %d %d %d %d\n",
509 newshares.my_guarantee,
511 newshares.total_guarantee, newshares.max_limit);
527 MAGIC_RDWR_FILEOPS(shares);
530 * magic file creation/deletion
534 int rcfs_clear_magic(struct dentry *parent)
536 struct dentry *mftmp, *mfdentry;
538 list_for_each_entry_safe(mfdentry, mftmp, &parent->d_subdirs, d_child) {
540 if (!rcfs_is_magic(mfdentry))
543 if (rcfs_delete_internal(mfdentry))
545 "rcfs_clear_magic: error deleting one\n");
552 EXPORT_SYMBOL(rcfs_clear_magic);
554 int rcfs_create_magic(struct dentry *parent, struct rcfs_magf magf[], int count)
557 struct dentry *mfdentry;
559 for (i = 0; i < count; i++) {
560 mfdentry = rcfs_create_internal(parent, &magf[i], 0);
561 if (IS_ERR(mfdentry)) {
562 rcfs_clear_magic(parent);
565 RCFS_I(mfdentry->d_inode)->core = RCFS_I(parent->d_inode)->core;
566 mfdentry->d_fsdata = &RCFS_IS_MAGIC;
568 mfdentry->d_inode->i_fop = magf[i].i_fop;
570 mfdentry->d_inode->i_op = magf[i].i_op;
575 EXPORT_SYMBOL(rcfs_create_magic);