博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
0.11版linux文件系统(二)
阅读量:3677 次
发布时间:2019-05-21

本文共 3823 字,大约阅读时间需要 12 分钟。

超级块描述了整个文件系统的信息,而文件作为存储的对象,它的信息是有inode节点来描述的。i节点位图描述了inode的使用情况。

struct m_inode{

 
  
  
  
 unsigned short i_mode; //文件类型

 
  
  
  
 unsigned short i_uid;//文件宿主

 
  
  
  
 unsigned long i_size;//文件大小

 
  
  
  
 unsigned long i_mtime;//文件修改时间

 
  
  
  
 unsigned char i_guid; //文件组id

 
  
  
  
 unsigned char i_nlinks; 
  
  
  
 //文件目录项连接数

 
  
  
  
 unsigned char i_zone[9];//文件所在的设备逻辑块号

//以下的字段在内存中

 
  
  
  
 struct task_struct *i_wait; //等待该i节点的进程

 
  
  
  
 unsigned long i_atime,i_ctime;

 
  
  
  
 unsigned short i_dev; //文件所在的设备号

 
  
  
  
 unsigned short i_num; //i节点号

 
  
  
  
 unsigned short i_count;//i节点被使用的次数,0表示空闲

 
  
  
  
 unsigned char i_lock;

 
  
  
  
 unsigned char i_dirt;

 
  
  
  
 unsigned char i_pipe;

 
  
  
  
 unsigned char i_mount; //该节点是否是某个文件系统的安装节点

 
  
  
  
 unsigned char i_seek;

 
  
  
  
 unsigned char i_update;

}

其 中i_zone[9]很重要,它指出了文件使用的设备的逻辑块号。其中0-6为直接块,也就是文件的数据直接在相应的逻辑块上;7位1级块,1级块可以包 含512个逻辑块号;8位2级块,它可以存放512个1级块。所以文件长度在7k以内只使用前7个位指定逻辑块,再大就要使用间接块指定了。

对i节点位图以及i节点的操作有new_inode,free_inode,iget,iput,bmp,以及namei.辅助的函数有get_empty_inode,read_inode,write_inode.内核维护了一个inode节点数组:

struct m_inode inode_table[NR_INODE]={
{0,},};

new_inode(int dev)从inode_table中获取一个空闲的inode节点项,然后相应设备超级块中的i节点位图中的第一个0bit,接着设置inode节点信 息,并置引用为1。free_inode则相反,进行一系列测试后,它清除位图的相应比特为,并清空inode节点占用的内存。

对 逻辑块位图的操作有new_block和free_block,前者获取一个空闲缓冲块并置位相应比特位,后者相反。以上都是对内存中的inode数组以 及缓冲区中的位图进行操作,而最终要落实到设备特定的块上。read_inode是从设备上读取指定i节点的信息到内存中,write_inode是写入 指定i节点到设备。后者是将inode写到相应缓冲块中,并置位

b_dirt。这里涉及到计算指定的inode节点在设备上的逻辑块号:

//启动块+超级块+i节点位图块数+逻辑块位图块数+(i节点号-1)/每块含有的i节点

block=1+1+sb->s_imap_blocks+sb->s_zmap_blocks+(inode->s_inum)/INODES_PER_BLOCK;

iget 函数是从设备上读取指定的i节点。如同getblk,考虑到同步问题也是个反复的过程。它首先从i节点表中申请一个空闲i节点。然后搜索i节点表,看是否 有指定的i节点,如果没有就用read_inode从设备中读取到空闲节点就可返回。如果有则等待它解锁。等待过程中如果节点表发生变化那么要重新搜索。 若该i节点是某个文件系统的安装点,则读取相应文件系统的超级块并设置节点号为该文件系统的第一个inode,然后重新开始。

iput是回写到设 备,这里根据文件的类型有几种不同的处理方法。如果文件是管道文件,则唤醒管道上等待的进程,并释放管道页面。管道的物理内存地址在inode-> i_size字段。如果文件是块设备,那么刷新设备。inode->i_zone[0]中存放的是设备号。如果链接数为0,则释放i节点所有的逻辑 块,并释放该节点。

还有一个比较重要的函数是 _bmp,它是将文件数据块映射到盘块。在前面讲过的do_no_page中用到过,计算出缺页的内存地址在程序所占的块号后,通过bmp映射到设备上的块号,并读取被交换到块设备上的页面。

下面具体讲解一下:

//inode:文件的节点,block:文件中的块号;create:创建标志。

static int _bmp(struct m_inode *inode,int block,int create)

