原文:我是一块硬盘(下)
目录我问老大: 每个文件都需要有个inode来描述, 每个目录是不是也需要一个?
”这是自然,和文件一样, 每个目录也是一个inode, 其中有目录的属性,还有存放这个目录内容的磁盘块号,在磁盘块中才真正的存放着目录下的内容““举个例子来说吧: 有人要读取 /tmp/test.log 这个文件, 查找次序是这样的:根目录inode->根目录磁盘块->tmp目录inode->tmp目录磁盘块->test.log的 inode->读取磁盘块”(点击看大图)内存说: “我赛,这也太绕了吧,比CPU访问我的数据麻烦多了, 硬盘,你要小心点, 这要是操作不当的很容易出乱子的。”
我心想内存这次没坑我,他提醒的对, 这操作确实有点复杂,读数据的时候还行, 如果是修改,尤其是删除就很容易出事,例如想删除上面的文件/tmp/test.log,需要这些步骤:(1) 在目录中删除文件(2) 释放inode 到空闲的节点池, 这样可以复用(3) 将磁盘块释放到空闲的磁盘块池
在操作某一步的时候出现系统崩溃,那我这些个目录和文件就凌乱了, 可能会出现空间无法释放的情况。
老大说: “这确实比较烦, 不过也能解决,听说过数据库是怎么办的吗: 记录日志! ”
”就是把要做的事记录下来?“
“是的, 在做操作之前, 记录要做的事情,形成日志, 把他们成功写入磁盘以后再正式动手操作, 等到所有步骤都搞完,才可以擦除日志项。 你想想,如果执行到某一步崩溃, 系统重启时检查日志项,就知道哪些没做,哪些已经做了, 对于没做的日志,重新来一遍就是了” 。
其实说的很轻松,实施起来还是挺难的, 重新执行就意味着那些操作一定是可以重复执行, 并且不会带来破坏才行。 (码农翻身注:这叫做日志(Journal)文件系统)管理空闲块目录和文件的存储问题解决了, 接下来我需要一个大管家,把那些没有使用的、空白的、数量上亿的磁盘块给管理起来,只有这样, 新的文件来的时候,才能分配空间存储。
操作系统老大给我推荐了两位, 第一位主张是链式大法好, 无非就是把空闲磁盘块组成一个链表(又是链表!) ,但是我心里盘算了一下: 如果磁盘块号是32位的,每个块都得花费我32位的空间,如果我有5亿个空闲块, 那仅仅为了记录他们就要占用接近2G的磁盘空间! 这浪费可是有点大啊。
还有一位主张位图法, 这个方法更简单, 对每个磁盘块,如果已经被使用,那就标记为1, 没被使用就是0。 这样整个磁盘块就形成了一个由0和1组成的一个大位图。
由于每个磁盘块只用一个位来表示, 非常节省空间, 这个方案我喜欢!文件系统扯了这么多,是时候看一看全局了, 在你们程序员的眼中, 其实我是长这个样子的(拿你们崇拜的Linux ext2为例):(点击看大图)我这个硬盘主要由MBR(Master Boot Record)和各个磁盘分区组成。
MBR中的有 引导代码 和 磁盘分区表, 分区表中记录了每个分区的起始位置,以及哪个磁盘分区是活动分区, 这样系统就会找到它, 然后装载这个分区中的引导块,并执行之。
引导块将会装载存存储在本分区的操作系统。 需要注意的是,每个分区都有一个引导块,不管这个分区有没有操作系统,这是各大厂商的约定,是一种标准。
每个分区除了必须的引导块之外,又被分成多个块组。
在每个块组中你能看到熟悉的磁盘块位图和inode位图, 不用解释估计你也知道是干嘛的。还有inode表(当然是存放文件和目录的inode 了)和真正的数据块。
对了, 我的磁盘分区表只有64个字节, 而每个分区项占用16个字节, 所以只能容纳4个分区。 如果你想用多于4个分区, 你就需要把其中一个设为扩展分区, 然后在其中继续划分成逻辑分区,想划几个就划分几个。
一般情况下,大家都喜欢把我划分成一个主分区+一个扩展分区, 在扩展分区中再需要划分。
(完)