code:getblk - ikarishinjieva/unixV6-code-analyze-chs GitHub Wiki

Table of Contents

Source

  • 寻找 与指定设备指定块号匹配的缓存块
    • 如找到匹配,则返回 指向该缓存块管理结构的指针
    • 如找不到匹配,则申请空闲缓存块,返回指向该缓存块管理结构的指针
  • 共传入两个参数 dev , blkno
    • dev 指定设备号
    • blkno 指定块号
  • getblk的第二功能(与设备IO无关)
    • 可以为程序提供512字节长的缓存区
    • 为避免错误,此时设备为NODEV
    • 此时传入参数 dev 为负
4913

4914 /* Assign a buffer for the given block. If the appropriate

4915  * block is already associated, return it; otherwise search

4916  * for the oldest non-busy buffer and reassign it.

4917  * When a 512-byte area is wanted for some random reason

4918  * (e.g. during exec, for the user arglist) getblk can be

4919  * called with device NODEV to avoid unwanted associativity.

4920  */

4921 getblk(dev, blkno)

4922 {

4923     register struct buf *bp;

4924     register struct devtab *dp;

4925     extern lbolt;

4926

4927     if(dev.d_major >= nblkdev)

4928          panic("blkdev");

  • 如果外设主设备号越界,则执行panic,进行出错处理
4929

4930     loop:

4931     if (dev < 0)

4932          dp = &bfreelist;

  • 若dev为负数
4933     else {

4934          dp = bdevsw[dev.d_major].d_tab;

4935          if(dp == NULL)

4936           panic("devtab");

  • 若dev为正数且不越界,则将dp指向该设备的设备控制结构
    • 此时如果dp为空,则调用panic进行出错处理
4937          for (bp=dp->b_forw; bp != dp; bp = bp->b_forw) {

4938           if (bp->b_blkno!=blkno || bp->b_dev!=dev)

4939                continue;

  • 遍历设备队列,查找与设备号dev和块号blkno匹配的缓存块
4940           spl6();
  • 处理机优先级设为6,防止不必要的中断进入
4941           if (bp->b_flags&B_BUSY) {

4942                bp->b_flags =| B_WANTED;

4943                sleep(bp, PRIBIO);

4944                spl0();

4945                goto loop;

  • 如果带有B_BUSY标志,表明当前块正在被使用,置B_WANTED
  • 进程睡眠
  • 睡眠结束被唤醒,开中断,回到4930行,重新从设备队列中寻找包含当前块的缓存
  • 这里涉及进程对于缓存块的竞争机制,参见设备缓存管理
4946           }

4947           spl0();

4948           notavail(bp);

4949           return(bp);

4950          }

4951     }

  • 如果不带B_BUSY标志,表明当前块可以被使用
  • 开中断
  • 将该缓存快从自由队列中取出,并返回指向该缓存管理块的指针bp
  • 此处与4960行的notavail函数疑似笔误
    • 在源代码中找不到该函数的定义,只有notavil
    • Lions在分析到此处时也说见4999行(notavil的定义)
    • 因此可能是将notavil误写为了notavail
4952     spl6();

4953     if (bfreelist.av_forw == &bfreelist) {

4954          bfreelist.b_flags =| B_WANTED;

4955          sleep(&bfreelist, PRIBIO);

4956          spl0();

4957          goto loop;

4958     }

4959     spl0();

4960     notavail(bp = bfreelist.av_forw);

4961     if (bp->b_flags & B_DELWRI) {

4962          bp->b_flags =| B_ASYNC;

4963          bwrite(bp);

4964          goto loop;

4965     }

  • 如果自由队列不为空
  • 判断是否含B_DELWRI标志
    • 若含B_DELWRI,增设B_ASYNC,将其异步写回设备
    • 回到4930行处开始执行
4966     bp->b_flags = B_BUSY | B_RELOC;

4967     bp->b_back->b_forw = bp->b_forw;

4968     bp->b_forw->b_back = bp->b_back;

  • 若不含B_DELWRI,b_flags置为B_BUSY
    • B_RELOC标志为 UNIX 源代码写作时的遗留,已经无作用 (引自Lions源代码分析)
  • 将该缓存块从原设备队列中取出
4969     bp->b_forw = dp->b_forw;

4970     bp->b_back = dp;

4971     dp->b_forw->b_back = bp;

4972     dp->b_forw = bp;

  • 将该缓存块插入新的设备队列队首
4973     bp->b_dev = dev;

4974     bp->b_blkno = blkno;

4975     return(bp);

  • 设置缓存块的设备号与块号
  • 返回指向该缓存管理块的指针bp
4976 }

4977 /* ------------------------- */

Extend

附图

Ref

Caller

⚠️ **GitHub.com Fallback** ⚠️