2009年7月30日木曜日

(FreeBSD) panic get_pv_entry: increase vm.pmap.shpgperproc

いろいろと忙しく仕事している、(5月ころbuildworldした)FreeBSD 7.2-STABLEなマシンで、先日、kernel panicが発生しました。

get_pv_entry: increase vm.pmap.shpgperproc

というメッセージが残されていました。



しかも、このkernel panic、立て続けに、数回発生。



けっこう安定して動作していたのに、突然の連続kernel panicで、ちょっと嫌な気分。



ネット検索してみると、この辺に、似たような話を発見。7.0-RELEASE-p5の場合で、ちょっと違いもありますが。



kernel: Approaching the limit on PV entries...
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=2052953+0+archive/2008/freebsd-questions/20081012.freebsd-questions



kernel panicするという話も、こちらに出てます。
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=2082943+0+archive/2008/freebsd-questions/20081012.freebsd-questions



pv_entryについて、少し解説がされてました。
http://docs.freebsd.org/cgi/getmsg.cgi?fetch=2094590+0+archive/2008/freebsd-questions/20081012.freebsd-questions





このpanicを発生させているのは、src/sys/i386/i386/pmap.cです。



7.2-STABLEは、RELENG_7ブランチなので、ソースコードはこれ(i386版なので)。
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/i386/i386/pmap.c?rev=1.594.2.18;content-type=text%2Fplain



get_pv_entryという関数の中ですね。



私が見たケースでは、

Approaching the limit on PV entries, consider increasing either the vm.pmap.shpgperproc or the vm.pmap.pv_entry_max tunable.

というメッセージは残っていませんでした。ディスプレイを接続していなのでわかりませんが、コンソール画面には出ていたかもしれないですけど。



さてさて、

get_pv_entry: increase vm.pmap.shpgperproc

でkernel panicしてるのは、ここですが・・・



/*
* Access to the ptelist "pv_vafree" is synchronized by the page
* queues lock.  If "pv_vafree" is currently non-empty, it will
* remain non-empty until pmap_ptelist_alloc() completes.
*/
if (pv_vafree == 0 || (m = vm_page_alloc(NULL, colour, (pq ==
    &vm_page_queues[PQ_ACTIVE] ? VM_ALLOC_SYSTEM : VM_ALLOC_NORMAL) |
    VM_ALLOC_NOOBJ | VM_ALLOC_WIRED)) == NULL) {
    if (try) {
        pv_entry_count--;
        PV_STAT(pc_chunk_tryfail++);
        return (NULL);
    }
    /*
     * Reclaim pv entries: At first, destroy mappings to
     * inactive pages.  After that, if a pv chunk entry
     * is still needed, destroy mappings to active pages.
     */
    if (pq == NULL) {
        PV_STAT(pmap_collect_inactive++);
        pq = &vm_page_queues[PQ_INACTIVE];
    } else if (pq == &vm_page_queues[PQ_INACTIVE]) {
        PV_STAT(pmap_collect_active++);
        pq = &vm_page_queues[PQ_ACTIVE];
    } else
        panic("get_pv_entry: increase vm.pmap.shpgperproc");
    pmap_collect(pmap, pq);
    goto retry;
}



よくわからないっす。[E:coldsweats01]



panicするんじゃなくて、システムコール(?)を失敗させるとか、もしくは、processをkillしちゃうとか(どうも、ここで必要なメモリ量は、process数と関係しているっぽいので)、何かもう少しましな方法があるんじゃないかと思うのですが・・・



swap不足になったとき、processがどんどこkillされたりしますねよ。あんな感じでいいので、とりあえず、OSとしては運用を継続して欲しいところです。



panicされちゃうと、file systemがdirtyのままになるので、fsckに時間がかかってたまらないし、なによりも、ファイル内容の破壊が怖いです。





とりあえずの解決方法。



vm.pmap.shpgperprocを増やせ、といってるので、増やしてみました。



これ、OSが立ち上がった後では変更できないパラメータなので、/boot/loader.confで指定しなければなりません。



ですが・・・、どんだけ増やせばいいのか? よくわかんないです。



デフォルトが200で、とりあえず50増やしてみて、やっぱりpanic。また50増やして・・・とやっていって、400でどうやらpanicしなくなったようです。



何をしたとき、pv_entryが不足するのか?・・・それが気になって、こんなシェルスクリプトを走らせておいて、いろいろ負荷をかけて観察してみました。

#! /bin/sh



( while [ /bin/true ] ; do
    sysctl vm.pmap
    sleep 0.5
  done ) | awk '
/pg_ps_enabled/ { printf("\n"); }
{ printf("%d ", $2); }
'

実行すると、こんな感じで、sysctl vm.pmapで表示される値を、表示しつづける、というもの。一部のパラメータは(ひたすらカウントアップしていくらしい)、signed intのために、負の値へ突入しちゃってますね。



0 0 0 68464 -2143457166 -2144110094 0 8838034 8840181 2147 652928 0 0 0 0 400 3362352
0 0 0 68797 -2143455008 -2144107939 0 8838043 8840191 2148 652931 0 0 0 0 400 3362352
0 0 0 68922 -2143449222 -2144106732 0 8838049 8840211 2162 657510 0 0 0 0 400 3362352



ところで、このスクリプト、改行位置が1列分、ずれてるみたい。awkで実行する2行を入れ替えればいいのかな。



で、観察してみたんですが、panicしなくなっちゃって、結局よくわからなかったです。
けっこうたくさんのプロセスが起動していても、手計算してみると、80%くらい、余裕で空きがあるように見えたんですが。



よくわかんないですねぇ・・・



% sysctl vm.pmap
vm.pmap.pmap_collect_active: 0
vm.pmap.pmap_collect_inactive: 0
vm.pmap.pv_entry_spare: 68508
vm.pmap.pv_entry_allocs: -2142835831
vm.pmap.pv_entry_frees: -2143492075
vm.pmap.pc_chunk_tryfail: 0
vm.pmap.pc_chunk_frees: 8840296
vm.pmap.pc_chunk_allocs: 8842453
vm.pmap.pc_chunk_count: 2157
vm.pmap.pv_entry_count: 656244
vm.pmap.pde.promotions: 0
vm.pmap.pde.p_failures: 0
vm.pmap.pde.mappings: 0
vm.pmap.pde.demotions: 0
vm.pmap.shpgperproc: 400
vm.pmap.pv_entry_max: 3362352
vm.pmap.pg_ps_enabled: 0



しかも、これって、一般ユーザー権限でkernel panicを発生させられちゃうので、local user exploitableなDoSじゃん? と思うわけで・・・



0 件のコメント:

コメントを投稿