Skip to main content
 首页 » 操作系统

Linux文件系统实现一个小的文件系统

2022年07月19日172freeliver54

1. 实现文件系统要记住两个重要链表

a.文件系统链表。
b.每一个文件系统的mount挂载点链表。

2. 注意vfs提供的三类接口

a.和POSIX系统调用有关的接口 即实现open/read/write的操作的接口。
b.和底层介质有关的接口 即下接块设备层的接口。
c.如何管理自身的接口,即何时以及如何操作vfs数据结构,inode,dentry,mount等对象。
一个文件系统如果能实现上面三类接口,那它就是个完整的文件系统了。

3. Linux内核自带的ramfs就是一个现成的小的文件系统,但它有两个问题导致无法领略实现一个文件系统的全过程

a.ramfs无法让你自己设计底层模拟介质的格式,不完整。
b.ramfs调用了大量的fs/libfs.c中的内核库例程,不纯碎。


4. 下面是实现一个实现简单文件系统的案例

a.最多容纳512个文件(包括目录在内)。
b.每个文件包括元数据在内最多32个字节。
c.文件名最多8个字节。

5. 实现代码如下:

// tinyfs.c 
#include <linux/init.h> 
#include <linux/module.h> 
#include <linux/fs.h> 
#include <linux/uaccess.h> 
 
#define MAXLEN 8 
#define MAX_FILES 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 { 
        uint8_t file_size; 
        uint8_t dir_children; 
    }; 
    char data[0]; 
}; 
 
//下面的block数组所占据的连续内存就是我的tinyfs的介质,每一个元素代表一个文件。 
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].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 -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; 
} 
 
//read实现 
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; 
} 
 
//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; 
} 
 
//文件的读写 
const struct file_operations tinyfs_file_operations = { 
    .read = tinyfs_read, 
    .write = tinyfs_write, 
}; 
 
//目录的操作 
const struct file_operations tinyfs_dir_operations = { 
    .owner = THIS_MODULE, 
    .readdir = tinyfs_readdir, 
}; 
 
//创建文件的实现 
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); 
 
    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); 
} 
 
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) 
{ 
    int i; 
    struct super_block *sb = parent_inode->i_sb; 
    struct file_blk *blk; 
    struct dir_entry *entry; 
 
    blk = (struct file_blk *)parent_inode->i_private; //block[1] 
    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 file_blk *blk = (struct file_blk *)dentry->d_inode->i_private; 
    blk->busy = 0; 
    return simple_rmdir(dir, dentry); 
} 
 
int tinyfs_unlink(struct inode *dir, struct dentry *dentry) 
{ 
    int i, j; 
    struct dir_entry *entry; 
 
    struct inode *inode = dentry->d_inode; 
    struct file_blk *blk = (struct file_blk *)inode->i_private; //存的是&block[1],superblock. 
    struct file_blk *pblk = (struct file_blk *)dir->i_private; 
 
    //更新其上层目录 
    entry = (struct dir_entry *)&pblk->data[0]; 
    for (i = 0; i < pblk->dir_children; i++) { 
        if (!strcmp(entry[i].filename, dentry->d_name.name)) { 
            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 = tinyfs_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]; //这里初始化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 tinyfs_init(void) 
{ 
    int ret; 
 
    memset(block, 0, sizeof(block)); 
    ret = register_filesystem(&tinyfs_fs_type); //注册一个文件系统 
    if (ret) 
        printk("register tinyfs failed\n"); 
 
    return ret; 
} 
 
static void tinyfs_exit(void) 
{ 
    unregister_filesystem(&tinyfs_fs_type); 
} 
 
module_init(tinyfs_init); 
module_exit(tinyfs_exit); 
MODULE_LICENSE("GPL");

参考:https://mp.weixin.qq.com/s/Sidfn8CZn4KxKh6xMH2uJQ


本文参考链接:https://www.cnblogs.com/hellokitty2/p/13020465.html