通过对内存区域的读写完成的一个最简文件系统。后续将陆续更新升级该文件系统
功能。
参考https://mp.weixin.qq.com/s/Sidfn8CZn4KxKh6xMH2uJQ
修复了其中删除目录的bug
#include<linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include<linux/uaccess.h>
#include <linux/blkdev.h>
#define MAXLEN 8
#define MAX_FILES 32
#define MAX_BLOCKSIZE 512
#define SIMPFS_MAGIC 0xeeffddcc
//printk("%s [%d] ", __func__,__LINE__,fmt,##arg)
#define PRINT_LOG(fmt,arg...) \
printk("[%s %d ] "fmt, __func__,__LINE__,##arg)
struct dir_entry
{
char filename[MAXLEN];
uint8_t idx;
};
// 定义每一个文件的格式。
struct file_blk
{
uint8_t used;
mode_t mode;
uint8_t idx;
union{
uint8_t file_size;
uint8_t dir_children;
};
char data[0];
};
struct file_blk block[MAX_FILES+1];
int curr_count = 0;
// 获得一个空闲的文件块
static int get_block(void)
{
int i;
for(i = 2; i < MAX_FILES; i++)
{
if (!block[i].used)
{
block[i].used =1;
PRINT_LOG(" index:%d\r\n",i);
return i;
}
}
return-1;
}
static struct inode_operations simpfs_inode_ops;
static int simpfs_readdir(struct file *filp, void*dirent, filldir_t filldir)
{
loff_t pos;
struct file_blk *blk;
struct dir_entry *entry;
int i;
pos = filp->f_pos;
if (pos)
return 0;
PRINT_LOG(" \r\n");
blk = (struct file_blk *)filp->f_dentry->d_inode->i_private;
if (!S_ISDIR(blk->mode))
{
return-ENOTDIR;
}
entry = (struct dir_entry *)&blk->data[0];
for (i= 0; i < blk->dir_children; i++)
{
filldir(dirent, entry[i].filename, MAXLEN, pos, entry[i].idx, DT_UNKNOWN);
filp->f_pos += sizeof(struct dir_entry);
pos += sizeof(struct dir_entry);
}
return 0;
}
ssize_t simpfs_read(struct file * filp, char __user * buf, size_t len, loff_t *ppos)
{
struct file_blk *blk;
char *buffer;
blk =(struct file_blk *)filp->f_path.dentry->d_inode->i_private;
if (*ppos >= blk->file_size)
return 0;
PRINT_LOG(" pos:%d len:%d\r\n",*ppos,len);
buffer =(char *)&blk->data[0];
len = min((size_t) blk->file_size, len);
if (copy_to_user(buf, buffer, len)) {
return -EFAULT;
}
*ppos += len;
return len;
}
ssize_t simpfs_write(struct file * filp, const char __user * buf, size_t len, loff_t * ppos)
{
struct file_blk *blk;
char *buffer;
PRINT_LOG(" pos:%d len:%d\r\n",*ppos,len);
blk = filp->f_path.dentry->d_inode->i_private;
buffer =(char *)&blk->data[0];
buffer += *ppos;
if (copy_from_user(buffer, buf, len))
{
return -EFAULT;
}
*ppos += len;
blk->file_size = *ppos;
return len;
}
const struct file_operations simpfs_file_operations = {
.read = simpfs_read,
.write = simpfs_write,
};
const struct file_operations simpfs_dir_operations = {
.owner = THIS_MODULE,
.readdir = simpfs_readdir,
};
struct inode *simpfs_new_inode(struct super_block *sb,struct inode *dir,int idx,umode_t mode)
{
struct inode *inode;
inode = new_inode(sb);
if (!inode)
{
return NULL;
}
inode->i_ino = idx;
inode->i_sb = sb;
inode->i_op = &simpfs_inode_ops;
if (S_ISDIR(mode))
{
inode->i_fop = &simpfs_dir_operations;
}
else if (S_ISREG(mode))
{
inode->i_fop =&simpfs_file_operations;
}
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
return inode;
}
static int simpfs_do_create(struct inode *dir, struct dentry *dentry, umode_t mode)
{
struct inode *inode;
struct super_block *sb;
struct dir_entry *entry;
struct file_blk *blk, *pblk;
int idx;
sb =dir->i_sb;
if (curr_count >= MAX_FILES) {
return -ENOSPC;
}
if (!S_ISDIR(mode)&& !S_ISREG(mode))
{
return -EINVAL;
}
idx = get_block();
inode = simpfs_new_inode(sb,dir,idx,mode);
if (!inode)
{
return -ENOMEM;
}
// 获取一个空闲的文件块保存新文件
blk = &block[idx];
blk->mode = mode;
curr_count ++;
if (S_ISDIR(mode))
{
blk->dir_children = 0;
}
else if (S_ISREG(mode))
{
blk->file_size = 0;
}
inode->i_private = blk;
pblk = (struct file_blk *)dir->i_private;
entry = (struct dir_entry *)&pblk->data[0];
entry += pblk->dir_children;
pblk->dir_children ++;
entry->idx = idx;
strcpy(entry->filename, dentry->d_name.name);
// VFS穿针引线的关键步骤,将VFS的inode链接到链表
inode_init_owner(inode, dir, mode);
d_add(dentry,inode);
return 0;
}
static int simpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
{
PRINT_LOG(" mode:0x%x\r\n",mode);
return simpfs_do_create(dir, dentry, S_IFDIR | mode);
}
static int simpfs_create(struct inode *dir, struct dentry*dentry, umode_t mode, bool excl)
{
PRINT_LOG(" mode:0x%x\r\n",mode);
return simpfs_do_create(dir, dentry, mode);
}
static struct inode *simpfs_iget(struct super_block *sb, int idx)
{
struct inode *inode;
struct file_blk *blk;
inode = new_inode(sb);
inode->i_ino = idx;
inode->i_sb = sb;
inode->i_op = &simpfs_inode_ops;
blk = &block[idx];
if (S_ISDIR(blk->mode))
inode->i_fop = &simpfs_dir_operations;
else if (S_ISREG(blk->mode))
inode->i_fop = &simpfs_file_operations;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_private = blk;
return inode;
}
struct dentry *simpfs_lookup(struct inode *parent_inode, struct dentry *child_dentry, unsigned int flags)
{
struct super_block *sb = parent_inode->i_sb;
struct file_blk *blk;
struct dir_entry *entry;
int i;
PRINT_LOG(" flags:0x%x\r\n",flags);
blk = (struct file_blk *)parent_inode->i_private;
entry = (struct dir_entry *)&blk->data[0];
for (i = 0; i < blk->dir_children; i++)
{
if (!strcmp(entry[i].filename, child_dentry->d_name.name))
{
struct inode *inode = simpfs_iget(sb, entry[i].idx);
struct file_blk *inner = (struct file_blk *)inode->i_private;
inode_init_owner(inode, parent_inode, inner->mode);
d_add(child_dentry, inode);
return NULL;
}
}
return NULL;
}
int simpfs_rmdir(struct inode *dir, struct dentry *dentry)
{
int i;
struct inode *inode = dentry->d_inode;
struct file_blk *blk = (struct file_blk *)inode->i_private;
struct file_blk *pblk = (struct file_blk *)dir->i_private;
struct dir_entry *entry;
PRINT_LOG(" name:%s\r\n",dentry->d_name.name);
// 更新父目录
entry =(struct dir_entry *)&pblk->data[0];
for(i = 0; i < pblk->dir_children; i++)
{ if (!strcmp(entry[i].filename, dentry->d_name.name)){
int j;
for (j = i; j < pblk->dir_children - 1; j++)
{
memcpy(&entry[j], &entry[j+1], sizeof(struct dir_entry));
}
pblk->dir_children --;
break;
}
}
blk->used = 0;
//return simple_rmdir(dir, dentry);
return simple_unlink(dir, dentry);
}
int simpfs_unlink(struct inode *dir, struct dentry *dentry)
{
int i;
struct inode *inode = dentry->d_inode;
struct file_blk *blk = (struct file_blk *)inode->i_private;
struct file_blk *pblk = (struct file_blk *)dir->i_private;
struct dir_entry *entry;
PRINT_LOG(" name:%s\r\n",dentry->d_name.name);
// 更新父目录
entry =(struct dir_entry *)&pblk->data[0];
for(i = 0; i < pblk->dir_children; i++)
{ if (!strcmp(entry[i].filename, dentry->d_name.name)){
int j;
for (j = i; j < pblk->dir_children - 1; j++)
{
memcpy(&entry[j], &entry[j+1], sizeof(struct dir_entry));
}
pblk->dir_children --;
break;
}
}
blk->used = 0;
return simple_unlink(dir, dentry);
}
static struct inode_operations simpfs_inode_ops = {
.create = simpfs_create,
.lookup = simpfs_lookup,
.mkdir = simpfs_mkdir,
.rmdir = simpfs_rmdir,
.unlink = simpfs_unlink,
};
int simpfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *root_inode;
umode_t mode = S_IFDIR;
root_inode=simpfs_new_inode(sb,NULL,1,mode);
if (!root_inode)
{
return -ENOMEM;
}
inode_init_owner(root_inode, NULL, mode);
block[1].mode = mode;
block[1].dir_children = 0;
block[1].idx = 1;
block[1].used = 1;
root_inode->i_private = &block[1];
sb->s_blocksize = 4096;//PAGE_CACHE_SIZE;
sb->s_blocksize_bits = 12;//PAGE_CACHE_SHIFT;
sb->s_magic = SIMPFS_MAGIC;
sb->s_root = d_make_root(root_inode);
curr_count ++;
return 0;
}
static struct dentry *simpfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data)
{
return mount_nodev(fs_type, flags, data, simpfs_fill_super);
}
static void simpfs_kill_superblock(struct super_block *sb)
{
kill_anon_super(sb);
}
struct file_system_type simpfs_fs_type = {
.owner = THIS_MODULE,
.name = "simpfs",
.mount = simpfs_mount,
.kill_sb = simpfs_kill_superblock,
};
static int simpfs_init(void)
{
int ret;
memset(block, 0, sizeof(block));
ret = register_filesystem(&simpfs_fs_type);
if (ret)
printk("register simpfs failed\n");
return ret;
}
static void simpfs_exit(void)
{
unregister_filesystem(&simpfs_fs_type);
}
module_init(simpfs_init);
module_exit(simpfs_exit);
MODULE_LICENSE("GPL");