用户程序读取文件内容流程
图1显示了用户程序读取文件内容的过程,其中绿色框部分为一个文件系统最基本的东西,其余部分为一些为了提高性能而加的模块。

图1
建立一个小型文件系统
小型文件系统基本就是实现了图1的绿色部分;具体的代码如下:
//tinyfs.h
#ifndef TINYFS_H
#define TINYFS_H
#define MAXLEN 8 //文件名最多8个字节
#define MAX_FILES 32 //定义文件最大32个字节
#define MAX_BLOCKSIZE 512 //文件及目录文件一共的个数
//定义一个目录项格式
struct dir_entry{
char filename[MAXLEN];
uint8_t idx;
};
//文件块数据结构
struct file_blk{
uint8_t busy; //
mode_t mode;
uint8_t idx; /
union
{
/* data */
uint8_t file_size; //文件大小
uint8_t dir_children; //文件夹中文件个数
};
char data[0]; //保存数据所在位置的指针
};
//下面的block数组所占据的连续内存就是我的tinyfs.h的介质,每一个元素代表一个文件
//struct file_blk bolck[MAX_FILES+1];
#endif
//tinyfs.c
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <asm/current.h>
#include <linux/sched.h>
#include <linux/dcache.h>
#include "tinyfs.h"
#include <linux/uaccess.h>
#include <linux/time.h>
#define CURRENT_TIME (current_kernel_time())
struct file_blk block[MAX_BLOCKSIZE + 1]; //在内存开辟一块空间作为模拟磁盘
int curr_count = 0; //当前文件或目录文件的个数
static int get_block(void){
int i;
//就是一个遍历,但实现快速
for(i =2;i<MAX_BLOCKSIZE;i++){
if(!block[i].busy){
block[i].busy = 1;
return i;
}
}
return -1;
}
static struct inode_operations tinyfs_inode_ops;
//读取目录的实现
/*static int tinyfs_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;
}
blk = (struct file_blk*)filp->f_dentry->d_inode->i_private;
if(!S_ISDIR(blk->mode)){
return -ENOMEM;
}
//循环获取一个目录的所有文件的文件名
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 tinyfs_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;
}
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;
}
static int tinyfs_iterate(struct file *flip,struct dir_context *ctx){
return 0;
}
// write实现
ssize_t tinyfs_write(struct file* filp,const char __user *buf,size_t len,loff_t *ppos){
struct file_blk *blk;
char *buffer;
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;
}
static struct file_operations tinyfs_file_operations = {
.read = tinyfs_read,
.write = tinyfs_write,
};
static struct file_operations tinyfs_dir_operations = {
.owner = THIS_MODULE,
//.readdir = tinyfs_readdir,
.iterate = tinyfs_iterate,
};
// 创建文件实现
static int tinyfs_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;
}
inode = new_inode(sb);
if(!inode){
return -ENOMEM;
}
inode->i_sb = sb;
inode->i_op = &tinyfs_inode_ops;
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
idx = get_block(); //获取一个空闲的文件块保存新文件
blk = &block[idx];
inode->i_ino = idx;
blk->mode = mode;
curr_count++;
if(S_ISDIR(mode)){
blk->dir_children = 0;
inode->i_fop = &tinyfs_dir_operations;
}else if(S_ISREG(mode)){
blk->file_size = 0;
inode->i_fop = &tinyfs_file_operations;
}
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); //将inode与dentry(包含文件名)绑定在一起
return 0;
}
//创建目录文件
static int tinyfs_mkdir(struct inode *dir,struct dentry *dentry,umode_t mode){
return tinyfs_do_create(dir,dentry,S_IFDIR | mode);
}
static int tinyfs_create(struct inode *dir,struct dentry *dentry,umode_t mode,bool excl){
return tinyfs_do_create(dir,dentry,mode);
}
//分配一个inode
static struct inode *tinyfs_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 = &tinyfs_inode_ops;
blk = &block[idx];
if(S_ISDIR(blk->mode)){
inode->i_fop = &tinyfs_dir_operations;
}else if(S_ISREG(blk->mode)){
inode->i_fop = &tinyfs_file_operations;
}
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
inode->i_private = blk;
return inode;
}
struct dentry *tinyfs_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;
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 = tinyfs_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 tinyfs_rmdir(struct inode *dir,struct dentry *dentry){
struct inode *inode = dentry->d_inode;
struct file_blk *blk = (struct file_blk *)inode->i_private;
blk->busy = 0;
return simple_rmdir(dir,dentry);
}
int tinyfd_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;
//更新其上层目录
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->busy = 0;
return simple_unlink(dir,dentry);
}
static struct inode_operations tinyfs_inode_ops = {
.create = tinyfs_create,
.lookup = tinyfs_lookup,
.mkdir = tinyfs_mkdir,
.rmdir = tinyfs_rmdir,
.unlink = tinyfd_unlink,
};
int tinyfs_fill_super(struct super_block *sb,void *data,int silent){
struct inode *root_inode;
int mode = S_IFDIR;
root_inode = new_inode(sb);
root_inode->i_ino = 1;
inode_init_owner(root_inode,NULL,mode);
root_inode->i_sb = sb;
root_inode->i_op = &tinyfs_inode_ops;
root_inode->i_fop = &tinyfs_dir_operations;
root_inode->i_atime = root_inode->i_mtime = root_inode->i_ctime = CURRENT_TIME;
block[1].mode = mode;
block[1].dir_children = 0;
block[1].idx = 1;
block[1].busy = 1;
root_inode->i_private = &block[1];
sb->s_root = d_make_root(root_inode);
curr_count++;
return 0;
}
static struct dentry *tinyfs_mount(struct file_system_type *fs_type,int flags,const char *dev_name,void *data){
return mount_nodev(fs_type,flags,data,tinyfs_fill_super);
}
static void tinyfs_kill_superblock(struct super_block *sb){
kill_anon_super(sb);
}
struct file_system_type tinyfs_fs_type = {
.owner = THIS_MODULE,
.name = "tinyfs",
.mount = tinyfs_mount,
.kill_sb = tinyfs_kill_superblock,
};
static int __init tinyfs_init(void){
int ret;
memset(block,0,sizeof(block));
printk("jisenquan,it's ok!");
ret = register_filesystem(&tinyfs_fs_type); //注册文件系统
return ret;
}
static void __exit tinyfs_exit(void){
printk("jisenquan,it's Over!");
unregister_filesystem(&tinyfs_fs_type); //
}
module_init(tinyfs_init);
module_exit(tinyfs_exit);
MODULE_LICENSE("GPL");注:
1. 该程序的实验环境所使用的内核版本是4.15.0
2.读取文件夹的函数没有进行实现。早期版本内核的file_operations读取目录的函数是readdir,我使用的内核版本已经将该函数删掉了,取而代之的是iterate函数
MAKEFILE文件
obj-m:=tinyfs.o
CURRENT_PATH:=$(shell pwd)
LINUX_KERNEL:=$(shell uname -r)
LINUX_KERNEL_PATH:=/usr/src/linux-headers-$(LINUX_KERNEL)
CONFIG_MODULE_SIG=n
all:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
clean:
make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) clean注:
1. MAKEFILE中必须加CONFIG_MODULE_SIG=n这句话,要不然编译会报没有签名的错
测试过程
sudo insmod tinyfs.ko #安装模块
sudo mount -t tinyfs none /mnt #挂载文件系统
sudo chmod 777 /mnt #修改文件夹权限
cd /mnt
echo 1111 > ./a #创建a文件,并将1111保存其中
mkdir first #创建文件夹
echo 2222 > ./first/b
版权声明:本文为qq_35536179原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。