和Steve之间的通信--RE: 关于《UNIX技术内幕》的勘误及遇到的问题_16

  1. 云栖社区>
  2. 博客>
  3. 正文

和Steve之间的通信--RE: 关于《UNIX技术内幕》的勘误及遇到的问题_16

罗宾豪 2012-07-12 12:47:08 浏览628
展开阅读全文
From: quntmec@hotmail.com
To: qf.hao@hotmail.com
Subject: 关于《UNIX技术内幕》的勘误及遇到的问题_16
Date: Fri, 2 Dec 2011 18:27:20 +0800

郝先生,

目前碰到的问题如下:

1、第256页提到的 bfreelist 和 rktab 这2个链表,其实每个链表里都各自包含2个链表,即如下:

对于bfreelist,
由 b_forw, b_back 组成:缓存记录链表(已分配块链表)
由 av_forw,av_back组成:可用缓存链表(未分配块链表)

对于rktab,
由 b_forw, b_back 组成:初始完成链表(已分配块链表)
由 av_forw,av_back组成:操作链表

是这样吗?如果是的话,那么

1)建议在8.4.2节开始处以表格形式列出,这样会比较直观(因为从后面的章节里,我发现不少地方是直接以“初始完成链表“、”缓存记录链表“等称呼所使用的链表,当我回头找这些链表的定义时只能从字里行间找,比较费劲,不知道其他读者是否会有相同的看法....)
[郝]:对,该处确实比较不容易理解和记忆。表格是个好办法。
2)(bfreelist,b_forw, b_back)和(rktab,b_forw, b_back)都包含“已分配”块的信息,这2个链表有什么不同吗?
[郝]:bfreelist是全局链表,rktab是和设备相关的链表,rktab中的元素是从bfreelist中获得的,用完后会再返还给bfreelist。
开始单独加说明可能更好理解一些。
2、第264页,getblk代码第45~50行,其中,

45、46行:在 bfreelist 的缓存记录链表中删除该缓存块
49、50行:在 rktab 的初始完成链表中添加该缓存块

1)那47、48行代码的意思是什么?
[郝]:第47~50行都是把bp添加到dp链表中的dp和dp->b_forw之间。
2)45、 46行代码的意义是什么?即为何要从缓存记录链表中删除该缓存块?说到底,还是上面 第1 中的 2)里的问题(即,(bfreelist,b_forw, b_back)和(rktab,b_forw, b_back)都包含“已分配”块的信息,这2个链表有什么不同吗)。
[郝]:顾名思义,bfreelisti包含了空闲块链表(以av_forw/av_back记录)和已经分配的块缓存链表(以b_forw/b_back记录),这里是很容易忽视的一点!bfreelist实际上包含了两个链表。
rktab也包含两个链表,一个是已经分配的而且正在向设备也就是磁盘读写的单向块缓存链表,另一个是初始完成链表(完成或没有完成磁盘操作的链表)。具体见261页。
3、第268页,brelse函数,对比第263页的getblk函数,为何brelse函数只在“可用缓存链表“(bfreelist)里增加“被释放的块”,而没有将该“被释放的块“从“初始完成链表“(rktab)里删除?
[郝]: 因为该块要放到rktab的初始完成链表中,这样以后如果上层接口需要访问该对应磁盘块数据的时候,就可以直接从rktab中找到读取出来(getblk 的11~27行所作的)。相反,如果直接把它从rktab中删除,那么以后上层再想访问该磁盘块时,就会找不到而不得不从磁盘再读一遍,这显然是性能上的 降低。
4、第271页,第4段,“那么如果当前有两个进程挂起在相同的fp->s_flock上,...“(总共2句 话)是对上面 if...sleep的解释。我看的不太懂。我的理解是:如果用if,则不管 fp->s_flock 如何,只要进程被唤醒,则程序继续往下执行(跳出 if 语句)。但如果使用 while,则即使进程被唤醒,也要再次判断 fp->s_flock 上的值才能决定是否跳出循环。是这样吗?
[郝]:对。在一个进程挂起在fp->s_flock上的时候,还没有问题,但如果有两个以上就会出错。很多其他地方也是这样做的。

5、第280页,倒数第3段,倒数4行:“并且读取300 号块中的数据到缓存中....(一直到段末,共4行)“。既然进程B释放了(brelse)300号缓存,那为何进程A还能在 rktab的“初始完成链表”里找到300号缓存块?这似乎又跟上面 第3个 问题有些关联。
[郝]:对。你已经意识到这一点了,所以你其实再想想就可以了解问题3了,甚至都不用我回答。所以可以大胆想象推理,都没有问题。
6、第282页,倒数第2段,第2行:“比如,第一次访问300号...,那么B首先获得块缓存就是必然了“(共2行)。这2句话看得不太明白。能稍微详细一点的解释一下吗?为何B首先获得块缓存是必然的?
[郝]:因为那样B因为没有挂起,中断就会发生在B的上下文中,而中断结束时,B会继续执行,而分配到缓存。
7、第283页,图8-50,这个图跟 图8-47 有什么不同吗?
[郝]:请参考问题6.
8、第286页,倒数第4段,第1行:“...由于块缓存 B_BUSY 标志被设,...“。这个 B_BUSY标志 是在哪个函数里被设的?我找了一下,似乎都没找到
[郝]:就是在上一步“500号块正在被其他进程。。。”,可以在代码中搜索一下B_BUSY,可能是在notavail中,或其他地方。
9、 第290页,最后一段,你指的“‘罪魁祸首‘是alloc函数”是指:alloc 中的第26行的clrbuf(bp)这句吗?是因为这句只是清除了缓存的内容,但这个函数并没有相应的清除磁盘上对应的块的内容;而bmap的第28行 bdwrite(bp) 就是为了完成“清除磁盘上对应块的内容“(实际就是将清空后的缓存内容写盘),以保证缓存和磁盘一致。是这样吗?
[郝]:是这样的。
10、第297页,iget代码的第20~21行,为何要重新设定dev和ino?
[郝]:这里表示该设备是加载的设备(磁盘),不是系统磁盘,所以要设定它真正的设备号,也就是ip->m_dev.
11、第299页,第1段,第3行“分配inode[0]作为1号节点缓存“。这个在哪里实现的?是在 第20 ~ 21行代码里实现的吗?如果是的话,能解释一下吗?(没看明白)
[郝]:是在第30~31行。
[郝]:最后对于如何研究代码我的一个一般性的建议就是对于一个函数,如果不明白,可以反复阅读几次,同时参照讲解,
然后从总体上理解这个函数的功能再研究细部,就是一个细部--->抽象(全局)---->再细部---->再抽象(全局)的过程。


此外,勘误如下:
267 3 1 “...首先调用binit(6.4.2)...“应是8.4.2
274 11 1 “...它通过把blk1记录的空闲块个数(块中起始2字节)...“。如果按照上例,起始2字节应该是 n
274 15 2 “...,再记录块bno到 s_free[0]中...”。应该是 bno到s_free[s_nfree]中。
279 1 2 “9行开始重新执行...“,应该是21行
288 4 3 “见6.2.1节...“,应该是8.2.1节
293

图8-59,似乎图不对,缺少“612块“
298 3 2 “参见6.3.10“应该是8.3.10
299 1 4 “i_mode~i_addr[8]...”,应该是“i_flag~i_lastr”,因为这里说的是内存中的inode(253页)

[郝]:谢谢

Steve

网友评论

登录后评论
0/500
评论
罗宾豪
+ 关注