您的位置:首页 > 运维架构 > Linux

0.11版linux文件系统(一)

2015-10-30 22:14 323 查看
文件系统和内存管理,以及进程管理是操作系统的核心部分。数据通常以文件的形式存储在设 备上,因此文件系统的基本功能就是以某种格式存取/控制文件。0.11版的内核中采用了minix1.0版的文件系统。在最新的2.6版内核中,借助于 VFS,系统支持50多种文件系统。

首先介绍一下minix文件系统

minix文件系统和标准unix文件系统基本相同。它由6个部分组 成,分别是:引导块,超级块,i节点位图,逻辑块位图,i节点,和数据区。如果存放文件系统的设备不是引导设备,那么引导块可以为空。PC机的块设备通常 以512字节为一个扇区,而文件系统则以盘块为单位使用之。minix中1个盘块等于2个扇区大小。从引导块为第0个盘块开始计算。逻辑块可以为2^n个
盘块,minix中逻辑块大小等于盘块。所以盘块=逻辑块=缓冲块=1024字节。超级块存放文件系统的整体信息。i节点位图描述了i节点的使用情况。文 件通常将控制信息和数据分开存放,i节点就是存放文件的控制信息的,通常称之为inode。逻辑块位图则描述了逻辑块的使用情况。

linux中的 文件范围很广泛,不仅仅指普通文件。用ls -l命令可以发现显示的信息的最左边字符可以为"-","d","s","p","b","c",分别表示正规文件,目录文件,符号连接,命名管道,块设 备,字符设备文件。紧跟在其后的9位字符可以为r,w,x,s,S等,描述了文件的访问权限。后面的信息有文件的用户名,组名,文件大小,修改日期等,这
些信息当然是放在inode中的。文件名除外。那么文件系统是如何被加载的呢?在系统启动过程中,具体是在任务1的init()函数中,通过setup系 统调用加载的,该函数调用mount_root()函数读取根文件系统的超级块和根inode节点。

下面,就结合文件系统的上述要素,及其数据结构讲解minix1.0文件系统。

1.超级块

struct super_block{

unsigned
short s_niodes; //节点数

unsigned
short s_nzones; //逻辑块数

unsigned
short s_imap_blocks; //i节点位图所占的数据块数

unsigned
short s_zmap_blocks; //逻辑块位图所占用的数据块数

unsigned
short s_firstdatazone; //第一个数据逻辑块号

unsigned
short s_log_zone_size; //log2(数据块数/逻辑块)

unsigned
short s_max_size; //文件的最大长度

unsigned
short s_magic ; //文件系统魔数

//以下的字段仅出现在内存中

struct
buffer_head* s_imap[8];//i节点位图在缓冲区中的指针

struct
buffer_head* s_zmap[8];//逻辑块位图在缓冲区中的指针

unsigned
short s_dev;//超级块所在的设备号

struct
m_inode *s_isup;//被安装的文件系统的根节点

struct
m_inode *s_imount; //被安装到的i节点

unsigned
long s_time; //修改时间

struct
task_struct *s_wait; //等待该超级块的进程

unsigned
char s_lock; //被锁定标志

unsigned
char s_rd_only; //只读标志

unsigned
char s_dirt; //已修改标志

};

每个文件系统都要有一个超级块。内核维护一个超级块数组:

struct super_block super_block[NR_SUPER];

当一个文件系统被加载时,就将它的超级块读到这个数组中,并读取它的i节点和逻辑块位图到super_block的相应数组中。卸载一个文件系统时就执行相反的操作。

super.c 文件中实现了对超级块的操作,包括get_super,put_super,read_super,另外还有sys_umount,sys_mount, mount_root函数。get_super是从超级块数组中搜索指定设备的超级块。所以它要求相应的文件系统已加载或者已读到数组中。 read_super则是从盘上读取超级块。put_super是释放超级块以及相应的位图,这在sys_umount函数中被调用。

我们来看一下read_super这个函数。

static struct super_block *read_super(int dev)

{

struct
super_block *s;

struct
buffer_head *bh;

int
i,block;

if(!dev)

return
NULL;

//检查设备是否更换,这里是检查软盘是否更换,如果更换那么就释放其超级块,并使其位图和缓冲区无效

check_disk_change(dev);

//如果该超级块已经在超级块数组中,那么就获取它并返回

if(s=get_super(dev))

return
s;

//否则就先在超级块数组中找到一个空项,准备读取后填充

for(s=0+super_block;;s++){

if(s>=NR_SUPER+super_block)

return
NULL;

if(!s->dev)

break;

}

//找到空项后初始化它

s->s_dev=dev;

s->s_isup=NULL;

s->s_imount=NULL;

s->s_time=0;

s->s_rd_only=0;

s->s_dirt=0;

//然后锁定该超级块,并从设备上读取超级块。超级块在第1块

lock_super(s);

if(!(bh=bread(dev,1))

s->s_dev=0;

free_super(s);

return
NULL;

}

//然后将读取到的超级块从缓冲块读到超级块数组中

*((struct
d_super_block*)s)=*((struct d_super_block*)bh->data);

brelse(bh);

//判断文件系统魔数是不是0x137f,minix的魔数

if(s->s_magic!=SUPER_MAGIC){

s->s_dev=0;

free_super(s);

return
NULL;

}

//然后就读取设备上的i节点和逻辑块位图到缓冲区中,先初始化指针数组。I_MAP_SLOTS和Z_MAP_SLOTS都等于8,所以共有1024*8*8个比特用于描述逻辑块。而每个逻辑块为1024字节,所以minix1.0最大支持64M的文件系统。

for(i=0;i<I_MAP_SLOTS;i++)

s->s_imap=NULL;

for(i=0;i<Z_MAP_SLOTS;i++)

s->s_zmap=NULL;

block=2;

for(i=0;i<s->s_imap_blocks;i++)

if(s->s_imap=bread(dev,block))

block++;

else

break;

for(i=0;i<s->s_zmap_blocks;i++)

if(s->s_zmap=bread(dev,block))

block++;

else

break;

//如果读出的块数不等于因该站有的块数,则说明文件系统位图有问题,则释放掉所有申请的资源后退出

if(block!=2+s->s_imap_blocks+s->s_zmap_blocks){

for(i=0;i<I_MAP_SLOTS;i++)

brelse(s->s_imap);

for(i=0;i<Z_MAP-SLOTS;i++)

brelse(s->s_zmap);

s->s_dev=0;

free_super(s);

return
NULL;

}

//对于申请空闲i节点的函数来讲,如果设备上所与的i节点都被使用,则返回为0。所以0号节点不能使用,逻辑块也是如此。

s->s_imap[0]->b_data[0]|=1;

s->s_zmap[0]->b_data[0]|=1;

//解锁超级块,返回超级块指针。

free_super(s);

return
s;

}

超级块就讲这么多,关于几个加载的函数在介绍了其他的部分后再介绍。在下一篇文章,我会介绍i节点,位图的操作,目录项概念,以及如何根据文件的路径名找出它的inode节点。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: