Linux下最简文件系统(一)

这个博客介绍了如何实现一个最简单的内存文件系统,并修复了删除目录的bug。该文件系统使用固定大小的块来存储文件和目录信息,支持读写操作。博客详细展示了文件结构、读写函数以及目录遍历的实现,并提供了创建、删除和查找文件的函数。
摘要由CSDN通过智能技术生成

通过对内存区域的读写完成的一个最简文件系统。后续将陆续更新升级该文件系统
功能。

参考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");

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值