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

linux/fs/inode.c/_bmap() and bmap()

2012-05-31 17:13 239 查看
// bmap函数的实体。用来实现文件数据块号到设备中的逻辑块号的映射。

// inode是文件i节点指针,block是要操作的文件数据块号,creat为创建标志

// 有0和1两种情况。若create为0(不置位)则只是映射。换句话说,若block

// 对应的逻辑块不存在,还是返回inode->i_zone[block],此时应该是0.

// 若create为1(创建标志置位)则block对应的逻辑块好不存在时调用new_block

// 函数注册一个新逻辑快,并返回这个新逻辑快的块号。

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

{

struct buffer_head * bh;

int i;

// block是文件数据块号,因此其范围是(0,7+512+512*512),这是由Minix1.0

// 文件系统决定的

if (block<0)

panic("_bmap: block<0");

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

panic("_bmap: block>big");

// 下面分三部分来处理。要明晰这一块代码,首先要明白Minix1.0文件系统中

// 记录文件数据块号索引的方法。inode->i_zone[9]总计记录9个索引号,分

// 配方式如下:i_zone[0]~i_zone[7]直接存储文件数据块号,因此可以存储

// 7个数据块号。对于文件数据量小于7k的文件,前7个块号就能满足了;i_zone[8]

// 采用间接存储块号方式。即i_zone[8]中存储的块号对应的块内存储着512个

// 文件数据块号(1块为1k,而一个块号是short型,因此一块正好存储512个块号)

// 因此文件数据块的1+7~512+7是由i_zone[8]来间接获取的;i_zone[9]则是两级

// 间接存储方式。即i_zone[9]内块号对应的块内存储着512个块号。这512个块号

// 每一个对应的块内又存储着512个块号,因此一共有512*512个块号可以被索引

// 因此由i_zone[9]能间接索引到的块为512+7+1~512*512+512+7+1

// 实际映射时,根据block就能计算出当前需要的数据块在哪一部分并分头处理

// 若block<7,在直接映射区域。

if (block<7) {

// 若create置位,并且block对应的逻辑块号不存在(i_zone[block]取出的

// 块号),就调用new_block申请一个新逻辑块号

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

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

// 写上inode修改时间时间(ctime stands for change time)

inode->i_ctime=CURRENT_TIME;

// 脏标志置位,这样在sync时就会将这个块同步到设备上。

inode->i_dirt=1;

}

// 返回找到的block对应的逻辑块号

return inode->i_zone[block];

}

// 若block>7,则先将block减7,然后再看在后面两段哪一段内

block -= 7;

// 对应block落在i_zone[7]的情况,此时为一次间接存储

if (block<512) {

// 同上面,若create置位并且i_zone[7]为空,则创建新的block

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;

}

// 若此处i_zone[7]仍为0,则说明create没有置位,而且要找的block

// 真的不存在,此时直接返回0即可。

if (!inode->i_zone[7])

return 0;

// 运行到这里,说明inode->i_zone[7]不为空,可以进行间接读取了。

// 先读出i_zone[7]内存储的512个块号所在的块内容。

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

return 0;

// bh->b_data为读出来的i_zone[7]里面存储的块号对应的块内容,也就是那

// 512个块号了。用(unsigned short *)格式化之,下面欲访问某个块号,

// 就可以考虑用指针或者数组两种方式访问了。

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;

}

// 用完bh后即释放

brelse(bh);

return i;

}

// block属于二次间接访问的情况,先减去512(注意这个block在上面已经被

// 减去7一次了,所以累计减去了512+7,就是前两级的逻辑快总数)

block -= 512;

// 同上面,若create置位,并且i_zone[8]为空,则进入创建i_zone[8]的一次

// 间接索引块

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;

}

// 到此处若还为空,那说明create没置位并且i_zone[8]为空,直接返回0

if (!inode->i_zone[8])

return 0;

// 读出i_zone[8]中存储的逻辑块号对应的块内容,这一块的数据包含了用于

// 二次间接寻块的块号索引。

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

return 0;

// 请记住这里读出的一块内容(1024bytes)被解析成512个两字节的块号,而

// 每个块号指向的不再是我们要的最终的记录文件的逻辑块,而是记录逻辑快

// 的逻辑块。因此这里的每一项(2字节)将来都对应着512个逻辑块。

// block>>9相当于block除512,这算出了block在i_zone[8]的一级块内的序号,

// 因此i就是512个专存块号的块(称为二次间接块好了,一次间接块指的就是

// i_zone[8])中和block对应的那个块。

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

if (create && !i)

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

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

bh->b_dirt=1;

}

brelse(bh);

if (!i)

return 0;

// 经过上面的一番折腾,到这里找到了block的二次间接块了,把丫读出来

// 这里面存的就是block % 512 这512个文件数据库对应的逻辑块块号了。

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

return 0;

// 这次读的是真正的文件数据库的块号了,bh->b_data中共有512个块号。

// 为了保证访问不越界,block & 511处理了。读出的i就是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;

}

// 将文件中数据块号block映射到设备上的逻辑块号。这个函数用在bread函数之前,

// 因为bread读盘需要盘号(即逻辑块号),而文件inode只能得到文件中的数据块号

// 因此要用bread读盘,必须先用bmap把文件数据块号映射到设备上的逻辑块号

int bmap(struct m_inode * inode,int block)

{

return _bmap(inode,block,0);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: