FreeBSDでVirtualBoxを動かしていると巨大ファイルの転送でCannot allocate memoryが出る

FreeBSD 10.1-RELEASEな自宅ファイルサーバからMacにファイルをコピーすると「予期しないエラーが起きたため、操作を完了できません(エラーコード -50)。」が発生してコピーに失敗する現象に長らく苦しめられていた。経験的にファイルサイズが大きいほど発生確率が高く、数百MBくらいまでのファイルなら問題ないが、2GBを超えるとまずアウトっていう。鯖→Macの場合AFP(Netatalk 3.1.7)でもCIFS(Samba 4.2.5)でも発生し、鯖→Windowsの場合は言うまでもなくCIFSしか使えないが、所々詰まりながらも一応成功するといった具合。

失敗時はNetatalkのログに「Cannot allocate memory」が必ず記録されている。発生場所は大体{fork.c:913} (error:AFPDaemon): afp_read{dsi_stream.c:424} (error:DSI): dsi_stream_read_fileのどっちか。メモリたんねーと言われましても、32GB積んでるtopで見ても余裕のよっちゃんイカで数GBレベルで残ってますし…。もう全くわけがわからないよ!本格的に原因を探ろうとsshで各種情報をモニタリングしながらコピーしたら、今度はsshdまでCannot allocate memory吐いて接続切れるし……。

ドライバの不具合?NIC/L2SW由来の不具合??もしかしてケーブルが腐ってる???などなど、疑心暗鬼ロードを爆走していたが、ようやく、ついに!遂に!!原因がわかったッ!!!!

犯人はヤス何とVirtualBox VirtualBox実行中はnetgraph関連のメモリが不足しやすく?なるっぽい。ここここで同症状が報告されており、/boot/loader.confnet.graph.maxdata=65536を追加すればおkと書いてあった。

このカーネルパラメータはnetgraphのデータキューの最大確保数を表すものらしい。同様に非データ用のnet.graph.maxallocなんてのもある。それぞれ/usr/src/sys/netgraph/ng_base.cで定義されていて、コメントが若干怖いことが書いてあった。

static int maxalloc = 4096;/* limit the damage of a leak */
static int maxdata = 512;  /* limit the damage of a DoS */

下手に大きくすると問題発生時に被害が拡大しそうな雰囲気。ま、外部公開してなきゃそんなに気にしなくてもいいだろうけど。

ついでにdmesgLimiting open port RST response from 208 to 200 packets/sec.なるログも出ていたので、/etc/sysctl.confに以下を追加。

net.inet.icmp.icmplim=2000

肝心のloader.confも一応。

net.graph.maxdata=65536
net.graph.maxalloc=65536

上記設定で1~6GBほどのファイルを100GB分くらいコピーしてみたら、何の問題もなく完了した。普通に動くって素晴らしい。

参考サイト