#include #include #include #include #include #include #include #include #include #include #include struct dentry *voidfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data); static int voidfs_fill_super(struct super_block *sb, void *data, int silent); void voidfs_kill_superblock(struct super_block *sb); struct dentry *voidfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int); int voidfs_readdir(struct file *fp, struct dir_context *ctx); int voidfs_open(struct inode *inode, struct file *fp); ssize_t voidfs_read(struct file *fp, char __user *buf, size_t len, loff_t *ppos); ssize_t voidfs_write(struct file *fp, const char __user *buf, size_t len, loff_t *ppos); struct file_system_type voidfs_fs_type = { .owner = THIS_MODULE, .name = "voidfs", .mount = voidfs_mount, .kill_sb = voidfs_kill_superblock, .fs_flags = FS_REQUIRES_DEV, }; struct super_operations voidfs_super_ops = { // null for now }; struct inode_operations voidfs_inode_ops = { .lookup = voidfs_lookup, }; struct file_operations voidfs_dir_ops = { .iterate_shared = voidfs_readdir, }; struct file_operations voidfs_file_ops = { .open = voidfs_open, .read = voidfs_read, .write = voidfs_write, }; struct dentry *voidfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int) { struct inode* inode = NULL; printk(KERN_INFO "listing directory %s %s", dentry->d_parent->d_name.name, dentry->d_name.name); printk(KERN_INFO " %p %p", dentry->d_inode, dir->i_sb); // parse an entry path // right now, let's just create a dummy path if (strcmp(dentry->d_name.name, "dummyfile") == 0) { // inode->i_sb = sb; inode = new_inode(dir->i_sb); inode->i_op = &voidfs_inode_ops; inode->i_fop = &voidfs_file_ops; inode->i_mode = S_IFREG | 0644; inode->i_ino = 3; // inode->i_private = (void*)1; } d_add(dentry, inode); return NULL; } int voidfs_readdir(struct file *dir, struct dir_context *ctx) { // populate directory entry maybe struct inode *inode; struct super_block *sb; printk(KERN_INFO "readdir"); if (ctx->pos > 3) { return -ENOENT; } inode = file_inode(dir); sb = inode->i_sb; dir_emit_dots(dir, ctx); dir_emit(ctx, "dummydir", 8, 2, DT_DIR); ctx->pos += 1; dir_emit(ctx, "dummyfile", 9, 3, DT_REG); ctx->pos += 1; return 0; } int voidfs_open(struct inode *inode, struct file *fp) { printk(KERN_INFO "voidfs open"); return 0; } ssize_t voidfs_read(struct file *fp, char __user *buf, size_t len, loff_t *ppos) { struct inode *inode; struct super_block *sb; printk(KERN_INFO "voidfs read"); // we only allow read 1 time, should be at the start if (*ppos > 0) { return 0; } inode = file_inode(fp); if (!inode) { return -EFAULT; } sb = inode->i_sb; // we don't read from the block device for now // so return a dummy string char* buffer = "this is a voidfs file"; ssize_t nbytes = 21; // get file buffer // move the offset // get as much as we can if (copy_to_user(buf, buffer, nbytes)) { printk(KERN_ERR "Error copying file content to userspace buffer\n"); return -EFAULT; } *ppos += nbytes; return nbytes; } ssize_t voidfs_write(struct file *fp, const char __user *buf, size_t len, loff_t *ppos) { return 0; } struct dentry *voidfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { printk(KERN_INFO "voidfs try to mount %s\n", dev_name); struct dentry *ret; ret = mount_bdev(fs_type, flags, dev_name, data, voidfs_fill_super); if (unlikely(IS_ERR(ret))) { printk(KERN_ERR "Error mounting voidfs.\n"); } else { printk(KERN_INFO "voidfs is succesfully mounted on: %s\n", dev_name); } return ret; } // initialize super block metadata static int voidfs_fill_super(struct super_block *sb, void *data, int silent) { struct inode *root_inode; struct inode *dummy_body; sb->s_magic = 0x44445555; sb->s_op = &voidfs_super_ops; sb_set_blocksize(sb, 1 << 12 /* 4 kilobyte */); sb->s_maxbytes = (1 << 12) * 10; // we don't get a read on file for now, because we still have // to define the internal format // create a dummy root node that we can access root_inode = new_inode(sb); if (!root_inode) { return -ENOMEM; } root_inode->i_mode = S_IFDIR | 0644; inode_init_owner(&nop_mnt_idmap, root_inode, NULL, root_inode->i_mode); root_inode->i_sb = sb; root_inode->i_op = &voidfs_inode_ops; root_inode->i_fop = &voidfs_dir_ops; sb->s_root = d_make_root(root_inode); // create a dummy file entry point // root_inode->i_fop = &voidfs_file_ops; // create a child file return 0; } void voidfs_kill_superblock(struct super_block *sb) { printk(KERN_INFO "voidfs try to unmount\n"); kill_block_super(sb); } static int __init voidfs_init(void) { int ret; ret = register_filesystem(&voidfs_fs_type); if (likely(0 == ret)) { printk(KERN_INFO "Sucessfully registered voidfs\n"); } else { printk(KERN_ERR "Failed to register voidfs. Error code: %d\n", ret); } return ret; } static void __exit voidfs_exit(void) { int ret; ret = unregister_filesystem(&voidfs_fs_type); // kmem_cache_destroy(voidfs_inode_cache); if (likely(ret == 0)) { printk(KERN_INFO "Sucessfully unregistered voidfs\n"); } else { printk(KERN_ERR "Failed to unregister voidfs. Error code: %d\n", ret); } } module_init(voidfs_init); module_exit(voidfs_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("nganhkhoa");