文章目录
- 第四章 文件的内部表示
-
- 索引节点
- 正规文件的结构
- 目录
- 路径名到索引节点的转换
- 超级块
- 为新文件分配索引节点
- 磁盘块的分配
- 其他文件类型
- 本章小结
- 习题
-
-
-
- 数组下标从0开始,那么为什么索引节点号是从1开始的呢?
- iget中睡眠,醒来为什么重新开始循环
- 描述算法,将内存索引节点作为输入,并修改相应的磁盘索引节点
- iget和iput没有要求提高处理机执行级别以封锁中断,这意味着什么?
- 怎么样才能高效的为bmap中对于间接块的循环进行编码?
- 运行下面命令,会发生什么?
- 一个文件系统能包含的文件数目的最大值是什么?
- 应该怎么样设计文件系统和相应的算法以允许任意长度的分量名?
- 考虑把路径名转换成索引节点的算法namei,当搜索在进行时,核心检查出当前工作索引节点是目录索引节点,其他进程有可能删除该目录嘛?核心怎样才能阻止这一点?
- 设计一个通过避免线性搜索来改进搜索路径名的效率的目录结构。考虑两种技术:散列和n元树;
- 理论上讲,文件系统永远不会含有其他索引节点号比被ialloc使用的“铭记”索引节点号小的空闲索引节点。为什么这一断言有可能不成立呢?
- 设计一个通过把常用文件名高速缓冲起来以减少为查到文件名而搜索目录的次数的方案;
- 链接表上一个磁盘块中应存储多少个空闲块号才是最适宜的?
- 谈论用位示图而不是块的链接表来记录空闲磁盘块的系统实现。这一方案的优点和缺点是什么?
-
-
第四章 文件的内部表示
UNIX系统中每个文件都有一个唯一的索引节点index_node,其中包含文件所有者、存取权限、文件长度、文件数据在文件系统中的位置等;
我们在使用文件的时候,使用文件路径来表示文件,核心将文件路径转换成文件的索引节点;
本章的算法的层次处在上一章所解释的高速缓冲算法之上;
iget:返回一个先前标识了的索引节点;
iput:释放索引节点;
其中iget和iput操作的内存中的索引节点;
bmap:做字节偏移量到磁盘块号之间的映射;
namei:做路径名与索引节点的映射;
alloc与free:分配与释放磁盘块;
ialloc ifree:为文件分配及释放索引节点;
索引节点
索引节点存在两份:磁盘上的和内存上的,之所有把其放置到内存上一份是为了做缓冲,提高效率,同时这里做的缓冲完全是使用的第三章的buffer设计;
索引节点以静态形式存在于磁盘上,核心把它们读进内存索引节点表中以操纵它们,由如下字段组成:
- 文件所有者
- 文件类型:正规类型、目录类型、字符设备类型、块设备类型、管道类型
- 文件存取许可权:按照如下三个类型进行权限管理,文件所有者、文件的所有者所在用户组以及其他用户,能分别进行设置;rwx-rwx-rwx 所以你明白了777是什么意思了叭! 然后chmod +x是什么意思貌似页明白咯,x:execute;777也明白什么意思了叭!
- 文件存取时间:文件最后一次修改的时间、最后一次存取的时间、最后一次修改索引节点的时间;
- 文件联结数目:在本目录树中有多少文件名指向该文件,这个在下面的章节中介绍;
- 文件数据的磁盘地址明细表;
- 文件长度;
注意:这里索引节点的缓冲方式和块设备的缓冲方式类似,即都会包含一个空闲表、散列队列用来管理可用和不可用的缓冲节点;
内存中的索引节点拷贝除了磁盘索引节点所包含的那些字段以外,还包含:
- 内存索引节点的状态:是否上锁、是否有进程在等待其变为开锁状态、索引结点的内存版本是否与它的磁盘拷贝不同、文件的内存表示是否与它的磁盘拷贝不同;该文件是否为安装点;状态决定了:有关竞争的条件、索引节点和文件分别与磁盘的统一程度,由此可见,引入高速缓冲之后是增加了很多复杂度的;
- 含有该文件的文件系统的逻辑设备号;个人猜测,不同设备可能拥有不同的文件系统,比如SSD,比如HD,比如Floppy,而且是用户可选的,比如在格式化U盘的时候是有选择选项的;
- 索引节点号,即记录了对应的inode在数组中的下标号;因为磁盘中的索引节点的组织方式是数组结构的,开头包含一张表;
- 指向其他索引节点的指针;
- 引用计数;指示出该文件的活跃实例数目;
那么这个引用计数有什么用呢?
- 只有当索引节点的引用计数为0时它才位于空闲表上,以表示核心能把这个内存索引节点表当作不活跃的索引节点的高速缓冲;
- 反观块设备缓冲区呢?只要缓冲区为开锁状态,它就位于空闲表中了;因为使用完之后都会调用brelse函数,其会将缓冲区放置到空闲表中;
- 难道不是只要索引节点的锁被解开,引用计数就为0了嘛?是这样的;
对索引节点的存取
获取的是内存中的索引节点,也就是说这部分算法直接交互的对象还是buffer,即缓冲区;
[外链图片转存失败(img-YRKw05sl-1567060305156)(en-resource://database/3308:1)]
核心用文件系统和索引节点号来标识特定的索引节点;iget算法和getblk算法如出一辙,核心将设备号和索引节点号映射到一个散列队列上,并且搜索该队列以便找到该索引节点,如果找不到,就从空闲表中分配一个索引节点,并且对它上锁;
然后就去磁盘中找对应的磁盘块号咯,块号=((索引节点号-1)/每块的索引节点数目)+索引结点表的起始块号;
知道了块号之后还需要使用缓冲区里的函数:bread,读出该块,然后计算该索引结点在该块中的字节偏移量:((索引节点号-1) mod (每块的索引节点数目))*磁盘索引节点大小;找到之后,拷贝到内存索引节点中,把它放到正确的散列队列中,并且将它的内存引用计数置为1;
当进程打开一个文件时,它就把索引节点引用计数增1,当引用结束的时候,比如当进程关闭一个文件时,就把索引节点啊引用计数间减1,当减到0的时候,意味着锁结束了;
算法iget,如果核心试图从空闲表中取出一个索引节点,但发现空闲表是空的,则报告一个错误;这与处理磁盘缓冲区是不同的,思考为什么不同?
- 首先文件的index_node是直接和用户相关的,即用户open一个文件,则会涉及到index_node,那么什么时候close呢?由用户决定,核心是无法预测的。
- 而反观磁盘缓冲区,磁盘缓冲区的buffer_head则是完全由核心来管理的,所以不会让iget的进程睡眠,而是直接返回错误,因为如果睡眠的话,核心是无法保证其一定能唤醒的;
算法iget会返回一个上了锁的索引节点数据结构,而且其引用计数比原来大1,上面图片中的文字还是