commit 9e05e670b44fa47b5aaed003670dcb63f3ff49fb Author: ben Date: Thu Jun 28 16:20:34 2007 +0000 initial commit of the fpgafs git-svn-id: svn+ssh://en.codiert.org/home/staff/ben/dev/misc.svn/projects/fpgafs@338 766a2236-cff9-0310-b0c0-a81a5f92509a diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..ac643f7 --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the fpgafs virtual filesystem +# +obj-$(CONFIG_FPGA_FS) += fpgafs.o + +fpgafs-objs := inode.o files.o diff --git a/files.c b/files.c new file mode 100644 index 0000000..1a34109 --- /dev/null +++ b/files.c @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include +#include +#include "fpgafs.h" + +/* generic open function for all pipe-like files */ +static int fpgafs_pipe_open(struct inode *inode, struct file *file) +{ + struct fpgafs_inode_info *i = FPGAFS_I(inode); + file->private_data = i->i_ctx; + + return nonseekable_open(inode, file); +} + +static ssize_t fpgafs_stat_read(struct file *file, char __user *buf, + size_t len, loff_t *pos) +{ + struct fpga_context *ctx = file->private_data; + u32 data, __user *udata; + ssize_t count; + + if (len < 4) + return -EINVAL; + + if (!access_ok(VERIFY_WRITE, buf, len)) + return -EFAULT; + + udata = (void __user *)buf; + + for (count = 0; (count + 4) <= len; count += 4, udata++) { + int ret; + + /* operation to read the status ... */ + data=0x42; + ret = 0; + if (ret == 0) + break; + + ret = __put_user(data, udata); + + if (ret) { + if (!count) + count = -EFAULT; + break; + } + } + + if (!count) + count = -EAGAIN; + + return count; +} + +static const struct file_operations fpgafs_stat_fops = { + .open = fpgafs_pipe_open, + .read = fpgafs_stat_read, +}; + +struct tree_descr fpgafs_dir_contents[] = { +#if 0 + { "cmd", &fpgafs_cmd_fops, 0222, }, + { "din", &spufs_mbox_fops, 0222, }, + { "dout", &spufs_ibox_fops, 0444, }, + { "load", &spufs_wbox_fops, 0666, }, +#endif + { "stat", &fpgafs_stat_fops, 0444, }, + {}, +}; diff --git a/fpgafs.h b/fpgafs.h new file mode 100644 index 0000000..ee15ad2 --- /dev/null +++ b/fpgafs.h @@ -0,0 +1,29 @@ +#ifndef FPGAFS_H +#define FPGAFS_H + +#include +#include +#include +#include + +/* magic number the file system */ +enum { + FPGAFS_MAGIC = 0x4255AA42, +}; + +struct fpga_context { + int bla1; + int bla2; +}; + +struct fpgafs_inode_info { + struct fpga_context *i_ctx; + struct inode vfs_inode; +}; + +extern struct tree_descr fpgafs_dir_contents[]; + +#define FPGAFS_I(inode) \ + container_of(inode, struct fpgafs_inode_info, vfs_inode) + +#endif /* FPGAFS_H */ diff --git a/inode.c b/inode.c new file mode 100644 index 0000000..3e35049 --- /dev/null +++ b/inode.c @@ -0,0 +1,307 @@ +#include +#include +#include +#include +#include + +#include "fpgafs.h" + +static struct inode *fpgafs_alloc_inode(struct super_block *sb); +static void fpgafs_destroy_inode(struct inode *inode); +static void fpgafs_delete_inode(struct inode *inode); +static struct inode *fpgafs_new_inode(struct super_block *sb, int mode); + +static void fpgafs_prune_dir(struct dentry *dir); +int fpgafs_mkdir(struct inode *dir, struct dentry *dentry, int mode); +static int fpgafs_rmdir(struct inode *dir, struct dentry *dentry); + +static int fpgafs_new_file(struct super_block *sb, struct dentry *dentry, + const struct file_operations *fops, int mode, + struct fpga_context *ctx); +static int fpgafs_setattr(struct dentry *dentry, struct iattr *attr); + +const struct file_operations fpgafs_context_foperations = { + .open = dcache_dir_open, + //.release = fpgafs_dir_close, + .llseek = dcache_dir_lseek, + .read = generic_read_dir, + .readdir = dcache_readdir, + .fsync = simple_sync_file, +}; + +const struct inode_operations fpgafs_simple_dir_inode_operations = { + .lookup = simple_lookup, +}; + +const struct inode_operations fpgafs_dir_inode_operations = { + .lookup = simple_lookup, + .mkdir = fpgafs_mkdir, + .rmdir = fpgafs_rmdir, +}; + +static struct kmem_cache *fpgafs_inode_cache; + +/* basic inode operations */ +static struct inode *fpgafs_alloc_inode(struct super_block *sb) +{ + struct fpgafs_inode_info *fsi; + + fsi = kmem_cache_alloc(fpgafs_inode_cache, GFP_KERNEL); + if (!fsi) + return NULL; + + fsi->i_ctx = NULL; + + return &fsi->vfs_inode; +} + +static void fpgafs_destroy_inode(struct inode *inode) +{ + kmem_cache_free(fpgafs_inode_cache, FPGAFS_I(inode)); +} + +static void fpgafs_delete_inode(struct inode *inode) +{ + //struct fpgafs_inode_info *fsi = FPGAFS_I(inode); + +// XXX: do some fpga interface operations.... +// if (fsi->i_ctx) +// put_fpga_context(ei->i_ctx); + clear_inode(inode); +} + +static struct inode *fpgafs_new_inode(struct super_block *sb, int mode) +{ + struct inode *inode; + + inode = new_inode(sb); + if (!inode) + return inode; + + inode->i_mode = mode; + inode->i_uid = current->fsuid; + inode->i_gid = current->fsgid; + inode->i_blocks = 0; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + return inode; +} + +/* FPGA FS specific functions */ +static int fpgafs_fill_dir(struct dentry *dir, struct tree_descr *files, + int mode, struct fpga_context *ctx) +{ + struct dentry *dentry; + int ret; + + while (files->name && files->name[0]) { + ret = -ENOMEM; + dentry = d_alloc_name(dir, files->name); + if (!dentry) + goto out; + ret = fpgafs_new_file(dir->d_sb, dentry, files->ops, + files->mode & mode, ctx); + if (ret) + goto out; + files++; + } + + return 0; +out: + fpgafs_prune_dir(dir); + return ret; +} + + +/* specific operations */ +static int fpgafs_setattr(struct dentry *dentry, struct iattr *attr) +{ + struct inode *inode = dentry->d_inode; + + if ((attr->ia_valid & ATTR_SIZE) && + (attr->ia_size != inode->i_size)) + return -EINVAL; + return inode_setattr(inode, attr); +} + +static int fpgafs_new_file(struct super_block *sb, struct dentry *dentry, + const struct file_operations *fops, int mode, + struct fpga_context *ctx) +{ + static struct inode_operations fpgafs_file_iops = { + .setattr = fpgafs_setattr, + }; + struct inode *inode; + int ret; + + ret = -ENOSPC; + inode = fpgafs_new_inode(sb, S_IFREG | mode); + if (!inode) + goto out; + + ret = 0; + inode->i_op = &fpgafs_file_iops; + inode->i_fop = fops; + //inode->i_private = SPUFS_I(inode)->i_ctx = get_spu_context(ctx); + d_add(dentry, inode); +out: + return ret; +} + +int fpgafs_mkdir( struct inode *dir, struct dentry *dentry, int mode) +{ + int ret; + struct inode *inode; + struct fpga_context *ctx; + + ret = -ENOSPC; + inode = fpgafs_new_inode(dir->i_sb, mode | S_IFDIR); + if (!inode) + goto unmutex; + + if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + inode->i_mode &= S_ISGID; + } + // ctx = alloc fpga context .... + // FPGAFS_I(inode)->i_ctx = ctx; + //if (!ctx) + // goto unmutex; + + inode->i_op = &fpgafs_simple_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + + ret = fpgafs_fill_dir(dentry, fpgafs_dir_contents, mode, ctx); + ret = 0; + //if (ret) { + // FREEE CONTENT + // goto unmutex; + //} + + d_instantiate(dentry, inode); + dget(dentry); + dir->i_nlink++; + dentry->d_inode->i_nlink++; + +unmutex: + mutex_unlock(&inode->i_mutex); + return ret; +} + +static void fpgafs_prune_dir(struct dentry *dir) +{ + struct dentry *dentry, *tmp; + + mutex_lock(&dir->d_inode->i_mutex); + list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) { + spin_lock(&dcache_lock); + spin_lock(&dentry->d_lock); + if (!(d_unhashed(dentry)) && dentry->d_inode) { + dget_locked(dentry); + __d_drop(dentry); + spin_unlock(&dentry->d_lock); + simple_unlink(dir->d_inode, dentry); + spin_unlock(&dcache_lock); + dput(dentry); + } else { + spin_unlock(&dentry->d_lock); + spin_unlock(&dcache_lock); + } + } + shrink_dcache_parent(dir); + mutex_unlock(&dir->d_inode->i_mutex); +} + +/* Caller must hold parent->i_mutex */ +static int fpgafs_rmdir(struct inode *dir, struct dentry *dentry) +{ + /* remove all entries */ + // fpgafs_prune_dir(dir); + //fpgafs_remove_inode + + return simple_rmdir(dir, dentry); +} + +/* SUPERBLOCK operations */ +int fpgafs_fill_sb(struct super_block *sb, void *data, int silent) +{ + struct inode *inode; + int ret = -ENOMEM; + + static struct super_operations fpgafs_ops = { + //.read_inode = fpgafs_read_inode, + //.put_super = fpgafs_put_super, + .alloc_inode = fpgafs_alloc_inode, + .destroy_inode = fpgafs_destroy_inode, + .statfs = simple_statfs, + .delete_inode = fpgafs_delete_inode, + .drop_inode = generic_delete_inode, + }; + + sb->s_maxbytes = MAX_LFS_FILESIZE; + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = FPGAFS_MAGIC; + sb->s_op = &fpgafs_ops; + + inode = fpgafs_new_inode(sb, S_IFDIR | 0775); + if (!inode) + return ret; + + inode->i_op = &fpgafs_dir_inode_operations; + inode->i_fop = &simple_dir_operations; + FPGAFS_I(inode)->i_ctx = NULL; + + sb->s_root = d_alloc_root(inode); + if (!sb->s_root) + return ret; + + return 0; +} + +static int fpgafs_get_sb(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data, struct vfsmount *mnt) +{ + return get_sb_nodev(fs_type, flags, data, fpgafs_fill_sb, mnt); +} + +static struct file_system_type fpgafs_type = { + .owner = THIS_MODULE, + .name = "fpgafs", + .get_sb = fpgafs_get_sb, + .kill_sb = kill_anon_super +}; + +static void fpgafs_init_once(void *p, struct kmem_cache * cachep, + unsigned long flags) +{ + struct fpgafs_inode_info *fsi = p; + if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == + SLAB_CTOR_CONSTRUCTOR) { + inode_init_once(&fsi->vfs_inode); + } +} + +/* init exit functions ... */ +int __init fpgafs_init(void) +{ + fpgafs_inode_cache = kmem_cache_create("fpgafs_inode_cache", + sizeof(struct fpgafs_inode_info), 0, + SLAB_HWCACHE_ALIGN, fpgafs_init_once, NULL); + if(!fpgafs_inode_cache) + return -ENOMEM; + + register_filesystem(&fpgafs_type); + return 0; +} + +void __exit fpgafs_exit(void) +{ + kmem_cache_destroy(fpgafs_inode_cache); + unregister_filesystem(&fpgafs_type); +} + +module_init(fpgafs_init); +module_exit(fpgafs_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Benjamin Krill ");