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

// 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);
}

你可能感兴趣的:(数据库,struct,存储,buffer)