_bmap()
1、_bmap()函数用于把一个文件数据块映射到盘块的处理操作
由于一个i节点对应一个文件,所以前面的i节点映射的逻辑块号就是文件数据储存的逻辑块号;i_zone[0]到i_zone[6]是直接逻辑块号,i_zone[7]是一次间接逻辑块号,i_zone[8]是二次间接逻辑块号;文件中的数据储存在那个硬碟上的逻辑块上就是由这个链表来映射的,按照这个也可以晓得一个文件的最大储存是多少?
//把文件上的数据块映射到磁盘上,inode 文件i节点;block 文件中数据块号,create是否创建标志
static int _bmap(struct m_inode * inode,int block,int create)
{
struct buffer_head * bh;
int i;
//判断文件数据块号block是否超出范围
if (block<0)
panic("_bmap: block= 7+512+512*512)//文件逻辑块的范围
panic("_bmap: block>big");
//使用直接块
if (blocki_zone[block])//创建标志置位,i节点对应的逻辑块字段为0
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 (blocki_zone[7])//表明文件是首次使用间接块,则申请一个磁盘块来存放间接块信息
if (inode->i_zone[7]=new_block(inode->i_dev)) {
inode->i_dirt=1;
inode->i_ctime=CURRENT_TIME;
}
if (!inode->i_zone[7])//表示创建间接块磁盘失败,或者create未置1
return 0;
if (!(bh = bread(inode->i_dev,inode->i_zone[7])))//读取间接块的信息
return 0;
i = ((unsigned short *) (bh->b_data))[block];//得到间接块上block所处的位置,判断是否为0
if (create && !i)//如果间接块号上的block位置为0,create置位
if (i=new_block(inode->i_dev)) {//申请一个新的逻辑块给block
((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;
//获取block二级间接块号在指定的哪个二级间接块的一级块号
i = ((unsigned short *)bh->b_data)[block>>9];//右移9位表示整除512,得到一级块号
if (create && !i)//如果二级间接块中二级块不存在,则要为该二级块申请一个逻辑块号
if (i=new_block(inode->i_dev)) {//得到一个逻辑块用来存放二级间接块中的二级间接块号
((unsigned short *) (bh->b_data))[block>>9]=i;//block>>9 === block/512 为二级块映射一个逻辑块
bh->b_dirt=1;
}
brelse(bh);
if (!i)
return 0;
if (!(bh=bread(inode->i_dev,i)))//读取二级间接块中的二级块映射的缓存块
return 0;
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;//返回逻辑块号
}
input()
2、iput()函数是把i节点的引用递减,假如i节点引用为1,则递减删掉i节点红旗linux6.0,但是设置相关属性;假如是管线文件或则块设备文件linux文件的inode,则另外进行处理;
//放置一个i节点,减去1个i节点的引用
void iput(struct m_inode * inode)
{
if (!inode)
return;
wait_on_inode(inode);
if (!inode->i_count)//如果i节点已经是0,那么死机
panic("iput: trying to free free inode");
if (inode->i_pipe) {//如果是管道文件
wake_up(&inode->i_wait);//唤醒等待该管道的进程
if (--inode->i_count)//引用减去1
return;//如果还被其他程序引用,则直接返回;否则就设置一些属性和释放内存
free_page(inode->i_size);//释放管道使用的内存页面
inode->i_count=0;//对i节点属性字段设置
inode->i_dirt=0;
inode->i_pipe=0;
return;
}
//i节点对应的设备号为0,引用递减后返回;如,管道操作i节点
if (!inode->i_dev) {
inode->i_count--;
return;
}
//如果是块设备文件的i节点,刷新该设备
if (S_ISBLK(inode->i_mode)) {
sync_dev(inode->i_zone[0]);//zone[0]是设备号
wait_on_inode(inode);
}
repeat:
if (inode->i_count>1) {//引用递减 返回
inode->i_count--;
return;
}
if (!inode->i_nlinks) {//链接数为0, 表示文件已经删除,置文件长度为0,释放i节点
truncate(inode);
free_inode(inode);
return;
}
if (inode->i_dirt) {//已经更改过
write_inode(inode); /* we can sleep - so do again *///把i节点信息写入缓存中
wait_on_inode(inode);
goto repeat;//经过睡眠,要再一次确认
}
inode->i_count--;//递减返回,文件还存在
return;
}
get_empty_inode()3、get_empty_inode(void)函数表示在i节点链表中查找一个空闲的i节点,进行设置,之后返回该i节点;
//从i节点表中获取一个空闲i节点项
struct m_inode * get_empty_inode(void)
{
struct m_inode * inode;
static struct m_inode * last_inode = inode_table;
int i;
do {
inode = NULL;
for (i = NR_INODE; i ; i--) {
if (++last_inode >= inode_table + NR_INODE)//如果last_inode已经到了最后一项,则重新扫描
last_inode = inode_table;
if (!last_inode->i_count) {//引用为0,
inode = last_inode;
if (!inode->i_dirt && !inode->i_lock)//没有修改,没有上锁,就选择这个i节点
break;
}
}
//没有找到i节点,打印i节点列表,供调试,死机
if (!inode) {
for (i=0 ; ii_dirt) {
write_inode(inode);
wait_on_inode(inode);
}
} while (inode->i_count);//如果i节点又被别的进程使用,那么再找一个i节点
//对空闲i节点详内容清零,设置引用,返回i节点指针
memset(inode,0,sizeof(*inode));
inode->i_count = 1;
return inode;
}
iget()
4、iget(intdev,intnr)函数依据设备号和i节点号得到i节点信息;其中有个重点判定的是该i节点是否是某个文件系统的安装节点。假如是,则把i节点释放一个引用;而且重新在该文件系统中查找i节点(也就是根节点)
//从设备上读取指定i节点号的i节点信息
//参数 dev设备号,nr i节点号
//1、在内存中的i节点列表中扫描,若查找到了,则返回i节点指针
//2、如果上面没有找到,则从设备上读取指定i节点号的i节点信息放入内存i节点表中,返回i节点指针
struct m_inode * iget(int dev,int nr)
{
struct m_inode * inode, * empty;
if (!dev)
panic("iget with dev==0");
empty = get_empty_inode();//得到一个空闲i节点
inode = inode_table;//i节点列表数组
while (inode i_dev != dev || inode->i_num != nr) {//设备号或者i节点号不相等,则看下一个
inode++;
continue;
}
//解锁,然后再确认下设备号和i节点号是否改变了
wait_on_inode(inode);
if (inode->i_dev != dev || inode->i_num != nr) {
inode = inode_table;
continue;
}
inode->i_count++;//引用
//如果找到的i节点是其他文件系统的安装节点
if (inode->i_mount) {
int i;
for (i = 0 ; i= NR_SUPER) {
printk("Mounted inode hasn't got sbn");
if (empty)
iput(empty);//释放空闲i节点
return inode;
}
//找到i节点安装的超级块,获取到该文件系统的设备号,得到nr为根节点1,重新在该文件系统中查找根i节点
iput(inode);
dev = super_block[i].s_dev;
nr = ROOT_INO;
inode = inode_table;
continue;
}
//如果找到的i节点不是,其他文件系统的安装节点,
//则释放空节点,返回i节点
if (empty)
iput(empty);
return inode;
}
//如果在i节点列表中,没有找到指定i节点,则自己新建一个
if (!empty)
return (NULL);
inode=empty;
inode->i_dev = dev;
inode->i_num = nr;
read_inode(inode);//从设备上读取该i节点
return inode;
}
read_inode()
5、读取设备上指定i节点的信息到缓存中,其中要分清楚,参数中的i节点是显存中使用的i节点,而程序旁边是读取到硬碟上的i节点;这应当是从硬碟上的i节点中加载其信息到显存中的i节点处,也就是更新i节点信息;所以用读i节点信息(把i节点信息从硬碟上读取到缓存区中,从硬碟使用的i节点更新到显存使用的i节点)
//从设备上读取指定i节点的信息到缓存中
static void read_inode(struct m_inode * inode)
{
struct super_block * sb;
struct buffer_head * bh;
int block;
lock_inode(inode);
if (!(sb=get_super(inode->i_dev)))//根据设备号获取到超级块
panic("trying to read inode without dev");
//下面是计算i节点逻辑号,引导块 超级块 两个位图 然后就是(i节点号/每块所拥有的i节点数)
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
(inode->i_num-1)/INODES_PER_BLOCK;
//从磁盘上获取到i节点信息
if (!(bh=bread(inode->i_dev,block)))
panic("unable to read i-node block");
*(struct d_inode *)inode =
((struct d_inode *)bh->b_data)
[(inode->i_num-1)%INODES_PER_BLOCK];//这是从硬盘中i节点上获取到数据,更新内存中i节点内容
brelse(bh);
unlock_inode(inode);
}
write_inode()6、将指定i节点信息写入c盘中,和前面的read_inode()函数恰好相反,该函数是由显存中使用的i节点写入到硬碟上使用的i节点;把显存中更改过的i节点信息更新到硬碟上使用的i节点信息;
//将i节点信息写入缓存区中
static void write_inode(struct m_inode * inode)//参数是内存中使用的i节点结构
{
struct super_block * sb;
struct buffer_head * bh;
int block;
lock_inode(inode);
if (!inode->i_dirt || !inode->i_dev) {
unlock_inode(inode);
return;
}
if (!(sb=get_super(inode->i_dev)))
panic("trying to write inode without device");
block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
(inode->i_num-1)/INODES_PER_BLOCK;//根据i节点号,找到磁盘逻辑块上i节点位置
if (!(bh=bread(inode->i_dev,block)))//把该i节点磁盘块读取到缓存区
panic("unable to read i-node block");
((struct d_inode *)bh->b_data)//把该缓存区强转为 磁盘使用的i节点结构
[(inode->i_num-1)%INODES_PER_BLOCK] =//根据i节点号,取余得到在该块磁盘上第几个位置为i节点
*(struct d_inode *)inode;//由内存i节点强转为磁盘i节点结构,因为磁盘i节点结构和内存i节点结构前几位一样
bh->b_dirt=1;
inode->i_dirt=0;
brelse(bh);
unlock_inode(inode);
}
虽然里面的读写i节点信息,只是在旁边的转换次序不一样。是在d_inode和m_inode结构体之间做文章的linux系统下载官网,由于两个结构体中前7项是一样的,也就是说上面7项是可以共用,可以改变的linux文件系统的inode,而m_inode结构体中前面几项d_inode结构体中是没有的(虽然这也是确定i节点的惟一性),所以也就不存在是否同步,是否一样。
读i节点次序是:*(structd_inode*)inode=((structd_inode*)bh->b_data)[(inode->i_num-1)%INODES_PER_BLOCK];从硬碟映射的缓存区中读取到i节点信息到显存i节点结构体中;
写i节点次序是:((structd_inode*)bh->b_data)[(inode->i_num-1)%INODES_PER_BLOCK]=*(structd_inode*)inode;把i节点结构体内容从显存中写入到硬碟映射的缓存区中使用的i节点结构体(虽然也就是硬碟上使用的i节点);
本文原创地址://lrxjmw.cn/ypsyijddljkh.html编辑:刘遄,审核员:暂无