{

 
  
  
  
 struct buffer_head *bh;

 
  
  
  
 int i;

 
  
  
  
 if(block<0)

 
  
  
  
  
  
  
  
 panic("_bmp:block<0");

//如果块号大于直接块数+间接块数+二次间接块数,则超出文件系统表示范围,死机

 
  
  
  
 if(block>=7+512+512*512)

 
  
  
  
  
  
  
  
 panic("_bmp:block>big");

//如果块号小于7,则使用直接块表示

 
  
  
  
 if(block<7){

 
  
  
  
  
  
  
  
 if(create&&!inode->i_zone[block])

 
  
  
  
  
  
  
  
  
  
  
  
 if(inode->i_zone[block]=new_block(inode->i_dev)){

 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 inode->i_ctime=CURRENT_TIME;

 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 inode->i_dirt=1;

 
  
  
  
  
  
  
  
  
  
  
  
 }

 
  
  
  
  
  
  
  
 return inode->i_zone[block];

 
  
  
  
 }

//否则就看是不是在间接块中

 
  
  
  
 block-=7;

 
  
  
  
 if(block<512){

//如果间接块没有创建且创建标志为1,那么创建间接块

 
  
  
  
  
  
  
  
 if(create&&!inode->i_zone[7])

 
  
  
  
  
  
  
  
  
  
  
  
 if(inode->i_zone[7]=new_block(inode->i_dev)){

 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 inode->i_dirt=1;

 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
 inode->i_ctime=CURRENT_TIME;

 
  
  
  
  
  
  
  
  
  
  
  
 }

 
  
  
  
  
  
  
  
 if(!inode->_zone[7])

 
  
  
  
  
  
  
  
  
  
  
  
 return 0;

//读取设备上的一次间接块

 
  
  
  
  
  
  
  
 if(!(bh=bread(inode->i_dev,inode->i_zone[7])))

 
  
  
  
  
  
  
  
  
  
  
  
 return 0;

//取间接块第block上的逻辑块号

 
  
  
  
  
  
  
  
 i=((unsigned short*)(bh->b_data))[block];

 
  
  
  
  
  
  
  
 if(create&&!i)

 
  
  
  
  
  
  
  
  
  
  
  
 if(i=new_block(inode->i_dev)){

 
  
  
  
  
  
  
  
  
  
  
  
 ((unsigned short*)(bh->b_data))[block]=i;

 
  
  
  
  
  
  
  
  
  
  
  
 bh->b_dirt=1;

 
  
  
  
  
  
  
  
  
  
  
  
 }

 
  
  
  
  
  
  
  
 brelse(bh);

 
  
  
  
  
  
  
  
 return i;

 
  
  
  
 }

//到此,表明数据块是在二次间接块上,如上所述处理之

 
  
  
  
 block-=512;

 
  
  
  
 if(create&&!inode->i_zone[8])

 
  
  
  
  
  
  
  
 if(inode->i_zone[8]=new_block[inode->i_dev]){

 
  
  
  
  
  
  
  
  
  
  
  
 inode->i_dirt=1;

 
  
  
  
  
  
  
  
  
  
  
  
 inode->i_ctime=CURRENT_TIME;

 
  
  
  
  
  
  
  
 }

 
  
  
  
 if(!inode->i_zone[8])

 
  
  
  
  
  
  
  
 return 0;

//读取该二次间接块的一级块

 
  
  
  
 if(!(bh=bread(inode->i_dev,inode->i_zone[8])))

 
  
  
  
  
  
  
  
 return 0;

 
  
  
  
 i=((unsigned short*)bh->b_data)[block>>9];

 
  
  
  
 if(create&&!i)

 
  
  
  
  
  
  
  
 if(i=new_block(inode->i_dev){

 
  
  
  
  
  
  
  
  
  
  
  
 bh->b_dirt=1;

 
  
  
  
  
  
  
  
 }

 
  
  
  
 brelse(bh);

 
  
  
  
 if(!i)

 
  
  
  
  
  
  
  
 return 0;

//读取二次间接块的二级块

 
  
  
  
 if(!(bh=bread(inode->i_dev,i))

 
  
  
  
  
  
  
  
 return 0;

//取二级块上的block项的逻辑号

 
  
  
  
 i=((unsigned short*)bh->b_data)[block&&511];

 
  
  
  
 if(create&&!i)

 
  
  
  
  
  
  
  
 if(i=new_block(inode->i_dev)){

 
  
  
  
  
  
  
  
  
  
  
  
 ((unsigned short*)(bh->b_data))[block&511]=i;

 
  
  
  
  
  
  
  
  
  
  
  
 bh->b_dirt=1;

 
  
  
  
  
  
  
  
 }

 
  
  
  
 brelse(bh);

 
  
  
  
 return i;

}

bmp是create=0的_bmp,仅取文件中的数据块号在缓冲区的对应块号,而create_block则是create=1的_bmp,它创建对应的设备逻辑块的缓冲块。


到 目前为止,应该对超级块,i节点,逻辑块,缓冲块有了一定的认识了。设备上的物理部分都有内存的表示,比如超级块在内存中有超级块数组 super_block[NR_SUPER],i节点和逻辑块位图有s_imap[8]和s_zmap[8]指向的缓冲区表示,i节点在内存中有i节点数 组inode_table[NR_INODE],逻辑块有缓冲区中的缓冲块。分配inode和逻辑块只需要分配内存中保留的空闲块,并设置对应位图和修改 位,内核会在适当时间刷新到设备上。

转载地址:http://tyxbn.baihongyu.com/

你可能感兴趣的文章
kafka之broker 保存消息
查看>>
kafka生产,保存,消费消息过程要点个人总结
查看>>
kafka消费者低级API
查看>>
消息队里内部原理简单分析
查看>>
KAFKA OFFSET的存储问题
查看>>
kafka集群依赖zookeeper
查看>>
HBase之优化
查看>>
Kafka Stream 数据清洗
查看>>
kafka 和 Flume 集成简单案例
查看>>
HBase Shell操作(DDL+DML)
查看>>
HBase删除数据
查看>>
Hbase 和 MapReduce 结合
查看>>
认识时间复杂度以及冒泡选择插入排序------排序1
查看>>
摒除一切封建迷信之递归并不难------排序2
查看>>
逆序思路
查看>>
荷兰国旗问题------排序3
查看>>
荷兰国旗问题来改进快速排序------排序4
查看>>
HashMap的实现原理,以及在JDK1.7和1.8的区别
查看>>
Hashmap的结构,1.7和1.8有哪些区别
查看>>
HashMap为何从头插入改为尾插入
查看>>