init
This commit is contained in:
commit
e087715248
6
Makefile
Normal file
6
Makefile
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
obj-m += voidfs.o
|
||||||
|
|
||||||
|
all: voidfs
|
||||||
|
|
||||||
|
voidfs:
|
||||||
|
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
|
21
README
Normal file
21
README
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
# Void Filesystem
|
||||||
|
|
||||||
|
Just a dummy filesystem for learning.
|
||||||
|
|
||||||
|
## Virtual Filesystem (VFS)
|
||||||
|
|
||||||
|
Linux VFS allows us to write customize filesystem. The filesystem must be able to mount, other operations such as file read/write or folder creation/deletion can be customized.
|
||||||
|
|
||||||
|
A filesystem can be virtual, without a backed-up device. This is the case for, I guess, network file descriptors. For filesystem with a backed-up device, usually a block device, the underlying block device can be accessed by sb_bread to read a block.
|
||||||
|
|
||||||
|
Internally, a filesystem must provide a superblock, that will be used as a pointer to read files.
|
||||||
|
|
||||||
|
When a file is read, the inode of the file entry can be accessed. If we also keep the internal data of the file in `inode->i_private`, we can fetch that to read the file system through `sb_read(inode->sb)`.
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
[simplefs](https://github.com/sysprog21/simplefs)
|
||||||
|
|
||||||
|
[Linux Kernel Labs - File system drivers](https://linux-kernel-labs.github.io/refs/heads/master/labs/filesystems_part1.html)
|
||||||
|
|
||||||
|
[Linux Kernel Documentation](https://docs.kernel.org/filesystems/vfs.html)
|
194
voidfs.c
Normal file
194
voidfs.c
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/buffer_head.h>
|
||||||
|
#include <linux/fs.h>
|
||||||
|
#include <linux/init.h>
|
||||||
|
#include <linux/namei.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/parser.h>
|
||||||
|
#include <linux/random.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
#include <linux/time.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
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 super_operations voidfs_inode_ops = {
|
||||||
|
// null for now
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_operations voidfs_dir_ops = {
|
||||||
|
.iterate_shared = voidfs_readdir,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct file_operations voidfs_file_ops = {
|
||||||
|
.read = voidfs_read,
|
||||||
|
.write = voidfs_write,
|
||||||
|
}
|
||||||
|
|
||||||
|
int voidfs_readdir(struct file *fp, struct dir_context *ctx) {
|
||||||
|
// populate directory entry maybe
|
||||||
|
struct inode *inode;
|
||||||
|
struct super_block *sb;
|
||||||
|
|
||||||
|
printk(KERN_INFO "readdir");
|
||||||
|
|
||||||
|
inode = file_inode(file);
|
||||||
|
sb = inode->i_sb;
|
||||||
|
|
||||||
|
// if (inode &&
|
||||||
|
// !dir_emit(ctx, f->filename, SIMPLEFS_FILENAME_LEN, f->inode,
|
||||||
|
// DT_UNKNOWN))
|
||||||
|
// break;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
inode = file_inode(file);
|
||||||
|
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)) {
|
||||||
|
brelse(bh);
|
||||||
|
printk(KERN_ERR
|
||||||
|
"Error copying file content to userspace buffer\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t voidfs_write(struct file *fp, const char __user *buf, size_t len, loff_t *ppos) {
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
inode_init_owner(root_inode, NULL, root_inode->i_mode);
|
||||||
|
|
||||||
|
root_inode->i_sb = sb;
|
||||||
|
root_inode->i_op = &voidfs_inode_ops;
|
||||||
|
root_inode->i_atime = root_inode->i_mtime
|
||||||
|
= root_inode->i_ctime
|
||||||
|
= CURRENT_TIME;
|
||||||
|
|
||||||
|
root_inode->i_fop = &voidfs_dir_ops;
|
||||||
|
|
||||||
|
// create a dummy file entry point
|
||||||
|
root_inode->i_fop = &voidfs_file_ops;
|
||||||
|
|
||||||
|
sb->s_root = d_make_root(root_inode);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void voidfs_kill_superblock(struct super_block *sb) {
|
||||||
|
printk(KERN_INFO "voidfs try to unmount\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __init voidfs_init(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
// hellofs_inode_cache = kmem_cache_create("hellofs_inode_cache",
|
||||||
|
// sizeof(struct hellofs_inode),
|
||||||
|
// 0,
|
||||||
|
// (SLAB_RECLAIM_ACCOUNT| SLAB_MEM_SPREAD),
|
||||||
|
// NULL);
|
||||||
|
// if (!hellofs_inode_cache) {
|
||||||
|
// return -ENOMEM;
|
||||||
|
// }
|
||||||
|
|
||||||
|
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("MIT");
|
||||||
|
MODULE_AUTHOR("nganhkhoa");
|
Loading…
Reference in New Issue
Block a user