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
This commit is contained in:
commit
9e05e670b4
6
Makefile
Normal file
6
Makefile
Normal file
@ -0,0 +1,6 @@
|
||||
#
|
||||
# Makefile for the fpgafs virtual filesystem
|
||||
#
|
||||
obj-$(CONFIG_FPGA_FS) += fpgafs.o
|
||||
|
||||
fpgafs-objs := inode.o files.o
|
71
files.c
Normal file
71
files.c
Normal file
@ -0,0 +1,71 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#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, },
|
||||
{},
|
||||
};
|
29
fpgafs.h
Normal file
29
fpgafs.h
Normal file
@ -0,0 +1,29 @@
|
||||
#ifndef FPGAFS_H
|
||||
#define FPGAFS_H
|
||||
|
||||
#include <linux/kref.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/fs.h>
|
||||
|
||||
/* 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 */
|
307
inode.c
Normal file
307
inode.c
Normal file
@ -0,0 +1,307 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
|
||||
#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 <ben@codiert.org>");
|
Loading…
Reference in New Issue
Block a user