【文件系統】實現一個小的文件系統


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM