vm-bhyve はカーネルのテストには向かない2018年02月10日 13時16分20秒

最近、bhyve を使って、カーネルの変更のテストをしている。sys/vm を変更しているので、カーネルモジュールは使えない。そうなると、カーネルをリンクし直して、インストールし再起動になる。bhyve を使うと、再起動が簡単になり、nfs を多用出来るので fsck を軽くできるので重宝している。

残念だが vm-bhyve は sys/vm などの低レベルを触る変更には向かないようだ。vm-bhyve は複数の仮想環境を管理するために使われる。そのため、各仮想環境をコンソールを使ってバックグラウンドで起動し、直接接続したい場合には cu デバイスを使って、接続する形を取る。そのため、vm-bhyve は ssh や http 等のリモートを主にした使い方には使い勝手が良い。

起動できなくなるような変更のテストは、そのままターミナルで始動する素の bhyve が良いようだ。なにせ、ブートローダでカーネルを古いカーネルの読み直しを繰り返さないと起動できない事も多い。 vm list で見ても起動してもいないし、vm connect を用いても繋がりもしない。

スワップ関連はロックとプロセス状態が複雑で難しい2018年01月17日 12時16分40秒

FreeBSD で無駄にスワップデバイスが解放されない場合があるので、実験してみた。

swapoff_all() 関数を参考に、スワップ領域が埋まってきたら、全てのプロセスのメモリを調べる。vmpage が実メモリに存在し、一度スワップに書き出されて呼び戻された後に、内容が更新されたとマークされているメモリを探す。

探して見付けたメモリの番地を表示したり、見付けた数を表示するだけは、比較的簡単に出来た。しかし、swp_pager_freeswapspace() 関数を呼び出すと、プロセスのスイッチやロック関連でカーネルパニックを連発する。他にも、何処からか kill シグナルが送られる様になったケースもあった。

スワップ領域が圧迫されている環境は、たいがい大量のページインとページアウトが行われている状態なので、それらの いIO 等と競合してしまうようだ。何度も試してみたが、思ったよりも複雑で、今は諦めるしか無さそうだ。

前回

vm.kmem_size_max が大きすぎても ZFS が動かない2017年12月21日 13時05分20秒

vm.kmem_size_max を大きくしすぎても ZFS が動かないようだ。メモリが 2GB の古い機種の /boot/loader.conf で
vm.kmem_size_max="1024m"
と設定してた。

時おり、以下の様なエラーを出して、操作不能になっていた。この状態になると、ファイルシステム自体にはダメージは無いが、システムの状態がおかしくなり再起動が必要になる。

taskqueue_start_threads: kthread_add(zio_free_issue_6): error 12vm_thread_new: kstack allocation failed
taskqueue_start_threads: kthread_add(zio_free_issue_7): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_free_intr): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_claim_issue): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_claim_intr): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_ioctl_issue): error 12vm_thread_new: kstack allocation failed
taskqueue_start_threads: kthread_add(zio_ioctl_intr): error 12vm_thread_new: kstack allocation failed
そこで、/boot/loader.conf でメモリの割り当てを半分にしてみた。
vm.kmem_size_max="512m"
この後は、もっとたくさんの zpool や zfs を扱える様になって、以前の様に、操作に失敗する事は無くなったようだ。

ただし、以前は 300MB まで増えていた ARC キャッシュが 50MB 前後の利用量に落されているようだ。

pagein した後でもスワップブロックは解放されない2017年12月20日 11時44分37秒

FreeBSD のコードと、動作の観察によると、FreeBSD では pagein した後でも、消費されているスワップのブロックはそのプロセスが終了するまで解放されない。そのため、実質の利用メモリよりも大幅にスワップ領域が消費される様だ。

例えば、clang をコンパイルすると、一つずつのプロセスが大量のメモリを必要とする。make buildworld -j 30 等とすると、あっと言う間にメモリが無くなる。実メモリが足りないとスワップデバイスに書き出される。それが、実メモリに呼び戻されて、メモリの内容が変更される。これの時、スワップデバイスは古いメモリの内容を保持し続ける。

このプロセスが、実メモリを 300MB 使っていたとしよう。このうち 100MB がスワップアウトされたとする。この時、このプロセスは実メモリを 200MB とスワップデバイスを 100MB 消費している事になる。この後、50MB がスワップインされてると、実メモリを 250MB 利用し、スワップデバイスを 100MB 利用する事になる。

もし、この 50MB の内容が更新されてもスワップデバイスはまだ、100MB 占有されている。つまり、実メモリ的には 300MB あれば、十分なのだが、350MB 分の記憶領域を保持していることになる。

この 50MB が更新されていなくて、メモリ掃除の対象になったら、既にスワップデバイスに同じ物があるので、そのままメモリの内容が破棄される。

まだ、この新しいメモリがスワップアウトする時に、何処に書き出されるかは掴めていない。

簡略すると、スワップ領域を大量に出し入れ使う状態に陥ると、必要以上のメモリ領域が浪費される。古いメモリの内容がスワップデバイスに残って、スワップ領域を無駄にするようだ。

Too big vm.kmem_size_max results process/thread creation errors2017年11月30日 13時26分58秒

Over-allocation of vm.kmem_size_max results in system instabilities. I have set vm.kmem_size_max to 1GB for i386 with 2GB of RAM.
vm.kmem_size_max="1024m"

I experiences kernel memory running out such as thread creation failures, unable to import multiple zpools, and process creation failures. seamonkey/firefox tends to fail to create a tab due to thread creation errors.

taskqueue_start_threads: kthread_add(zio_free_issue_6): error 12vm_thread_new: kstack allocation failed
taskqueue_start_threads: kthread_add(zio_free_issue_7): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_free_intr): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_claim_issue): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_claim_intr): error 12vm_thread_new: kstack allocation failed
kthread_add(zio_ioctl_issue): error 12vm_thread_new: kstack allocation failed
taskqueue_start_threads: kthread_add(zio_ioctl_intr): error 12vm_thread_new: kstack allocation failed

I reduced the size in /boot/loader.conf

vm.kmem_size_max="512m"
After this adjustments, I am be able to import multiple zpools, stopped seeing process and thread creation errors.

vm.swap_fragmentation sysctl が追加された2017年10月30日 12時55分41秒

11-STABLE に sysctl vm.swap_fragmentationが追加された。現在は、11.1-RELEASE が夏の終りに出されたばかり。次のリリースは 11.2-RELEASE なので、最初に使えるのはそこからになるだろう。

現在、二つのデバイスが割り当てられていて、利用量はゼロ。

% % sysctl vm.swap_fragmentation
vm.swap_fragmentation: 
Free space on device ada0s2b:
number of maximal free ranges: 1
largest free range: 262142
average maximal free range size: 262142
number of maximal free ranges of different sizes:
               count  |  size range
               -----  |  ----------
                   1  |  262142

Free space on device da0s2b:
number of maximal free ranges: 1
largest free range: 522610
average maximal free range size: 522610
number of maximal free ranges of different sizes:
               count  |  size range
               -----  |  ----------
                   1  |  522610
わざとスワップを使ってからの表示。
% sysctl vm.swap_fragmentation
vm.swap_fragmentation: 
Free space on device ada0s2b:
number of maximal free ranges: 11
largest free range: 232508
average maximal free range size: 22607
number of maximal free ranges of different sizes:
               count  |  size range
               -----  |  ----------
                   2  |  1
                   1  |  3 to 4
                   4  |  5 to 7
                   1  |  13 to 20
                   1  |  34 to 54
                   1  |  10946 to 17710
                   1  |  232508

Free space on device da0s2b:
number of maximal free ranges: 14
largest free range: 492884
averge maximal free range size: 36367
anumber of maximal free ranges of different sizes:
               count  |  size range
               -----  |  ----------
                   3  |  1
                   3  |  3 to 4
                   1  |  5 to 7
                   1  |  13 to 20
                   3  |  21 to 33
                   1  |  55 to 88
                   1  |  10946 to 17710
                   1  |  492884

killproc の dtrace が殺されてしまう2017年10月21日 12時02分49秒

OOM killer が呼ばれるのを、dtrace で観察しようと思った。OOM は「Out Of Memory」の略。

プロセスが選ばれてから、最後に解放されるまでの順序を探りたい。

$ dtrace -n 'fbt::killproc:entry{stack()}'
これで、まずはプロセスが落されるのを見付けれられると思ったが、そんなに簡単では無かったようだ。

pagedaemon が OOM Kill をやるのだが、メモリが枯渇している状況なので、dtrace が反応しない。dtrace 自体もスワップアウトされていたり、ページアウトされていたりする。また、シグナルの伝達も遅いので、kill シグナルが送られても、なかなかメモリが解放されずに、pagedamon が他のプロセスも殺し始めて、dtrace も落される。

vm_pageout_scan に、関数の呼び出しと終了以外の dtrace の観察点が仕掛けられているのを見付けた。

SDT_PROVIDER_DEFINE(vm);
SDT_PROBE_DEFINE(vm, , , vm__lowmem_scan);
...
                SDT_PROBE0(vm, , , vm__lowmem_scan);
dtrace でどのように呼び出せば良いかを調べる。
$ dtrace -l | grep lowmem_scan
39458         vm            kernel                              none vm-lowmem_scan
$ dtrace -n 'vm:::vm-lowmem_scan{stack()}'
          CPU     ID                    FUNCTION:NAME
  0  39458              none:vm-lowmem_scan
              kernel`0xc0b8d220

  0  39458              none:vm-lowmem_scan
              kernel`0xc0b8d220
カーネルから直接呼ばれているみたいだ。これは、11-STABLE の結果。11.2-RELEASE が前回のリリースだ。

FreeBSD のスワップ枯渇時の kill シグナルの伝達が遅い2017年10月19日 14時04分29秒

FreeBSD に業と過負荷をかけて遊んでいる。make buildworld -j 100 等とすると、clang のコンパイル時にあっと言う間に大量のメモリが持っていかれる。

まだ、確証は無いのだが、スワップ領域が埋め尽くされた後の kill がやけに遅い。まず、シグナルがプロセスに届くのにやけに時間がかかる。また、実メモリはすぐに解放されるようだが、スワップ領域の解放に時間がかかりすぎている様に見える。

top で観察していると、pagedaemon は動いているが、スワップの利用領域はなかなか下がらない。pagedaemon が何とか未解放のスワップを処理できれば、随分と効率が上がりそうに見えるが…

実験しているのは 11-STABLE で、現在は 11.2-RELEASE が出された後。

paging in/out と swaping in/out の大まかな違い2017年10月14日 14時06分45秒

swap out はプロセスを主メモリから、二次メモリに書き出す事。page out はプロセスのメモリの一部を二次メモリに書き出す事。

そのため、swap out されたプロセスの実行は不可能になる。page out されただけなら、主メモリに残っている部分で、プロセスを実行することが出来る。paging は、プロセスのアドレス空間を細かく区切って管理すること。

システムでは、top などで swap と表示したり、スワップデバイス、スワップファイル等と呼んだりするので、page-out と混同しやすい。

FreeBSD の syslog の出力を他のサーバに送る2017年10月13日 12時50分24秒

FreeBSD のハンドブックに Configuring Remote Logging がある。例えば、ファイアーウォール等の細かい設定や注意点はそちらを参照の事。

syslog を受けたい側のサーバ側を 192.168.0.1 とする。そして、今回の syslog を送るクライアント側を 192.168.0.3 としよう。

ハンドブックの記述には、サーバの 192.168.0.1 側の /etc/syslog.conf に

+192.168.0.3
*.*     /var/log/192.168.0.3.log
に書くと記述されている。しかし、/etc/syslog.conf を見ると、/etc/syslog.d に入っているファイルも読み込むようだ。そこで、
$ cat > /etc/syslog.d/192.168.0.3.conf
+192.168.0.3
*.*     /var/log/192.168.0.3.log
^D
$ touch /var/log/192.168.0.3.log
として、設定ファイルを作成し、ログファイルも作成する。

その後、192.168.0.1 の /etc/rc.conf に

syslogd_enable="YES"
syslogd_flags="-a 192.168.0.3"
を記述。-v -v でログのレベルをあげることも出来る。

今度は 192.168.0.3 のクライアント側の設定。192.168.0.3 の /etc/rc.conf に

syslogd_enable="YES"
syslogd_flags="-s"
と書き、syslogd を起動するが、192.168.0.3 サーバでは syslogd のパケットを受け取らないように記述する。