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