テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(writeboost report) v2.2.6をリリースしました

一週間前にv2.2.5をリリースしたばかりですが, v2.2.6をリリースしました. v2.2.5で入れた修正によって3.10(3.14以前)でコンパイルが出来なくなったためです. リードキャッシュを修正するために, DM_IO_BIOを使ってdm_ioを実行するコードを入れたのですが, これが入ったのが3.14(bioに大きな修正があった. bi_iterが追加)なので, それ以前のカーネルではコンパイルが通らなくなったということです. 3.14で行われた修正を参考にして, DM_IO_BVECを使うように修正しました. bash99という人がCentOS7で使ってるから捨てないでーと言ってますが, 実際にはTwitterでCentOS7でコンパイル出来ねえと言ってる人を見つけたので気づくことが出来ました. ありがとうございます.

github.com

ちょうど私が支笏湖にリフレッシュ旅行に行ってたということもあり, ついでに設計改善も検討して, 全部盛り込んだリリースとなっています. コーディングは主に, 森の中のテーブルでやりました. みなさんもたまには森の中でコーディングをしてみたらどうでしょうか.

github.com

ライトブーストは, rambuffer, SSD, HDDという3層を制御しているのですが, 副作用はrambufferからHDDに一方向に伝搬していきます. それぞれの間はproducer-consumerパターンになっているのですが, 実装的により明確にするようにしました. その方が, メモリバリアの挿入がよりわかりやすくなるのと, 終了処理がきれいになるからです. メモリバリアについて軽く説明すると, プログラムというのは, 書いた順に実行されるとは限りません. コンパイラやCPUは, 全く依存関係のないコードをout-of-orderに実行します. 従って, スレッドAがデータを書く -> idをincrementする -> スレッドBがidのincrementに気づく -> データを読むというproducer-consumerのような形では, 正しくメモリバリアを挿入しなければ, スレッドBが, スレッドAがライトする前のデータを読む可能性があります. だから, スレッドAがデータを書く -> ライトバリアを挿入; idをincrementする -> スレッドBがidのincrementに気づく; リードバリアを挿入 -> データを読む という形でメモリバリアを挿入してあげる必要があるのが, デザインパターンのような, お決まりの形です. なので, このお決まりの形により明確に帰着させるために, 土台の設計改善もやったというのが今回の修正です. もっと知りたい人は https://www.kernel.org/doc/Documentation/memory-barriers.txt を読んでください. (関係箇所を以下に抜粋)

[!] Note that the stores before the write barrier would normally be expected to
match the loads after the read barrier or the data dependency barrier, and vice
versa:

    CPU 1                               CPU 2
    ===================                 ===================
    WRITE_ONCE(a, 1);    }----   --->{  v = READ_ONCE(c);
    WRITE_ONCE(b, 2);    }    \ /    {  w = READ_ONCE(d);
    <write barrier>            \        <read barrier>
    WRITE_ONCE(c, 3);    }    / \    {  x = READ_ONCE(a);
    WRITE_ONCE(d, 4);    }----   --->{  y = READ_ONCE(b);
 (*) smp_mb__before_atomic();
 (*) smp_mb__after_atomic();

     These are for use with atomic (such as add, subtract, increment and
     decrement) functions that don't return a value, especially when used for
     reference counting.  These functions do not imply memory barriers.

     These are also used for atomic bitop functions that do not return a
     value (such as set_bit and clear_bit).

     As an example, consider a piece of code that marks an object as being dead
     and then decrements the object's reference count:

    obj->dead = 1;
    smp_mb__before_atomic();
    atomic_dec(&obj->ref_count);

     This makes sure that the death mark on the object is perceived to be set
     *before* the reference counter is decremented.

その他, 次リリースの4.8カーネル(現在はrc6)では, bioのフラグの持ち方に大きな修正が入ります. 具体的には, bi_rwに詰め込んでいたものをbi_opとbi_opfに分離します. 4.8-rc6に上げてみるとコンパイルが通らなくなっていたので, 追従しておきました.

github.com

疲れた・・・