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 以降の部分については別途なエントリで、ってことで今日はおしまい。