block 分配器
文件和目录的内容存在磁盘块中,磁盘块都从一个空闲块池中分配出来。xv6 的块分配器包含一个磁盘上的空闲块位图,每个块占一个位。引导区,超级块,i 节点块和位图块的位永远都被置为有效。
每个bitmap块就是一个扇区大小,共512字节,每个字节是8bit,那么一个bitmap块就可以表示4096个扇区的状态。
1. balloc函数
balloc 分配一个新的磁盘块,从第0块开始一直到 sb.size(文件系统块总数),寻找一个在位图中的位是0的块。这个循环被分成两块。外层循环读位图的每一块。内层循环检查这一块中的所有 BPB 那么多个位(4096个状态位)。两个进程可能同时申请空闲块,这就有可能导致竞争,但事实上块缓冲只允许一个进程同时只使用一个块。
1.1 外层循环
BPB表示一个bitmap块表示的bit个数,也就是4096个,整个循环目的是找出文件系统中空闲的块位置,方法是通过检索bitmap来实现。BBLOCK用于计算一个实际的扇区号对应所在的bitmap的真实扇区号。
b/BPB的值表示一个实际的扇区号所在的bitmap的偏移量,加上sb.bmapstart就得出其所在的bitmap的真实扇区号。
通过bread读取一个bitmap扇区数据,这就是外循环所做的事。
1.2 内层循环
内层循环检测bitmap的数据,从而找到一个空闲的数据块。注意,内层循环的判断条件有两个:
- bi < BPB
- b + bi < sb.size
第一个条件用于控制寻找的次数在4096以内,第二个条件用于控制检测的磁盘扇区没有超出文件系统所表示的最大扇区号,因为最后一个birtmap中的所有位并不都是有效的。
bi % 8)表示bit位在当前字节中的偏移,m的值也就是1 << (bi % 8)表示当前bit位对应的字节掩码。bp->data[bi/8]表示当前bit所在的的字节数据,(bp->data[bi/8] & m)用于检测当前bit位的值。如果为0表示此bit位对应的扇区是空闲的。
如果找到空闲块则进行如下处理:
- bp->data[bi/8] |= m,将当前bit位标记为已使用状态。
- log_write(bp),表示bitmap数据已被修改,写回磁盘。
- bzero(dev, b + bi),b+bi表示空闲的磁盘扇区号,bzero表示将其清零。
1.2.1 bzero函数
- 读取对应扇区号的磁盘数据。
- 将buffer cache中的数据清零。
- 使用log_write表示需要将此buffer cache写会磁盘。
找到后返回b+bi,表示空闲的扇区号。
2. bfree函数
- 首先读取超级块数据,(为什么balloc时不需要读取???)。
- 接着读取此扇区号对应的biemap块数据。
- bi = b % BPB的值表示当前扇区号在4096个bit位中对应的位置。
- m = 1 << (bi % 8)和balloc中的一样,表示其对应的字节掩码。
- 校验是否是释放一个已经空闲的块。
- bp->data[bi/8] &= ~m,清除bitmap中其对应的位域。
- 通过log_write告知系统需要将修改后的bitmap块回写。
评论