2004-11-29 19:00:00

by Gerrit Huizenga

[permalink] [raw]
Subject: [PATCH] CKRM: 4/10 CKRM: Full rcfs support

Updates CKRM Resource Control Filesystem (rcfs) to include full
directory structure support.

Signed-Off-By: Chandra Seetharaman <[email protected]>
Signed-Off-By: Hubertus Franke <[email protected]>
Signed-Off-By: Shailabh Nagar <[email protected]>
Signed-Off-By: Vivek Kashyap <[email protected]>
Signed-Off-By: Gerrit Huizenga <[email protected]>


Index: linux-2.6.10-rc2/fs/Makefile
===================================================================
--- linux-2.6.10-rc2.orig/fs/Makefile 2004-11-14 17:27:52.000000000 -0800
+++ linux-2.6.10-rc2/fs/Makefile 2004-11-19 20:44:18.255709415 -0800
@@ -92,5 +92,6 @@
obj-$(CONFIG_XFS_FS) += xfs/
obj-$(CONFIG_AFS_FS) += afs/
obj-$(CONFIG_BEFS_FS) += befs/
+obj-$(CONFIG_RCFS_FS) += rcfs/
obj-$(CONFIG_HOSTFS) += hostfs/
obj-$(CONFIG_HPPFS) += hppfs/
Index: linux-2.6.10-rc2/fs/rcfs/dir.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10-rc2/fs/rcfs/dir.c 2004-11-19 20:44:18.261708464 -0800
@@ -0,0 +1,300 @@
+/*
+ * fs/rcfs/dir.c
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2004
+ * Vivek Kashyap, IBM Corp. 2004
+ *
+ *
+ * Directory operations for rcfs
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+/*
+ * Changes
+ *
+ * 08 Mar 2004
+ * Created.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/namespace.h>
+#include <linux/dcache.h>
+#include <linux/seq_file.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
+#include <linux/parser.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/rcfs.h>
+
+#define rcfs_positive(dentry) ((dentry)->d_inode && !d_unhashed((dentry)))
+
+int rcfs_empty(struct dentry *dentry)
+{
+ struct dentry *child;
+ int ret = 0;
+
+ spin_lock(&dcache_lock);
+ list_for_each_entry(child, &dentry->d_subdirs, d_child)
+ if (!rcfs_is_magic(child) && rcfs_positive(child))
+ goto out;
+ ret = 1;
+out:
+ spin_unlock(&dcache_lock);
+ return ret;
+}
+
+/* Directory inode operations */
+
+int
+rcfs_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ return rcfs_mknod(dir, dentry, mode | S_IFREG, 0);
+}
+
+EXPORT_SYMBOL_GPL(rcfs_create);
+
+/* Symlinks permitted ?? */
+int rcfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+{
+ struct inode *inode;
+ int error = -ENOSPC;
+
+ inode = rcfs_get_inode(dir->i_sb, S_IFLNK | S_IRWXUGO, 0);
+ if (inode) {
+ int l = strlen(symname) + 1;
+ error = page_symlink(inode, symname, l);
+ if (!error) {
+ if (dir->i_mode & S_ISGID)
+ inode->i_gid = dir->i_gid;
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ } else
+ iput(inode);
+ }
+ return error;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_symlink);
+
+int rcfs_create_coredir(struct inode *dir, struct dentry *dentry)
+{
+
+ struct rcfs_inode_info *ripar, *ridir;
+ int sz;
+
+ ripar = RCFS_I(dir);
+ ridir = RCFS_I(dentry->d_inode);
+ /* Inform resource controllers - do Core operations */
+ if (ckrm_is_core_valid(ripar->core)) {
+ sz = strlen(ripar->name) + strlen(dentry->d_name.name) + 2;
+ ridir->name = kmalloc(sz, GFP_KERNEL);
+ if (!ridir->name) {
+ return -ENOMEM;
+ }
+ snprintf(ridir->name, sz, "%s/%s", ripar->name,
+ dentry->d_name.name);
+ ridir->core = (*(ripar->core->classtype->alloc))
+ (ripar->core, ridir->name);
+ } else {
+ printk(KERN_ERR "rcfs_mkdir: Invalid parent core %p\n",
+ ripar->core);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_create_coredir);
+
+int rcfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+
+ int retval = 0;
+ ckrm_classtype_t *clstype;
+
+#if 0
+ struct dentry *pd = list_entry(dir->i_dentry.next, struct dentry,
+ d_alias);
+ if ((!strcmp(pd->d_name.name, "/") &&
+ !strcmp(dentry->d_name.name, "ce"))) {
+ /* Call CE's mkdir if it has registered, else fail. */
+ if (rcfs_eng_callbacks.mkdir) {
+ return (*rcfs_eng_callbacks.mkdir) (dir, dentry, mode);
+ } else {
+ return -EINVAL;
+ }
+ }
+#endif
+ if (_rcfs_mknod(dir, dentry, mode | S_IFDIR, 0)) {
+ printk(KERN_ERR "rcfs_mkdir: error in _rcfs_mknod\n");
+ return retval;
+ }
+ dir->i_nlink++;
+ /* Inherit parent's ops since _rcfs_mknod assigns noperm ops. */
+ dentry->d_inode->i_op = dir->i_op;
+ dentry->d_inode->i_fop = dir->i_fop;
+ retval = rcfs_create_coredir(dir, dentry);
+ if (retval) {
+ simple_rmdir(dir, dentry);
+ return retval;
+ }
+ /* create the default set of magic files */
+ clstype = (RCFS_I(dentry->d_inode))->core->classtype;
+ rcfs_create_magic(dentry, &(((struct rcfs_magf *)clstype->mfdesc)[1]),
+ clstype->mfcount - 3);
+ return retval;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_mkdir);
+
+int rcfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct rcfs_inode_info *ri = RCFS_I(dentry->d_inode);
+
+#if 0
+ struct dentry *pd = list_entry(dir->i_dentry.next,
+ struct dentry, d_alias);
+ if ((!strcmp(pd->d_name.name, "/") &&
+ !strcmp(dentry->d_name.name, "ce"))) {
+ // Call CE's mkdir if it has registered, else fail.
+ if (rcfs_eng_callbacks.rmdir) {
+ return (*rcfs_eng_callbacks.rmdir) (dir, dentry);
+ } else {
+ return simple_rmdir(dir, dentry);
+ }
+ } else if ((!strcmp(pd->d_name.name, "/") &&
+ !strcmp(dentry->d_name.name, "network"))) {
+ return -EPERM;
+ }
+#endif
+ if (!rcfs_empty(dentry)) {
+ printk(KERN_ERR "rcfs_rmdir: directory not empty\n");
+ return -ENOTEMPTY;
+ }
+ /* Core class removal */
+
+ if (ri->core == NULL) {
+ printk(KERN_ERR "rcfs_rmdir: core==NULL\n");
+ // likely a race condition
+ return 0;
+ }
+
+ if ((*(ri->core->classtype->free)) (ri->core)) {
+ printk(KERN_ERR "rcfs_rmdir: ckrm_free_core_class failed\n");
+ goto out;
+ }
+ ri->core = NULL; // just to be safe
+
+ /* Clear magic files only after core successfully removed */
+ rcfs_clear_magic(dentry);
+
+ return simple_rmdir(dir, dentry);
+
+out:
+ return -EBUSY;
+}
+
+EXPORT_SYMBOL(rcfs_rmdir);
+
+int rcfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+ // -ENOENT and not -ENOPERM to allow rm -rf to work despite
+ // magic files being present
+ return -ENOENT;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_unlink);
+
+/* rename is allowed on directories only */
+int
+rcfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
+ return simple_rename(old_dir, old_dentry, new_dir, new_dentry);
+ else
+ return -EINVAL;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_rename);
+
+struct inode_operations rcfs_dir_inode_operations = {
+ .create = rcfs_create,
+ .lookup = simple_lookup,
+ .link = simple_link,
+ .unlink = rcfs_unlink,
+ .symlink = rcfs_symlink,
+ .mkdir = rcfs_mkdir,
+ .rmdir = rcfs_rmdir,
+ .mknod = rcfs_mknod,
+ .rename = rcfs_rename,
+};
+
+int
+rcfs_root_create(struct inode *dir, struct dentry *dentry, int mode,
+ struct nameidata *nd)
+{
+ return -EPERM;
+}
+
+int
+rcfs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+{
+ return -EPERM;
+}
+
+int rcfs_root_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+ return -EPERM;
+}
+
+int rcfs_root_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ return -EPERM;
+}
+
+int rcfs_root_unlink(struct inode *dir, struct dentry *dentry)
+{
+ return -EPERM;
+}
+
+int
+rcfs_root_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+ return -EPERM;
+}
+
+int
+rcfs_root_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_dir, struct dentry *new_dentry)
+{
+ return -EPERM;
+}
+
+struct inode_operations rcfs_rootdir_inode_operations = {
+ .create = rcfs_root_create,
+ .lookup = simple_lookup,
+ .link = simple_link,
+ .unlink = rcfs_root_unlink,
+ .symlink = rcfs_root_symlink,
+ .mkdir = rcfs_root_mkdir,
+ .rmdir = rcfs_root_rmdir,
+ .mknod = rcfs_root_mknod,
+ .rename = rcfs_root_rename,
+};
Index: linux-2.6.10-rc2/fs/rcfs/inode.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10-rc2/fs/rcfs/inode.c 2004-11-19 20:44:18.265707831 -0800
@@ -0,0 +1,189 @@
+/*
+ * fs/rcfs/inode.c
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2004
+ * Vivek Kashyap, IBM Corp. 2004
+ *
+ * Resource class filesystem (rcfs) forming the
+ * user interface to Class-based Kernel Resource Management (CKRM).
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+/* Changes
+ *
+ * 05 Mar 2004
+ * Created.
+ * 06 Mar 2004
+ * Parsing for shares added
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/namespace.h>
+#include <linux/dcache.h>
+#include <linux/seq_file.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
+#include <linux/parser.h>
+#include <asm/uaccess.h>
+
+#include <linux/rcfs.h>
+
+/*
+ * Address of variable used as flag to indicate a magic file,
+ * value unimportant
+ */
+int RCFS_IS_MAGIC;
+
+struct inode *rcfs_get_inode(struct super_block *sb, int mode, dev_t dev)
+{
+ struct inode *inode = new_inode(sb);
+
+ if (inode) {
+ inode->i_mode = mode;
+ inode->i_uid = current->fsuid;
+ inode->i_gid = current->fsgid;
+ inode->i_blksize = PAGE_CACHE_SIZE;
+ inode->i_blocks = 0;
+ inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+ switch (mode & S_IFMT) {
+ default:
+ init_special_inode(inode, mode, dev);
+ break;
+ case S_IFREG:
+ /* Treat as default assignment */
+ inode->i_op = &rcfs_file_inode_operations;
+ /* inode->i_fop = &rcfs_file_operations; */
+ break;
+ case S_IFDIR:
+ /* inode->i_op = &rcfs_dir_inode_operations; */
+ inode->i_op = &rcfs_rootdir_inode_operations;
+ inode->i_fop = &simple_dir_operations;
+
+ /*
+ * directory inodes start off with i_nlink == 2
+ * (for "." entry)
+ */
+ inode->i_nlink++;
+ break;
+ case S_IFLNK:
+ inode->i_op = &page_symlink_inode_operations;
+ break;
+ }
+ }
+ return inode;
+}
+
+int _rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+ struct inode *inode;
+ int error = -EPERM;
+
+ if (dentry->d_inode)
+ return -EEXIST;
+ inode = rcfs_get_inode(dir->i_sb, mode, dev);
+ if (inode) {
+ if (dir->i_mode & S_ISGID) {
+ inode->i_gid = dir->i_gid;
+ if (S_ISDIR(mode))
+ inode->i_mode |= S_ISGID;
+ }
+ d_instantiate(dentry, inode);
+ dget(dentry);
+ error = 0;
+ }
+ return error;
+}
+
+EXPORT_SYMBOL_GPL(_rcfs_mknod);
+
+int rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
+{
+ /* User can only create directories, not files */
+ if ((mode & S_IFMT) != S_IFDIR)
+ return -EINVAL;
+
+ return dir->i_op->mkdir(dir, dentry, mode);
+}
+
+EXPORT_SYMBOL_GPL(rcfs_mknod);
+
+struct dentry *rcfs_create_internal(struct dentry *parent,
+ struct rcfs_magf *magf, int magic)
+{
+ struct qstr qstr;
+ struct dentry *mfdentry;
+
+ /* Get new dentry for name */
+ qstr.name = magf->name;
+ qstr.len = strlen(magf->name);
+ qstr.hash = full_name_hash(magf->name, qstr.len);
+ mfdentry = lookup_hash(&qstr, parent);
+
+ if (!IS_ERR(mfdentry)) {
+ int err;
+
+ down(&parent->d_inode->i_sem);
+ if (magic && (magf->mode & S_IFDIR))
+ err = parent->d_inode->i_op->mkdir(parent->d_inode,
+ mfdentry,
+ magf->mode);
+ else {
+ err = _rcfs_mknod(parent->d_inode, mfdentry,
+ magf->mode, 0);
+ /*
+ * _rcfs_mknod doesn't increment parent's link count,
+ * i_op->mkdir does.
+ */
+ parent->d_inode->i_nlink++;
+ }
+ up(&parent->d_inode->i_sem);
+ if (err) {
+ dput(mfdentry);
+ return mfdentry;
+ }
+ }
+ return mfdentry;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_create_internal);
+
+int rcfs_delete_internal(struct dentry *mfdentry)
+{
+ struct dentry *parent;
+
+ if (!mfdentry || !mfdentry->d_parent)
+ return -EINVAL;
+ parent = mfdentry->d_parent;
+ if (!mfdentry->d_inode) {
+ return 0;
+ }
+ down(&mfdentry->d_inode->i_sem);
+ if (S_ISDIR(mfdentry->d_inode->i_mode))
+ simple_rmdir(parent->d_inode, mfdentry);
+ else
+ simple_unlink(parent->d_inode, mfdentry);
+ up(&mfdentry->d_inode->i_sem);
+ d_delete(mfdentry);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_delete_internal);
+
+struct inode_operations rcfs_file_inode_operations = {
+ .getattr = simple_getattr,
+};
Index: linux-2.6.10-rc2/fs/rcfs/magic.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10-rc2/fs/rcfs/magic.c 2004-11-19 20:44:18.272706722 -0800
@@ -0,0 +1,542 @@
+/*
+ * fs/rcfs/magic.c
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2004
+ * (C) Vivek Kashyap, IBM Corp. 2004
+ * (C) Chandra Seetharaman, IBM Corp. 2004
+ * (C) Hubertus Franke, IBM Corp. 2004
+ *
+ * File operations for common magic files in rcfs,
+ * the user interface for CKRM.
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+/*
+ * Changes
+ *
+ * 23 Apr 2004
+ * Created from code kept earlier in fs/rcfs/magic_*.c
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/namespace.h>
+#include <linux/dcache.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/parser.h>
+#include <asm/uaccess.h>
+
+#include <linux/rcfs.h>
+
+/*
+ * Macros
+ *
+ * generic macros to assist in writing magic fileops
+ *
+ */
+
+#define MAGIC_SHOW(FUNC) \
+static int \
+FUNC ## _show(struct seq_file *s, void *v) \
+{ \
+ int rc=0; \
+ ssize_t precnt; \
+ ckrm_core_class_t *core ; \
+ \
+ core = (ckrm_core_class_t *) \
+ (((struct rcfs_inode_info *)s->private)->core); \
+ \
+ if (!ckrm_is_core_valid(core)) { \
+ return -EINVAL; \
+ } \
+ precnt = s->count ; \
+ if (core->classtype->show_ ## FUNC) \
+ rc = (* core->classtype->show_ ## FUNC)(core, s); \
+ \
+ if (s->count == precnt) \
+ seq_printf(s, "No data to display\n"); \
+ return rc; \
+};
+
+#define MAGIC_OPEN(FUNC) \
+static int \
+FUNC ## _open(struct inode *inode, struct file *file) \
+{ \
+ struct rcfs_inode_info *ri; \
+ int ret=-EINVAL; \
+ \
+ if (file->f_dentry && file->f_dentry->d_parent) { \
+ \
+ ri = RCFS_I(file->f_dentry->d_parent->d_inode); \
+ ret = single_open(file,FUNC ## _show, (void *)ri); \
+ } \
+ return ret; \
+}
+
+#define MAGIC_CLOSE(FUNC) \
+static int \
+FUNC ## _close(struct inode *inode, struct file *file) \
+{ \
+ return single_release(inode,file); \
+}
+
+#define MAGIC_PARSE(FUNC) \
+static int \
+FUNC ## _parse(char *options, char **resstr, char **otherstr) \
+{ \
+ char *p; \
+ *resstr = NULL; \
+ \
+ if (!options) \
+ return 0; \
+ \
+ while ((p = strsep(&options, ",")) != NULL) { \
+ substring_t args[MAX_OPT_ARGS]; \
+ int token; \
+ \
+ if (!*p) \
+ continue; \
+ \
+ token = match_token(p, FUNC##_tokens, args); \
+ switch (token) { \
+ case FUNC ## _res_type: \
+ *resstr = match_strdup(args); \
+ if (!strcmp(#FUNC, "config")) { \
+ char *str = p + strlen(p) + 1; \
+ *otherstr = kmalloc(strlen(str) + 1, \
+ GFP_KERNEL); \
+ if (*otherstr == NULL) { \
+ kfree(*resstr); \
+ *resstr = NULL; \
+ return 0; \
+ } else { \
+ strcpy(*otherstr, str); \
+ return 1; \
+ } \
+ } \
+ break; \
+ case FUNC ## _str: \
+ *otherstr = match_strdup(args); \
+ break; \
+ default: \
+ return 0; \
+ } \
+ } \
+ return (*resstr != NULL); \
+}
+
+#define MAGIC_WRITE(FUNC,CLSTYPEFUN) \
+static ssize_t \
+FUNC ## _write(struct file *file, const char __user *buf, \
+ size_t count, loff_t *ppos) \
+{ \
+ struct rcfs_inode_info *ri = \
+ RCFS_I(file->f_dentry->d_parent->d_inode); \
+ char *optbuf, *otherstr=NULL, *resname=NULL; \
+ int done, rc = 0; \
+ ckrm_core_class_t *core ; \
+ \
+ core = ri->core; \
+ if (!ckrm_is_core_valid(core)) \
+ return -EINVAL; \
+ \
+ if ((ssize_t) count < 0 \
+ || (ssize_t) count > FUNC ## _max_input_size) \
+ return -EINVAL; \
+ \
+ if (!access_ok(VERIFY_READ, buf, count)) \
+ return -EFAULT; \
+ \
+ down(&(ri->vfs_inode.i_sem)); \
+ \
+ optbuf = kmalloc(FUNC ## _max_input_size, GFP_KERNEL); \
+ __copy_from_user(optbuf, buf, count); \
+ if (optbuf[count-1] == '\n') \
+ optbuf[count-1]='\0'; \
+ \
+ done = FUNC ## _parse(optbuf, &resname, &otherstr); \
+ \
+ if (!done) { \
+ printk(KERN_ERR "Error parsing FUNC \n"); \
+ goto FUNC ## _write_out; \
+ } \
+ \
+ if (core->classtype-> CLSTYPEFUN) { \
+ rc = (*core->classtype->CLSTYPEFUN) \
+ (core, resname, otherstr); \
+ if (rc) { \
+ printk(KERN_ERR "FUNC_write: CLSTYPEFUN error\n"); \
+ goto FUNC ## _write_out; \
+ } \
+ } \
+ \
+FUNC ## _write_out: \
+ up(&(ri->vfs_inode.i_sem)); \
+ kfree(optbuf); \
+ kfree(otherstr); \
+ kfree(resname); \
+ return rc ? rc : count; \
+}
+
+#define MAGIC_RD_FILEOPS(FUNC) \
+struct file_operations FUNC ## _fileops = { \
+ .open = FUNC ## _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = FUNC ## _close, \
+}; \
+EXPORT_SYMBOL(FUNC ## _fileops);
+
+#define MAGIC_RDWR_FILEOPS(FUNC) \
+struct file_operations FUNC ## _fileops = { \
+ .open = FUNC ## _open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = FUNC ## _close, \
+ .write = FUNC ## _write, \
+}; \
+EXPORT_SYMBOL(FUNC ## _fileops);
+
+/*
+ * Shared function used by Target / Reclassify
+ */
+
+#define TARGET_MAX_INPUT_SIZE 100
+
+static ssize_t
+target_reclassify_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * ppos, int manual)
+{
+ struct rcfs_inode_info *ri = RCFS_I(file->f_dentry->d_inode);
+ char *optbuf;
+ int rc = -EINVAL;
+ ckrm_classtype_t *clstype;
+
+ if ((ssize_t) count < 0 || (ssize_t) count > TARGET_MAX_INPUT_SIZE)
+ return -EINVAL;
+ if (!access_ok(VERIFY_READ, buf, count))
+ return -EFAULT;
+ down(&(ri->vfs_inode.i_sem));
+ optbuf = kmalloc(TARGET_MAX_INPUT_SIZE, GFP_KERNEL);
+ __copy_from_user(optbuf, buf, count);
+ if (optbuf[count - 1] == '\n')
+ optbuf[count - 1] = '\0';
+ clstype = ri->core->classtype;
+ if (clstype->forced_reclassify)
+ rc = (*clstype->forced_reclassify) (manual ? ri->core: NULL, optbuf);
+ up(&(ri->vfs_inode.i_sem));
+ kfree(optbuf);
+ return (!rc ? count : rc);
+
+}
+
+/*
+ * Target
+ *
+ * pseudo file for manually reclassifying members to a class
+ */
+
+static ssize_t
+target_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ return target_reclassify_write(file,buf,count,ppos,1);
+}
+
+struct file_operations target_fileops = {
+ .write = target_write,
+};
+
+EXPORT_SYMBOL_GPL(target_fileops);
+
+/*
+ * Reclassify
+ *
+ * pseudo file for reclassification of an object through CE
+ */
+
+static ssize_t
+reclassify_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ return target_reclassify_write(file,buf,count,ppos,0);
+}
+
+struct file_operations reclassify_fileops = {
+ .write = reclassify_write,
+};
+
+EXPORT_SYMBOL_GPL(reclassify_fileops);
+
+/*
+ * Config
+ *
+ * Set/get configuration parameters of a class.
+ */
+
+/*
+ * Currently there are no per-class config parameters defined.
+ * Use existing code as a template
+ */
+
+#define config_max_input_size 300
+
+enum config_token_t {
+ config_str, config_res_type, config_err
+};
+
+static match_table_t config_tokens = {
+ {config_res_type, "res=%s"},
+ {config_err, NULL},
+};
+
+MAGIC_PARSE(config);
+MAGIC_WRITE(config, set_config);
+MAGIC_SHOW(config);
+MAGIC_OPEN(config);
+MAGIC_CLOSE(config);
+
+MAGIC_RDWR_FILEOPS(config);
+
+/*
+ * Members
+ *
+ * List members of a class
+ */
+
+MAGIC_SHOW(members);
+MAGIC_OPEN(members);
+MAGIC_CLOSE(members);
+
+MAGIC_RD_FILEOPS(members);
+
+/*
+ * Stats
+ *
+ * Get/reset class statistics
+ * No standard set of stats defined. Each resource controller chooses
+ * its own set of statistics to maintain and export.
+ */
+
+#define stats_max_input_size 50
+
+enum stats_token_t {
+ stats_res_type, stats_str, stats_err
+};
+
+static match_table_t stats_tokens = {
+ {stats_res_type, "res=%s"},
+ {stats_str, NULL},
+ {stats_err, NULL},
+};
+
+MAGIC_PARSE(stats);
+MAGIC_WRITE(stats, reset_stats);
+MAGIC_SHOW(stats);
+MAGIC_OPEN(stats);
+MAGIC_CLOSE(stats);
+
+MAGIC_RDWR_FILEOPS(stats);
+
+/*
+ * Shares
+ *
+ * Set/get shares of a taskclass.
+ * Share types and semantics are defined by rcfs and ckrm core
+ */
+
+#define SHARES_MAX_INPUT_SIZE 300
+
+/*
+ * The enums for the share types should match the indices expected by
+ * array parameter to ckrm_set_resshare
+ *
+ * Note only the first NUM_SHAREVAL enums correspond to share types,
+ * the remaining ones are for token matching purposes
+ */
+
+enum share_token_t {
+ MY_GUAR, MY_LIM, TOT_GUAR, MAX_LIM, SHARE_RES_TYPE, SHARE_ERR
+};
+
+/* Token matching for parsing input to this magic file */
+static match_table_t shares_tokens = {
+ {SHARE_RES_TYPE, "res=%s"},
+ {MY_GUAR, "guarantee=%d"},
+ {MY_LIM, "limit=%d"},
+ {TOT_GUAR, "total_guarantee=%d"},
+ {MAX_LIM, "max_limit=%d"},
+ {SHARE_ERR, NULL}
+};
+
+static int
+shares_parse(char *options, char **resstr, struct ckrm_shares *shares)
+{
+ char *p;
+ int option;
+
+ if (!options)
+ return 1;
+ while ((p = strsep(&options, ",")) != NULL) {
+ substring_t args[MAX_OPT_ARGS];
+ int token;
+
+ if (!*p)
+ continue;
+ token = match_token(p, shares_tokens, args);
+ switch (token) {
+ case SHARE_RES_TYPE:
+ *resstr = match_strdup(args);
+ break;
+ case MY_GUAR:
+ if (match_int(args, &option))
+ return 0;
+ shares->my_guarantee = option;
+ break;
+ case MY_LIM:
+ if (match_int(args, &option))
+ return 0;
+ shares->my_limit = option;
+ break;
+ case TOT_GUAR:
+ if (match_int(args, &option))
+ return 0;
+ shares->total_guarantee = option;
+ break;
+ case MAX_LIM:
+ if (match_int(args, &option))
+ return 0;
+ shares->max_limit = option;
+ break;
+ default:
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static ssize_t
+shares_write(struct file *file, const char __user * buf,
+ size_t count, loff_t * ppos)
+{
+ struct inode *inode = file->f_dentry->d_inode;
+ struct rcfs_inode_info *ri;
+ char *optbuf;
+ int rc = 0;
+ struct ckrm_core_class *core;
+ int done;
+ char *resname = NULL;
+
+ struct ckrm_shares newshares = {
+ CKRM_SHARE_UNCHANGED,
+ CKRM_SHARE_UNCHANGED,
+ CKRM_SHARE_UNCHANGED,
+ CKRM_SHARE_UNCHANGED,
+ CKRM_SHARE_UNCHANGED,
+ CKRM_SHARE_UNCHANGED
+ };
+ if ((ssize_t) count < 0 || (ssize_t) count > SHARES_MAX_INPUT_SIZE)
+ return -EINVAL;
+ if (!access_ok(VERIFY_READ, buf, count))
+ return -EFAULT;
+ ri = RCFS_I(file->f_dentry->d_parent->d_inode);
+ if (!ri || !ckrm_is_core_valid((ckrm_core_class_t *) (ri->core))) {
+ printk(KERN_ERR "shares_write: Error accessing core class\n");
+ return -EFAULT;
+ }
+ down(&inode->i_sem);
+ core = ri->core;
+ optbuf = kmalloc(SHARES_MAX_INPUT_SIZE, GFP_KERNEL);
+ if (!optbuf) {
+ up(&inode->i_sem);
+ return -ENOMEM;
+ }
+ __copy_from_user(optbuf, buf, count);
+ if (optbuf[count - 1] == '\n')
+ optbuf[count - 1] = '\0';
+ done = shares_parse(optbuf, &resname, &newshares);
+ if (!done) {
+ printk(KERN_ERR "Error parsing shares\n");
+ rc = -EINVAL;
+ goto write_out;
+ }
+ if (core->classtype->set_shares) {
+ rc = (*core->classtype->set_shares) (core, resname, &newshares);
+ if (rc) {
+ printk(KERN_ERR
+ "shares_write: resctlr share set error\n");
+ goto write_out;
+ }
+ }
+ printk(KERN_ERR "Set %s shares to %d %d %d %d\n",
+ resname,
+ newshares.my_guarantee,
+ newshares.my_limit,
+ newshares.total_guarantee, newshares.max_limit);
+ rc = count;
+
+write_out:
+ up(&inode->i_sem);
+ kfree(optbuf);
+ kfree(resname);
+ return rc;
+}
+
+MAGIC_SHOW(shares);
+MAGIC_OPEN(shares);
+MAGIC_CLOSE(shares);
+
+MAGIC_RDWR_FILEOPS(shares);
+
+/*
+ * magic file creation/deletion
+ */
+
+int rcfs_clear_magic(struct dentry *parent)
+{
+ struct dentry *mftmp, *mfdentry;
+
+ list_for_each_entry_safe(mfdentry, mftmp, &parent->d_subdirs, d_child) {
+ if (!rcfs_is_magic(mfdentry))
+ continue;
+ if (rcfs_delete_internal(mfdentry))
+ printk(KERN_ERR
+ "rcfs_clear_magic: error deleting one\n");
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_clear_magic);
+
+int rcfs_create_magic(struct dentry *parent, struct rcfs_magf magf[], int count)
+{
+ int i;
+ struct dentry *mfdentry;
+
+ for (i = 0; i < count; i++) {
+ mfdentry = rcfs_create_internal(parent, &magf[i], 0);
+ if (IS_ERR(mfdentry)) {
+ rcfs_clear_magic(parent);
+ return -ENOMEM;
+ }
+ RCFS_I(mfdentry->d_inode)->core = RCFS_I(parent->d_inode)->core;
+ mfdentry->d_fsdata = &RCFS_IS_MAGIC;
+ if (magf[i].i_fop)
+ mfdentry->d_inode->i_fop = magf[i].i_fop;
+ if (magf[i].i_op)
+ mfdentry->d_inode->i_op = magf[i].i_op;
+ }
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_create_magic);
Index: linux-2.6.10-rc2/fs/rcfs/Makefile
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10-rc2/fs/rcfs/Makefile 2004-11-19 20:44:18.274706405 -0800
@@ -0,0 +1,6 @@
+#
+# Makefile for rcfs routines.
+#
+
+obj-$(CONFIG_RCFS_FS) += rcfs.o
+rcfs-objs := super.o inode.o dir.o rootdir.o magic.o
Index: linux-2.6.10-rc2/fs/rcfs/rootdir.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10-rc2/fs/rcfs/rootdir.c 2004-11-19 20:44:18.279705613 -0800
@@ -0,0 +1,209 @@
+/*
+ * fs/rcfs/rootdir.c
+ *
+ * Copyright (C) Vivek Kashyap, IBM Corp. 2004
+ *
+ *
+ * Functions for creating root directories and magic files
+ * for classtypes and classification engines under rcfs
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+/*
+ * Changes
+ *
+ * 08 April 2004
+ * Created.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/namespace.h>
+#include <linux/dcache.h>
+#include <linux/seq_file.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
+#include <linux/parser.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/rcfs.h>
+
+rbce_eng_callback_t rcfs_eng_callbacks = {
+ NULL, NULL
+};
+
+int rcfs_register_engine(rbce_eng_callback_t * rcbs)
+{
+ if (!rcbs->mkdir || rcfs_eng_callbacks.mkdir) {
+ return -EINVAL;
+ }
+ rcfs_eng_callbacks = *rcbs;
+ rcfs_engine_regd++;
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_register_engine);
+
+int rcfs_unregister_engine(rbce_eng_callback_t * rcbs)
+{
+ if (!rcbs->mkdir || !rcfs_eng_callbacks.mkdir ||
+ (rcbs->mkdir != rcfs_eng_callbacks.mkdir)) {
+ return -EINVAL;
+ }
+ rcfs_eng_callbacks.mkdir = NULL;
+ rcfs_eng_callbacks.rmdir = NULL;
+ rcfs_engine_regd--;
+ return 0;
+}
+
+EXPORT_SYMBOL(rcfs_unregister_engine);
+
+/*
+ * rcfs_mkroot
+ * Create and return a "root" dentry under /rcfs.
+ * Also create associated magic files
+ *
+ * @mfdesc: array of rcfs_magf describing root dir and its magic files
+ * @count: number of entries in mfdesc
+ * @core: core class to be associated with root
+ * @rootde: output parameter to return the newly created root dentry
+ */
+
+int rcfs_mkroot(struct rcfs_magf *mfdesc, int mfcount, struct dentry **rootde)
+{
+ int sz;
+ struct rcfs_magf *rootdesc = &mfdesc[0];
+ struct dentry *dentry;
+ struct rcfs_inode_info *rootri;
+
+ if ((mfcount < 0) || (!mfdesc))
+ return -EINVAL;
+
+ rootdesc = &mfdesc[0];
+ printk("allocating classtype root <%s>\n", rootdesc->name);
+ dentry = rcfs_create_internal(rcfs_rootde, rootdesc, 0);
+
+ if (!dentry) {
+ printk(KERN_ERR "Could not create %s\n", rootdesc->name);
+ return -ENOMEM;
+ }
+ rootri = RCFS_I(dentry->d_inode);
+ sz = strlen(rootdesc->name) + strlen(RCFS_ROOT) + 2;
+ rootri->name = kmalloc(sz, GFP_KERNEL);
+ if (!rootri->name) {
+ printk(KERN_ERR "Error allocating name for %s\n",
+ rootdesc->name);
+ rcfs_delete_internal(dentry);
+ return -ENOMEM;
+ }
+ snprintf(rootri->name, sz, "%s/%s", RCFS_ROOT, rootdesc->name);
+ if (rootdesc->i_fop)
+ dentry->d_inode->i_fop = rootdesc->i_fop;
+ if (rootdesc->i_op)
+ dentry->d_inode->i_op = rootdesc->i_op;
+
+ /* set output parameters */
+ *rootde = dentry;
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_mkroot);
+
+int rcfs_rmroot(struct dentry *rootde)
+{
+ struct rcfs_inode_info *ri;
+
+ if (!rootde)
+ return -EINVAL;
+
+ rcfs_clear_magic(rootde);
+ ri = RCFS_I(rootde->d_inode);
+ kfree(ri->name);
+ ri->name = NULL;
+ rcfs_delete_internal(rootde);
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_rmroot);
+
+int rcfs_register_classtype(ckrm_classtype_t * clstype)
+{
+ int rc;
+ struct rcfs_inode_info *rootri;
+ struct rcfs_magf *mfdesc;
+
+ if (genmfdesc[clstype->mfidx] == NULL) {
+ return -ENOMEM;
+ }
+
+ clstype->mfdesc = (void *)genmfdesc[clstype->mfidx]->rootmf;
+ clstype->mfcount = genmfdesc[clstype->mfidx]->rootmflen;
+
+ mfdesc = (struct rcfs_magf *)clstype->mfdesc;
+
+ /* rcfs root entry has the same name as the classtype */
+ strncpy(mfdesc[0].name, clstype->name, RCFS_MAGF_NAMELEN);
+
+ rc = rcfs_mkroot(mfdesc, clstype->mfcount,
+ (struct dentry **)&(clstype->rootde));
+ if (rc)
+ return rc;
+ rootri = RCFS_I(((struct dentry *)(clstype->rootde))->d_inode);
+ rootri->core = clstype->default_class;
+ clstype->default_class->name = rootri->name;
+ ckrm_core_grab(clstype->default_class);
+
+ /* Create magic files under root */
+ if ((rc = rcfs_create_magic(clstype->rootde, &mfdesc[1],
+ clstype->mfcount - 1))) {
+ kfree(rootri->name);
+ rootri->name = NULL;
+ rcfs_delete_internal(clstype->rootde);
+ return rc;
+ }
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_register_classtype);
+
+int rcfs_deregister_classtype(ckrm_classtype_t * clstype)
+{
+ int rc;
+
+ rc = rcfs_rmroot((struct dentry *)clstype->rootde);
+ if (!rc) {
+ clstype->default_class->name = NULL;
+ ckrm_core_drop(clstype->default_class);
+ }
+ return rc;
+}
+
+EXPORT_SYMBOL_GPL(rcfs_deregister_classtype);
+
+/* Common root and magic file entries.
+ * root name, root permissions, magic file names and magic file permissions
+ * are needed by all entities (classtypes and classification engines) existing
+ * under the rcfs mount point
+ *
+ * The common sets of these attributes are listed here as a table. Individual
+ * classtypes and classification engines can simple specify the index into the
+ * table to initialize their magf entries.
+ */
+
+struct rcfs_mfdesc *genmfdesc[] = {
+ NULL,
+};
Index: linux-2.6.10-rc2/fs/rcfs/super.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.10-rc2/fs/rcfs/super.c 2004-11-19 20:44:18.283704980 -0800
@@ -0,0 +1,304 @@
+/*
+ * fs/rcfs/super.c
+ *
+ * Copyright (C) Shailabh Nagar, IBM Corp. 2004
+ * Vivek Kashyap, IBM Corp. 2004
+ *
+ * Super block operations for rcfs
+ *
+ *
+ * Latest version, more details at http://ckrm.sf.net
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+/*
+ * Changes
+ *
+ * 08 Mar 2004
+ * Created.
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/namei.h>
+#include <linux/namespace.h>
+#include <linux/dcache.h>
+#include <linux/seq_file.h>
+#include <linux/pagemap.h>
+#include <linux/highmem.h>
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/smp_lock.h>
+#include <linux/backing-dev.h>
+#include <linux/parser.h>
+
+#include <asm/uaccess.h>
+
+#include <linux/rcfs.h>
+#include <linux/ckrm_rc.h>
+#include <linux/ckrm_ce.h>
+
+static kmem_cache_t *rcfs_inode_cachep;
+
+inline struct rcfs_inode_info *RCFS_I(struct inode *inode)
+{
+ return container_of(inode, struct rcfs_inode_info, vfs_inode);
+}
+
+EXPORT_SYMBOL_GPL(RCFS_I);
+
+static struct inode *rcfs_alloc_inode(struct super_block *sb)
+{
+ struct rcfs_inode_info *ri;
+ ri = (struct rcfs_inode_info *)kmem_cache_alloc(rcfs_inode_cachep,
+ SLAB_KERNEL);
+ if (!ri)
+ return NULL;
+ ri->name = NULL;
+ return &ri->vfs_inode;
+}
+
+static void rcfs_destroy_inode(struct inode *inode)
+{
+ struct rcfs_inode_info *ri = RCFS_I(inode);
+
+ kfree(ri->name);
+ kmem_cache_free(rcfs_inode_cachep, ri);
+}
+
+static void
+rcfs_init_once(void *foo, kmem_cache_t * cachep, unsigned long flags)
+{
+ struct rcfs_inode_info *ri = (struct rcfs_inode_info *)foo;
+
+ if ((flags & (SLAB_CTOR_VERIFY | SLAB_CTOR_CONSTRUCTOR)) ==
+ SLAB_CTOR_CONSTRUCTOR)
+ inode_init_once(&ri->vfs_inode);
+}
+
+int rcfs_init_inodecache(void)
+{
+ rcfs_inode_cachep = kmem_cache_create("rcfs_inode_cache",
+ sizeof(struct rcfs_inode_info),
+ 0,
+ SLAB_HWCACHE_ALIGN |
+ SLAB_RECLAIM_ACCOUNT,
+ rcfs_init_once, NULL);
+ if (rcfs_inode_cachep == NULL)
+ return -ENOMEM;
+ return 0;
+}
+
+void rcfs_destroy_inodecache(void)
+{
+ printk(KERN_WARNING "destroy inodecache was called\n");
+ if (kmem_cache_destroy(rcfs_inode_cachep))
+ printk(KERN_INFO
+ "rcfs_inode_cache: not all structures were freed\n");
+}
+
+struct super_operations rcfs_super_ops = {
+ .alloc_inode = rcfs_alloc_inode,
+ .destroy_inode = rcfs_destroy_inode,
+ .statfs = simple_statfs,
+ .drop_inode = generic_delete_inode,
+};
+
+struct dentry *rcfs_rootde; /* redundant; can also get it from sb */
+static struct inode *rcfs_root;
+static struct rcfs_inode_info *rcfs_rootri;
+
+static int rcfs_fill_super(struct super_block *sb, void *data, int silent)
+{
+ struct inode *inode;
+ struct dentry *root;
+ struct rcfs_inode_info *rootri;
+ struct ckrm_classtype *clstype;
+ int i, rc;
+
+ sb->s_fs_info = NULL;
+ if (rcfs_mounted) {
+ return -EPERM;
+ }
+ rcfs_mounted++;
+
+ sb->s_blocksize = PAGE_CACHE_SIZE;
+ sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
+ sb->s_magic = RCFS_MAGIC;
+ sb->s_op = &rcfs_super_ops;
+ inode = rcfs_get_inode(sb, S_IFDIR | 0755, 0);
+ if (!inode)
+ return -ENOMEM;
+ inode->i_op = &rcfs_rootdir_inode_operations;
+
+ root = d_alloc_root(inode);
+ if (!root) {
+ iput(inode);
+ return -ENOMEM;
+ }
+ sb->s_root = root;
+
+ /* Link inode and core class */
+ rootri = RCFS_I(inode);
+ rootri->name = kmalloc(strlen(RCFS_ROOT) + 1, GFP_KERNEL);
+ if (!rootri->name) {
+ d_delete(root);
+ iput(inode);
+ return -ENOMEM;
+ }
+ strcpy(rootri->name, RCFS_ROOT);
+ rootri->core = NULL;
+
+ rcfs_root = inode;
+ sb->s_fs_info = rcfs_root = inode;
+ rcfs_rootde = root;
+ rcfs_rootri = rootri;
+
+ /* register metatypes */
+ for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) {
+ clstype = ckrm_classtypes[i];
+ if (clstype == NULL)
+ continue;
+ printk("A non null classtype\n");
+
+ if ((rc = rcfs_register_classtype(clstype)))
+ continue; /* could return with an error too */
+ }
+
+ /*
+ * do post-mount initializations needed by CE
+ * this is distinct from CE registration done on rcfs module load
+ */
+ if (rcfs_engine_regd) {
+ if (rcfs_eng_callbacks.mnt)
+ if ((rc = (*rcfs_eng_callbacks.mnt) ())) {
+ printk(KERN_ERR "Error in CE mnt %d\n", rc);
+ }
+ }
+ /*
+ * Following comment handled by code above; keep nonetheless if it
+ * can be done better
+ *
+ * register CE's with rcfs
+ * check if CE loaded
+ * call rcfs_register_engine for each classtype
+ * AND rcfs_mkroot (preferably subsume latter in former)
+ */
+ return 0;
+}
+
+static struct super_block *rcfs_get_sb(struct file_system_type *fs_type,
+ int flags, const char *dev_name,
+ void *data)
+{
+ return get_sb_nodev(fs_type, flags, data, rcfs_fill_super);
+}
+
+void rcfs_kill_sb(struct super_block *sb)
+{
+ int i, rc;
+ struct ckrm_classtype *clstype;
+
+ if (sb->s_fs_info != rcfs_root) {
+ generic_shutdown_super(sb);
+ return;
+ }
+ rcfs_mounted--;
+
+ for (i = 0; i < CKRM_MAX_CLASSTYPES; i++) {
+ clstype = ckrm_classtypes[i];
+ if (clstype == NULL || clstype->rootde == NULL)
+ continue;
+
+ if ((rc = rcfs_deregister_classtype(clstype))) {
+ printk(KERN_ERR "Error removing classtype %s\n",
+ clstype->name);
+ }
+ }
+
+ /*
+ * do pre-umount shutdown needed by CE
+ * this is distinct from CE deregistration done on rcfs module unload
+ */
+ if (rcfs_engine_regd) {
+ if (rcfs_eng_callbacks.umnt)
+ if ((rc = (*rcfs_eng_callbacks.umnt) ())) {
+ printk(KERN_ERR "Error in CE umnt %d\n", rc);
+ /* TODO: return ; until error handling improves */
+ }
+ }
+ /*
+ * Following comment handled by code above; keep nonetheless if it
+ * can be done better
+ *
+ * deregister CE with rcfs
+ * Check if loaded
+ * if ce is in one directory /rcfs/ce,
+ * rcfs_deregister_engine for all classtypes within above
+ * codebase
+ * followed by
+ * rcfs_rmroot here
+ * if ce in multiple (per-classtype) directories
+ * call rbce_deregister_engine within ckrm_deregister_classtype
+ *
+ * following will automatically clear rcfs root entry including its
+ * rcfs_inode_info
+ */
+
+ generic_shutdown_super(sb);
+}
+
+static struct file_system_type rcfs_fs_type = {
+ .name = "rcfs",
+ .get_sb = rcfs_get_sb,
+ .kill_sb = rcfs_kill_sb,
+};
+
+struct rcfs_functions my_rcfs_fn = {
+ .mkroot = rcfs_mkroot,
+ .rmroot = rcfs_rmroot,
+ .register_classtype = rcfs_register_classtype,
+ .deregister_classtype = rcfs_deregister_classtype,
+};
+
+extern struct rcfs_functions rcfs_fn;
+
+static int __init init_rcfs_fs(void)
+{
+ int ret;
+
+ ret = register_filesystem(&rcfs_fs_type);
+ if (ret)
+ goto init_register_err;
+ ret = rcfs_init_inodecache();
+ if (ret)
+ goto init_cache_err;
+ rcfs_fn = my_rcfs_fn;
+ /*
+ * Due to tight coupling of this module with ckrm
+ * do not allow this module to be removed.
+ */
+ try_module_get(THIS_MODULE);
+ return ret;
+
+init_cache_err:
+ unregister_filesystem(&rcfs_fs_type);
+init_register_err:
+ return ret;
+}
+
+static void __exit exit_rcfs_fs(void)
+{
+ rcfs_destroy_inodecache();
+ unregister_filesystem(&rcfs_fs_type);
+}
+
+module_init(init_rcfs_fs)
+module_exit(exit_rcfs_fs)
+
+MODULE_LICENSE("GPL");
Index: linux-2.6.10-rc2/init/Kconfig
===================================================================
--- linux-2.6.10-rc2.orig/init/Kconfig 2004-11-19 20:41:45.572898412 -0800
+++ linux-2.6.10-rc2/init/Kconfig 2004-11-19 20:44:18.288704188 -0800
@@ -152,6 +152,17 @@
If you say Y here, enable the Resource Class File System and atleast
one of the resource controllers below. Say N if you are unsure.

+config RCFS_FS
+ tristate "Resource Class File System (User API)"
+ depends on CKRM
+ help
+ RCFS is the filesystem API for CKRM. This separate configuration
+ option is provided only for debugging and will eventually disappear
+ since rcfs will be automounted whenever CKRM is configured.
+
+ Say N if unsure, Y if you've enabled CKRM, M to debug rcfs
+ initialization.
+
endmenu

config SYSCTL


2004-11-29 22:18:03

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] CKRM: 4/10 CKRM: Full rcfs support

On Mon, Nov 29, 2004 at 10:48:24AM -0800, Gerrit Huizenga wrote:
> +#include <linux/module.h>
> +#include <linux/list.h>
> +#include <linux/fs.h>
> +#include <linux/namei.h>
> +#include <linux/namespace.h>
> +#include <linux/dcache.h>
> +#include <linux/seq_file.h>
> +#include <linux/pagemap.h>
> +#include <linux/highmem.h>
> +#include <linux/init.h>
> +#include <linux/string.h>
> +#include <linux/smp_lock.h>
> +#include <linux/backing-dev.h>
> +#include <linux/parser.h>
> +#include <asm/uaccess.h>
> +
> +#include <linux/rcfs.h>

asm last please.

> +/*
> + * Address of variable used as flag to indicate a magic file,
> + * value unimportant
> + */
> +int RCFS_IS_MAGIC;

Shouldn't this be static?

And what is a "magic" file used for? I see where you set something to
point to this, but no where do you check for it. What's the use of it?

> +int _rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> +{
> + struct inode *inode;
> + int error = -EPERM;
> +
> + if (dentry->d_inode)
> + return -EEXIST;
> + inode = rcfs_get_inode(dir->i_sb, mode, dev);
> + if (inode) {
> + if (dir->i_mode & S_ISGID) {
> + inode->i_gid = dir->i_gid;
> + if (S_ISDIR(mode))
> + inode->i_mode |= S_ISGID;
> + }
> + d_instantiate(dentry, inode);
> + dget(dentry);
> + error = 0;
> + }
> + return error;
> +}
> +
> +EXPORT_SYMBOL_GPL(_rcfs_mknod);
> +
> +int rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> +{
> + /* User can only create directories, not files */
> + if ((mode & S_IFMT) != S_IFDIR)
> + return -EINVAL;
> +
> + return dir->i_op->mkdir(dir, dentry, mode);
> +}
> +
> +EXPORT_SYMBOL_GPL(rcfs_mknod);

Why 2 mknod functions? Do they both really need to be exported?

> +
> +#define MAGIC_SHOW(FUNC) \
> +static int \

You mix tabs and spaces in your #defines in this file, please just use
tabs properly.

> +static ssize_t
> +target_reclassify_write(struct file *file, const char __user * buf,
> + size_t count, loff_t * ppos, int manual)
> +{
> + struct rcfs_inode_info *ri = RCFS_I(file->f_dentry->d_inode);
> + char *optbuf;
> + int rc = -EINVAL;
> + ckrm_classtype_t *clstype;
> +
> + if ((ssize_t) count < 0 || (ssize_t) count > TARGET_MAX_INPUT_SIZE)
> + return -EINVAL;

But count is an unsigned variable, right? How could it ever be
negative?

> + if (!access_ok(VERIFY_READ, buf, count))
> + return -EFAULT;
> + down(&(ri->vfs_inode.i_sem));
> + optbuf = kmalloc(TARGET_MAX_INPUT_SIZE, GFP_KERNEL);

kmalloc with a lock held? Is that a good idea?

You also don't check the return value of kmalloc, that's a bad idea.

> + __copy_from_user(optbuf, buf, count);
> + if (optbuf[count - 1] == '\n')
> + optbuf[count - 1] = '\0';

Stripping off a single trailing \n character? Why?

> +inline struct rcfs_inode_info *RCFS_I(struct inode *inode)
> +{
> + return container_of(inode, struct rcfs_inode_info, vfs_inode);
> +}
> +
> +EXPORT_SYMBOL_GPL(RCFS_I);

This should be named something sane, and just use a #define for it like
most other container_of() users.

> +void rcfs_destroy_inodecache(void)
> +{
> + printk(KERN_WARNING "destroy inodecache was called\n");

Do you really want to print this out in "production" code?

> + if (kmem_cache_destroy(rcfs_inode_cachep))
> + printk(KERN_INFO
> + "rcfs_inode_cache: not all structures were freed\n");

Shouldn't this really be INFO level? What is a user going to do with
this information?

> +config RCFS_FS
> + tristate "Resource Class File System (User API)"
> + depends on CKRM
> + help
> + RCFS is the filesystem API for CKRM. This separate configuration
> + option is provided only for debugging and will eventually disappear
> + since rcfs will be automounted whenever CKRM is configured.
> +
> + Say N if unsure, Y if you've enabled CKRM, M to debug rcfs
> + initialization.
> +

So is this option going to stay around, or should it always be enabled
if CKRM is enabled? Why not just do that for the user?

thanks,

greg k-h

2005-02-24 09:39:09

by Gerrit Huizenga

[permalink] [raw]
Subject: Re: [PATCH] CKRM: 4/10 CKRM: Full rcfs support


On Mon, 29 Nov 2004 14:15:48 PST, Greg KH wrote:
> On Mon, Nov 29, 2004 at 10:48:24AM -0800, Gerrit Huizenga wrote:
> > +#include <linux/module.h>
> > +#include <linux/list.h>
> > +#include <linux/fs.h>
> > +#include <linux/namei.h>
> > +#include <linux/namespace.h>
> > +#include <linux/dcache.h>
> > +#include <linux/seq_file.h>
> > +#include <linux/pagemap.h>
> > +#include <linux/highmem.h>
> > +#include <linux/init.h>
> > +#include <linux/string.h>
> > +#include <linux/smp_lock.h>
> > +#include <linux/backing-dev.h>
> > +#include <linux/parser.h>
> > +#include <asm/uaccess.h>
> > +
> > +#include <linux/rcfs.h>
>
> asm last please.

Fixed.

> > +/*
> > + * Address of variable used as flag to indicate a magic file,
> > + * value unimportant
> > + */
> > +int RCFS_IS_MAGIC;
>
> Shouldn't this be static?

Nope - used across files.

> And what is a "magic" file used for? I see where you set something to
> point to this, but no where do you check for it. What's the use of it?

I believe that these are auto-created file entries which are instantiated
when a class is created, hence they "magically" appear. They are also
special in the sense that they are tied to the life of the class, unlike
other files in the class directories. The MAGIC value is used to help
distinguish these auto-created entries from other entries in a directory.
This is a little bit like "." and ".." but specific to the class creation.

> > +int _rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> > +{
> > + struct inode *inode;
> > + int error = -EPERM;
> > +
> > + if (dentry->d_inode)
> > + return -EEXIST;
> > + inode = rcfs_get_inode(dir->i_sb, mode, dev);
> > + if (inode) {
> > + if (dir->i_mode & S_ISGID) {
> > + inode->i_gid = dir->i_gid;
> > + if (S_ISDIR(mode))
> > + inode->i_mode |= S_ISGID;
> > + }
> > + d_instantiate(dentry, inode);
> > + dget(dentry);
> > + error = 0;
> > + }
> > + return error;
> > +}
> > +
> > +EXPORT_SYMBOL_GPL(_rcfs_mknod);
> > +
> > +int rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> > +{
> > + /* User can only create directories, not files */
> > + if ((mode & S_IFMT) != S_IFDIR)
> > + return -EINVAL;
> > +
> > + return dir->i_op->mkdir(dir, dentry, mode);
> > +}
> > +
> > +EXPORT_SYMBOL_GPL(rcfs_mknod);
>
> Why 2 mknod functions? Do they both really need to be exported?

I believe they are both exported so resource controllers can create
class specific directories (including corresponding magic files)
in the case of _rcfs_mknod, and rcfs_mknod is the exported fs op
which allows a restricted set of standard user filesystem operations
within the created directory. So, yes.

> > +
> > +#define MAGIC_SHOW(FUNC) \
> > +static int \
>
> You mix tabs and spaces in your #defines in this file, please just use
> tabs properly.

Fixed.

> > +static ssize_t
> > +target_reclassify_write(struct file *file, const char __user * buf,
> > + size_t count, loff_t * ppos, int manual)
> > +{
> > + struct rcfs_inode_info *ri = RCFS_I(file->f_dentry->d_inode);
> > + char *optbuf;
> > + int rc = -EINVAL;
> > + ckrm_classtype_t *clstype;
> > +
> > + if ((ssize_t) count < 0 || (ssize_t) count > TARGET_MAX_INPUT_SIZE)
> > + return -EINVAL;
>
> But count is an unsigned variable, right? How could it ever be
> negative?

Yep. But see how those nice casts covered up all the warnings? ;-)
(Fixed!)

> > + if (!access_ok(VERIFY_READ, buf, count))
> > + return -EFAULT;
> > + down(&(ri->vfs_inode.i_sem));
> > + optbuf = kmalloc(TARGET_MAX_INPUT_SIZE, GFP_KERNEL);
>
> kmalloc with a lock held? Is that a good idea?

Lock? Or sema? Sema should be okay here, right?

> You also don't check the return value of kmalloc, that's a bad idea.

Yep - good catch. Fixed.

> > + __copy_from_user(optbuf, buf, count);
> > + if (optbuf[count - 1] == '\n')
> > + optbuf[count - 1] = '\0';
>
> Stripping off a single trailing \n character? Why?

I believe this is the "echo value > /rcfs/class/magic_file". If
there is a newline, it would show up as an extra newline during
an ls. Of course, Shailabh can correct me if I'm wrong on this one.

> > +inline struct rcfs_inode_info *RCFS_I(struct inode *inode)
> > +{
> > + return container_of(inode, struct rcfs_inode_info, vfs_inode);
> > +}
> > +
> > +EXPORT_SYMBOL_GPL(RCFS_I);
>
> This should be named something sane, and just use a #define for it like
> most other container_of() users.

Stupid name gone. I didn't grok the need for the #define though?

> > +void rcfs_destroy_inodecache(void)
> > +{
> > + printk(KERN_WARNING "destroy inodecache was called\n");
>
> Do you really want to print this out in "production" code?

Nope. Fixed.

> > + if (kmem_cache_destroy(rcfs_inode_cachep))
> > + printk(KERN_INFO
> > + "rcfs_inode_cache: not all structures were freed\n");
>
> Shouldn't this really be INFO level? What is a user going to do with
> this information?
>
> > +config RCFS_FS
> > + tristate "Resource Class File System (User API)"
> > + depends on CKRM
> > + help
> > + RCFS is the filesystem API for CKRM. This separate configuration
> > + option is provided only for debugging and will eventually disappear
> > + since rcfs will be automounted whenever CKRM is configured.
> > +
> > + Say N if unsure, Y if you've enabled CKRM, M to debug rcfs
> > + initialization.
> > +
>
> So is this option going to stay around, or should it always be enabled
> if CKRM is enabled? Why not just do that for the user?

It may be a module, but yes, this should be auto-set in the future when
CKRM is enabled.

gerrit

2005-02-24 10:15:24

by Arjan van de Ven

[permalink] [raw]
Subject: Re: [PATCH] CKRM: 4/10 CKRM: Full rcfs support

On Thu, 2005-02-24 at 01:33 -0800, Gerrit Huizenga wrote:

> > > + if (!access_ok(VERIFY_READ, buf, count))
> > > + return -EFAULT;
> > > + down(&(ri->vfs_inode.i_sem));
> > > + optbuf = kmalloc(TARGET_MAX_INPUT_SIZE, GFP_KERNEL);
> >
> > kmalloc with a lock held? Is that a good idea?
>
> Lock? Or sema? Sema should be okay here, right?

not if that semaphore can be grabbed from a file data write out path...

and the semaphore sounds VFS-ish so it sure makes me nervous.



2005-02-24 17:53:20

by Greg KH

[permalink] [raw]
Subject: Re: [PATCH] CKRM: 4/10 CKRM: Full rcfs support

On Thu, Feb 24, 2005 at 01:33:18AM -0800, Gerrit Huizenga wrote:
> On Mon, 29 Nov 2004 14:15:48 PST, Greg KH wrote:
> > > +/*
> > > + * Address of variable used as flag to indicate a magic file,
> > > + * value unimportant
> > > + */
> > > +int RCFS_IS_MAGIC;
> >
> > Shouldn't this be static?
>
> Nope - used across files.

It shouldn't be.

> > And what is a "magic" file used for? I see where you set something to
> > point to this, but no where do you check for it. What's the use of it?
>
> I believe that these are auto-created file entries which are instantiated
> when a class is created, hence they "magically" appear. They are also
> special in the sense that they are tied to the life of the class, unlike
> other files in the class directories. The MAGIC value is used to help
> distinguish these auto-created entries from other entries in a directory.
> This is a little bit like "." and ".." but specific to the class creation.

That is just wrong.

> > > +int _rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> > > +{
> > > + struct inode *inode;
> > > + int error = -EPERM;
> > > +
> > > + if (dentry->d_inode)
> > > + return -EEXIST;
> > > + inode = rcfs_get_inode(dir->i_sb, mode, dev);
> > > + if (inode) {
> > > + if (dir->i_mode & S_ISGID) {
> > > + inode->i_gid = dir->i_gid;
> > > + if (S_ISDIR(mode))
> > > + inode->i_mode |= S_ISGID;
> > > + }
> > > + d_instantiate(dentry, inode);
> > > + dget(dentry);
> > > + error = 0;
> > > + }
> > > + return error;
> > > +}
> > > +
> > > +EXPORT_SYMBOL_GPL(_rcfs_mknod);
> > > +
> > > +int rcfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
> > > +{
> > > + /* User can only create directories, not files */
> > > + if ((mode & S_IFMT) != S_IFDIR)
> > > + return -EINVAL;
> > > +
> > > + return dir->i_op->mkdir(dir, dentry, mode);
> > > +}
> > > +
> > > +EXPORT_SYMBOL_GPL(rcfs_mknod);
> >
> > Why 2 mknod functions? Do they both really need to be exported?
>
> I believe they are both exported so resource controllers can create
> class specific directories (including corresponding magic files)
> in the case of _rcfs_mknod, and rcfs_mknod is the exported fs op
> which allows a restricted set of standard user filesystem operations
> within the created directory. So, yes.

Then name the functions sanely. As it is, they are not descriptive of
what they actually do at all.

> > > + __copy_from_user(optbuf, buf, count);
> > > + if (optbuf[count - 1] == '\n')
> > > + optbuf[count - 1] = '\0';
> >
> > Stripping off a single trailing \n character? Why?
>
> I believe this is the "echo value > /rcfs/class/magic_file". If
> there is a newline, it would show up as an extra newline during
> an ls. Of course, Shailabh can correct me if I'm wrong on this one.

So what if a user adds 2 \n to the end of the string. You missed that
one. If you are going to try to protect the names of your files, don't
do it half-hearted...

> > > +inline struct rcfs_inode_info *RCFS_I(struct inode *inode)
> > > +{
> > > + return container_of(inode, struct rcfs_inode_info, vfs_inode);
> > > +}
> > > +
> > > +EXPORT_SYMBOL_GPL(RCFS_I);
> >
> > This should be named something sane, and just use a #define for it like
> > most other container_of() users.
>
> Stupid name gone. I didn't grok the need for the #define though?

Use a #define, not a inline function for this, like everyone else in the
kernel does for their container_of macros. Actually inline functions
can't be exported anyway...

> > > +config RCFS_FS
> > > + tristate "Resource Class File System (User API)"
> > > + depends on CKRM
> > > + help
> > > + RCFS is the filesystem API for CKRM. This separate configuration
> > > + option is provided only for debugging and will eventually disappear
> > > + since rcfs will be automounted whenever CKRM is configured.
> > > +
> > > + Say N if unsure, Y if you've enabled CKRM, M to debug rcfs
> > > + initialization.
> > > +
> >
> > So is this option going to stay around, or should it always be enabled
> > if CKRM is enabled? Why not just do that for the user?
>
> It may be a module, but yes, this should be auto-set in the future when
> CKRM is enabled.

Then fix it? :)

greg k-h

2005-02-24 22:25:12

by Shailabh Nagar

[permalink] [raw]
Subject: Re: [ckrm-tech] Re: [PATCH] CKRM: 4/10 CKRM: Full rcfs support

Greg KH wrote:
>
>>>>+config RCFS_FS
>>>>+ tristate "Resource Class File System (User API)"
>>>>+ depends on CKRM
>>>>+ help
>>>>+ RCFS is the filesystem API for CKRM. This separate configuration
>>>>+ option is provided only for debugging and will eventually disappear
>>>>+ since rcfs will be automounted whenever CKRM is configured.
>>>>+
>>>>+ Say N if unsure, Y if you've enabled CKRM, M to debug rcfs
>>>>+ initialization.
>>>>+
>>>
>>>So is this option going to stay around, or should it always be enabled
>>>if CKRM is enabled? Why not just do that for the user?
>>
>>It may be a module, but yes, this should be auto-set in the future when
>>CKRM is enabled.
>
>
> Then fix it? :)
>
> greg k-h

Sounds like a case is being made to make CONFIG_RCFS a "y" and eliminate
the possibility of it being a loadable module ? If so, I don't think its
a good idea. While a kernel may have CKRM enabled, the user may choose
not to use it. In such a case, he should have the option of not loading
the rcfs module.

How does one restrict the choices of a tristate variable to exclude just
the N selection ? It wasn't clear from the kconfig-language.txt...any
pointers appreciated.


-- Shailabh



2005-02-24 23:25:55

by Chris Friesen

[permalink] [raw]
Subject: Re: [ckrm-tech] Re: [PATCH] CKRM: 4/10 CKRM: Full rcfs support

Shailabh Nagar wrote:

> Sounds like a case is being made to make CONFIG_RCFS a "y" and eliminate
> the possibility of it being a loadable module ?

No, I believe the idea was to make CONFIG_RCFS be automatically set to
the same as CKRM.

Chris

2005-02-25 00:04:51

by Gerrit Huizenga

[permalink] [raw]
Subject: Re: [ckrm-tech] Re: [PATCH] CKRM: 4/10 CKRM: Full rcfs support


On Thu, 24 Feb 2005 17:25:28 CST, Chris Friesen wrote:
> Shailabh Nagar wrote:
>
> > Sounds like a case is being made to make CONFIG_RCFS a "y" and eliminate
> > the possibility of it being a loadable module ?
>
> No, I believe the idea was to make CONFIG_RCFS be automatically set to
> the same as CKRM.

Right, but CONFIG_CKRM is a Y/N, rcfs can be a module which is loaded
or not, depending on whether someone actually wants to *use* classes
in CKRM.

In theory, distros could build with CKRM set to "Y" but leave RCFS
as a module to simplify testing. It dosn't matter too much to me but
it seems like having the flexibility of leaving rcfs as a module
is a nice capability.

I'm willing to be hear all comments. ;-)

gerrit