Lions' 本読み (131)

b_flags で xref を追いかけてみます。最初は定義なのでスルー。
いっちゃん最初に出てくるのは bread 手続き。

4758    rbp = getblk(dev, blkno);
4859    if (rbp->b_flags&B_DONE)
4860            return(rbp);

getblk で取得したバッファが最新 (ディスクの情報と同一) であればディスクからの読み込みはスルーでバッファを戻している模様。
次も bread 手続きでした。ディスクアクセスな要求を kickoff する前に b_flags に B_READ を設定して読み込み要求としています。

4761    rbp->b_flags =| B_READ;
4762    rbp->b_wcount = -256;
4763    (*bdevsw[dev.d_major].d_strategy)(rbp);

次は breada 手続きの以下の箇所です。

4780    if (!incore(dev, blkno)) {
4781            rbp = getblk(dev, blkno);
4782            if ((rbp->b_flags&B_DONE) == 0) {
4783                    rbp->b_flags =| B_READ
4784                    rbp->w_count = -256;
4785                    (*bdevsw[adev.d_major].d_strategy)(rbp);

ここでも getblk して DONE ならスルー。ちなみに最後で以下な記述になってますが

4800    iowait(rbp);
4801    return(rbp);

iowait では b_flags が DONE なら sleep せずに終わっていますね (中身は別途)。
次は先読みな部分で以下。

4788    if (rablkno && !incore(dev, rablkno)) {
4789            rabp = getblk(dev, rablkno);
4790            if (rabp->b_flags & B_DONE)
4791                    brelse(rabp);

上記では getblk で取得できたバッファの b_flags が B_DONE なら brelse 手続きを呼び出して av_ なリストに追加しています。先読みなブロックは他の人が使うかも、という配慮だと考えられます。
次のブロックはバッファが B_DONE ではない場合のソレ

4792    else {
4793            rabp->b_flags =| B_READ|B_ASYNC;
4794            rabp->b_wcount = -256;
4795            (*bdevsw[adev.d_major].d_strategy)(rabp);

getblk したバッファが最新ではないので、読み込みリクエストを kickoff してます。B_SAYNC が立っている場合、ディスクアクセス完了割り込みな rkintr から呼び出される iodone 手続きでバッファが av_ なリストに追加されます。
これってどーゆー意味なのかな。あ、リスト追加と共に B_ASYNC なフラグも除去されてますね (iodone 手続き)。ここで言われてる_非同期_って待たない、という意味だと思ってるんですがダウトなのかどうなのか。

bwrite 手続き

全部引用した方が良さげ。

4816    flag = rbp->b_flags;
4817    rbp->b_flags =& ~(B_READ | B_DONE | B_ERROR | B_DELWRI);
4818    rbp->b_wcount = -256;
4819    (*bdevsw[rbp->b_dev.d_major].dstrategy)(rbp);
4820    if ((flag&B_ASYNC) == 0) {
4821            iowait(rbp);
4822            breslse(rbp);
4823    } else if ((flag&B_DELWRI)==0)
4824            geterror(rbp);

フラグを四つ取って、書き込み要求を kickoff した後に

  • B_ASYNC が立ってなければ処理完了を待って brelse する
  • B_ACYND がオンで B_DELWRI がオフなら geterror 手続き呼び出し

ということらしい。geterror 云々は今はスルーで。

bdwrite 手続き

出力要求した後、対象デバイスがテープ以外なら云々。

4843    dp = bdevsw[rbp->b_dev.d_major].d_tab;
4844    if (dp == &tmtab || dp == &httab)
4845            bawrite(rbp);
4846    else {
4847            rbp->b_flags =| B_DELWRI | B_DONE;
4848            brelse(rbp);
4849    }

バッファの内容はディスクよりも新しい、という目印を付けて av_ なリストに追加。これ、B_DONE も一緒にオンにしてるあたりもアレゲ

bawrite 手続き

実質的に B_ASYNC して bwrite てそのままです。

4862    rbp->b_flags =| B_ASYNC;
4863    bwrite(rbp);

brelse 手続き

最初に以下な判定などの前処理。

4876    if (rbp->b_flags&B_WANTED)
4877            wakeup(rbp);
4878    if (bfreelist.b_flags&B_WANTED) {
4879            bfreelist.b_flags =& ~B_WANTED;
4880            wakeup(&bfreelist);
4881    }

解放な手続きなので B_WANTED な場合、その根拠なソレを引数に wakeup を呼び出してるんですが、最初のソレは B_WANTED をクリアしてないあたりが若干気になります。
む、B_WANTED をクリアしてるのは iodone だな。つうか B_WANTED を立てて sleep するのは getblk てことで良いのかな。
バッファの場合と bfreelist の場合は B_WANTED な待ちのソレがちょっと異なるのかどうか。このあたりも宿題ということにしておきます。あと以下もスルー。

4882    if (rbp->b_flags&B_ERROR)
4883            rbp->b_dev.d_minor = -1;

最後が brelse 手続きで b_flags をおろす処理です。

4887    rbp->b_flags =& ~(B_WANTED|B_BUSY|B_ASYNC);

getblk 手続き

incore 手続き的探索で対象のバッファが見つかった後の判定。

4941                    if (bp->b_flags&B_BUSY) {
4942                            bp->b_flags =| B_WANTED;
4943                            sleep(bp, PRIBIO);

そのバッファが B_BUSY な状態であれば sleep しています。その後、!incore だった場合の処理として bfreelist が空だった場合の判定。

4953    if (bfreelist.av_forw == &bfreelist) {
4954            bfreelist.b_flags =| B_WANTED;
4955            sleep(&bfreelist, PRIBIO);

で、次は割り当てた bfreelist のソレが B_DELWRI (書きこまなきゃいけないバッファ) の場合の記述。

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;

なきゃいけない、ので書きこみに行って loop からやりなおし。最後に getblk 手続きから戻るバッファの b_flags の最低限の初期値の設定。

4966    bp->b_flags = B_BUSY | B_RELOC;

あ、getblk 手続きで_初期化_されるのか。気がついてませんでした。ここポイント高いですね。あと iowait 手続きのソレはスルーで、bio.c の Page 7 以降の部分については別途なエントリで、ってことで今日はおしまい。