Linux内核源码分析--文件系统(五、Inode.c)
来源:互联网 发布:网络热销产品 编辑:程序博客网 时间:2024/06/05 17:20
_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<0");if (block >= 7+512+512*512)//文件逻辑块的范围panic("_bmap: block>big");//使用直接块if (block<7) {if (create && !inode->i_zone[block])//创建标志置位,i节点对应的逻辑块字段为0if (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) {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->i_zone[7])//表示创建间接块磁盘失败,或者create未置1return 0;if (!(bh = bread(inode->i_dev,inode->i_zone[7])))//读取间接块的信息return 0;i = ((unsigned short *) (bh->b_data))[block];//得到间接块上block所处的位置,判断是否为0if (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节点,并且设置相关属性;如果是管道文件或者块设备文件,则另外进行处理;
//放置一个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)//引用减去1return;//如果还被其他程序引用,则直接返回;否则就设置一些属性和释放内存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 ; i<NR_INODE ; i++)printk("%04x: %6d\t",inode_table[i].i_dev,inode_table[i].i_num);panic("No free inodes in mem");}//检查下是否又被上锁wait_on_inode(inode);//若i节点信息修改过,则刷新等待i节点解锁while (inode->i_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(int dev, int nr)函数 根据设备号和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 < NR_INODE+inode_table) {if (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 ; i++)if (super_block[i].s_imount==inode)//看看是哪个文件系统的安装节点break;//如果没有找到安装在此i节点上的超级块,则释放申请的空闲i节点if (i >= NR_SUPER) {printk("Mounted inode hasn't got sb\n");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节点信息写入磁盘中,和上面的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结构体之间做文章的,因为两个结构体中前7项是一样的,也就是说前面7项是可以共用,可以改变的,而m_inode结构体中后面几项d_inode结构体中是没有的(其实这也是确定i节点的唯一性),所以也就不存在是否同步,是否一样。
读i节点顺序是:*(struct d_inode *)inode = ((struct d_inode *)bh->b_data)[(inode->i_num-1)%INODES_PER_BLOCK];从硬盘映射的缓存区中读取到i节点信息到内存i节点结构体中;
写i节点顺序是:((struct d_inode *)bh->b_data)[(inode->i_num-1)%INODES_PER_BLOCK] =*(struct d_inode *)inode;把i节点结构体内容从内存中写入到硬盘映射的缓存区中使用的i节点结构体(其实也就是硬盘上使用的i节点);
转载请注明作者和原文出处,原文地址:http://blog.csdn.net/yuzhihui_no1/article/details/43951153
若有不正确之处,望大家指正,共同学习!谢谢!!
- Linux内核源码分析--文件系统(五、Inode.c)
- Linux内核源码分析--文件系统(三、buffer.c)
- Linux内核源码分析--文件系统(四、Bitmap.c)
- Linux内核源码分析--文件系统(六、Super.c)
- Linux内核源码分析--文件系统(七、Namei.c)
- Linux内核源码分析--文件系统(八、Block_dev.c)
- Linux内核源码分析--文件系统(九、File_dev.c)
- 文件系统(一)--super.c bitmap.c inode.c 源码分析
- Linux内核文件系统 inode.c中_bmap函数理解
- Linux内核源码分析--文件系统(二、高速缓存区)
- Linux内核源码分析-卸载文件系统-sys_umount
- Linux内核分析(五)
- Linux内核分析(五)
- linux 0.11 内核学习 -- inode.c
- Linux内核源码分析之文件系统(1) -- 三思而后行
- Linux内核源码分析-安装普通文件系统-mount系统调用
- Linux内核源码分析-安装根文件系统-init_rootfs- init_mount_tree
- Linux内核源码分析-安装实际根文件系统- prepare_namespace
- php自动加载类 __autoload()函数
- APP被苹果App Store拒绝的79个原因(未完待续)
- Java 理论与实践: 构建一个更好的 HashMap
- 在你步入职业软件开发生涯那天起就该知道的五件事
- PHP强制浏览器不缓存的方法
- Linux内核源码分析--文件系统(五、Inode.c)
- JDBC java连接Oracle基本方法
- 网站优化之整站优化的重要性
- 机器学习技法-3-Kernel Support Vector Machine
- UVALive - 3029 City Game 推理
- 新站SEO的八个链接建设策略
- dubbo接口懒惰,惰性检查,懒加载,接口检查,服务检查
- 利用Azure快速创建WordPress博客网站
- 鼠标右键失灵了怎么回事