自己编写UNIX文件系统

近日有人求助,要写一个UNIX文件系统作为暑假作业。这种事情基本是学操作系统的必须要做的或者是做过的,毕竟文件系统是操作系统课程的一个重要组成部分。要实现这个UNIX文件系统,很多人就扎进了UNIX V6的的系统源码,以及《莱昂氏UNIX源代码分析》和《返璞归真:UNIX技术内幕》这两本书,很多人出来了,很多人在里面迷失了...最终忘了自己只是要实现一个UNIX文件系统而已。

为何会迷失,因为代码不是自己写的,而且年代久远,编程理念不同了,作者为何那样写不一定就能理解,实际上对于任何别人写的代码,总是会有一些不易理解的地方,当然,如果作者水平超级高,那么代码也就相对容易理解。因此,写代码永远比读代码要容易!既然是要写一个文件系统,为何要用现成的UNIX V6代码呢?如果理解了UNIX文件的布局和结构,自己从零开始不参考任何现有的代码做一个也不是什么难事,最根本的是UNIX文件系统本身,至于说代码,仅仅是一个实现与用户操作的一个接口而已。如果代码是自己一点一点写的,那么你肯定能彻底明白每一行的每一个语句的精确含义,至于为何这么写,你当然及其明了!

本文留下我仓促间几个小时写的一个类UNIX文件系统的代码,不是让别人看的,是为了自己留档,因为本文已经说了,看别人的代吗只能学习经验,不能理解本质,更何况,你看的还得是超级一流的代码,而我写的,则是超级垃圾的代码。我只想说,理解问题的本质要比代码重要得多,代码,码,并不是很多人想象中的那般重要!本文的实现基于Linux系统,即在Linux系统上编写一个用户态程序,实现UNIX文件的IO接口以及操作。

推荐阅读:

UNIX/Linux 系统管理技术手册(第四版)高清中文PDF 下载:

UNIX/Linux 系统管理技术手册(第四版)高清英文PDF 下载见

我一向坚持的原则,那就是任何东西的根本性的,本质上的原理以及背后的思想都是及其简单的,所谓的复杂性都是优化与策略化的扩展带来的,正如TCP一样,UNIX的文件系统也不例外!我们必须知道,什么是最根本的,什么是次要的。对于UNIX文件系统,最根本的就是其布局以及其系统调用接口,一个处在最低层,一个在最上层开放给用户,如下所示:

系统调用接口:open,write,read,close...

文件系统布局:引导快,超级块,inode区表,数据块区

所有的在二者中间的部分都是次要的,也就是说那些东西不要也行,比如高速缓冲,高速缓存,VFS层,块层...因此在我的实现代码中,并没有这些东西,我所做到的,仅仅是UNIX文件系统所要求必须做到的最小集,那就是:

面对一个按照UNIX文件系统标准布局的“块设备”,可以使用open,read,write等接口进行IO操作。

在实现中,我用一个标准的Linux大文件来模拟磁盘块,这样块的操作基本都映射到了Linux标准的write,read等系统调用了。

首先定义必要的结构体:

//超级块结构
struct filesys {
        unsigned int s_size;        //总大小                                         
        unsigned int s_itsize;        //inode表大小                                       
        unsigned int s_freeinodesize;    //空闲i节点的数量                         
        unsigned int s_nextfreeinode;    //下一个空闲i节点
        unsigned int s_freeinode[NUM];    //空闲i节点数组
        unsigned int s_freeblocksize;    //空闲块的数量         
        unsigned int s_nextfreeblock;    //下一个空闲块
        unsigned int s_freeblock[NUM];    //空闲块数组
        unsigned int s_pad[];        //填充到512字节 
};
//磁盘inode结构
struct finode {
        int fi_mode;            //类型:文件/目录
        int fi_uid_unused;        //uid,由于和进程无关联,仅仅是模拟一个FS,未使用,下同
        int fi_gid_unused;
        int fi_nlink;            //链接数,当链接数为0,意味着被删除
        long int fi_size;        //文件大小
        long int fi_addr[BNUM];        //文件块一级指针,并未实现多级指针
        time_t  fi_atime_unused;    //未实现
        time_t  fi_mtime_unused;
};
//内存inode结构
struct inode {
        struct finode  i_finode;
        struct inode    *i_parent;    //所属的目录i节点
        int    i_ino;            //i节点号
        int    i_users;        //引用计数
};
//目录项结构(非Linux内核的目录项)
struct direct
{
        char d_name[MAXLEN];        //文件或者目录的名字
        unsigned short d_ino;        //文件或者目录的i节点号
};
//目录结构
struct dir
{
        struct direct direct[DIRNUM];    //包含的目录项数组
        unsigned short size;        //包含的目录项大小   
};
//抽象的文件结构
struct file {
        struct inode *f_inode;        //文件的i节点
        int f_curpos;            //文件的当前读写指针
};

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/19329.html