2016/12/21

qcow2 の cluster leak を直す

qcow2 の cluster leak を直してみたログ。
オチがついてて原因が完全特定できていないのでふわっとしたお話。


環境

Host OS: CentOS 7.1.1503
Host Kernel: 3.10.0-327.4.5.el7.x86_64
qemu-img: 1.5.3


状況

VMイメージ を GFS2 上に置いているVMで ls が返ってこない。
pcs から見る限り clvmd も dlm も全ノード上で動いているし全ノード online になっている。
過去にクラスタの1ノードが物理的な問題で急に落ちたこともあって VM イメージの破損を疑ってみる。
調べてみると qcow2 の整合性の確認には qemu-img の check コマンドを使うことができるらしい。

qemu-img check を qcow2 に対して打つとこんな結果が返ってくる。
[root@hoge ~]# qemu-img check /mnt/hoge/fuga.qcow2
Leaked cluster 42362 refcount=1 reference=0
Leaked cluster 42363 refcount=1 reference=0
Leaked cluster 42364 refcount=1 reference=0
Leaked cluster 42365 refcount=1 reference=0
4 leaked clusters were found on the image.
This means waste of disk space, but no harm to data.
65043/524288 = 12.41% allocated, 0.15% fragmented, 0.00% compressed clusters
Image end offset: 4264099840
何やらエラーが返ってきている。
同じ GFS2 の上にある VM に対しても qemu-img check すると
[root@hoge ~]# qemu-img check /mnt/hoge/piyo.qcow2
No errors were found on the image.
468877/524288 = 89.43% allocated, 0.13% fragmented, 0.00% compressed clusters
Image end offset: 30733303808
と返すので問題の VM のみがエラーを吐いているらしい。


解決方法

qemu-img check -h を読んでいると -r オプションがあって、リカバリを試すことができる様子。
Parameters to check subcommand:
  '-r' tries to repair any inconsistencies that are found during the check.
       '-r leaks' repairs only cluster leaks, whereas '-r all' fixes all
       kinds of errors, with a higher risk of choosing the wrong fix or
       hiding corruption that has already occurred.
今回は cluster leak のようなので qemu-img -check r leaks を実行してみた。
どうやら上手くいったようで check してもエラーを返さなくなった。
直したイメージを起動すると ls が返ってきたのでめでたしめでたし。


オチ

これで直ったと思っていたらlsを返さない他のVMを発見。
そしてこいつは qemu-img check でエラーを返さない。
修復した VM の /var/log/messages に、 nfs への書き込みが time out している kernel panic っぽいものを発見。
両方のVMは同じ nfs をマウントしてたので nfs が原因説が濃厚に。
ちなみにある時間から nfs head server がレスポンスを返さない状態になっていたらしい。
おそらく前にもあった案件と同じ原因では無いかと思ってます。
しかし若干の謎があって、nfsをマウントしていたVMは最低限3つある上2つは死んでいたのに1つだけは生きていた。
しかも生きていたVMの mount option に intr は無い。
生きてたVMは書き込していなかった、とすれば辻褄はあうのですがそれはログからは分からなかった。

nfs server 側は私が直接触っていないので余計曖昧な情報ですが、レスポンスを返さない原因は特定のパーティションの容量が一杯だったせいとか。
容量一杯で nfs への書き込みができないのはともかく、それでハングするものなのだろうか。
最終的な対応としては nfs server 側の容量を空けることでおしまい。


ということで qcow2 の cluster leak を直したものの、本来の原因では無かった可能性がある。

2016/12/06

何故 Rails では View から Controller のインスタンス変数にアクセスできるのか

この記事は Okinawa.rb Advent Calendar 2016 6日目の記事です。


はじまり

むかしむかし、あるところでひとりのあっとんさんが Okinawa.rb Advent Calendar のネタをどうるか考えていました。
そこへ @CodeHex さんがあらわれ、ちょっと Rails について質問をしても良いですかと尋ねてきました。

CodeHex さん「Controller で @ を付けた変数は View からアクセスできるんですか?」
あっとんさん「Rails ではそうですね。ちなみに Ruby では @ が付いた変数はインスタンス変数なのです。」
CodeHex さん「なるほど。 Perl では @ があると配列なので違和感がありますね。」

さて、質問された時に Rails ではそういうものだという解答をしたのですがふと思いました。
「別にインスタンス変数だからと言って View から見えるのは関係が無いよね」
そこで調査班は実装を見付けるために Rails へと踏み込むことにしました。


View はどのようにインスタンス変数にアクセスしているのか

まずは View のクラスを確認してみます。
単に Controller を継承しているだけなのかもしれません。
それならこの記事は終わってしまいますがまず確認しないことには始まりません。

ということで Rails のプロジェクトを作ります
$ rails -v # 5.0.01
$ rails new advent2016
$ cd advent2016
$ rails generate scaffold user uid:string
ここで User#index に binding.pry を仕込んで self.class を確認してみます。
[2] pry(#<#<Class:0x007ffdce310d48>>)> self.class
=> #<Class:0x007ffdce310d48>
どうやら特異クラス。さて ancestors を確認してみると
となっていました。
継承しているものに Controller らしきものはパッと見は無いようですね。
調査は続行しそうです。

そこで self を確認していると
とそのまま @_assigns というインスタンス変数があることを発見。あやしいですね。
もちろんこの段階では @users は存在しているので
$ self.instance_eval{@_assigns= nil}
としても @users は変更されません。


@_assign を追いかける

@_assign はどこで変更されるのか。
調査隊はさらに Rails の奥へと踏み込むことを決意します。
$ git grep @_assigns
するとactionview/lib/action_view/base.rb の一つしかありません。
しかもやっていることは instance_variable_set なので怪しさしかありません。
assigns は引数なのでどこかで new されているはず。
次はそれを探します。


ActionView::Base.new はどこだ

まずは素直に git grep します。test もあったので grep -v で除外。
$ git grep ActionView::Base.new | grep -v test
actionpack/lib/action_controller/metal/helpers.rb が引っかかりました。
しかしこいつは module でこれが呼ばれるのを探すのは面倒。
また pry に戻って探してみることにします。

backtrace を覗く

また User#index の binding.pry に戻ります。
User#index の段階では view は用意されてるのでどこかで既に new されているはず。
なのでまず backtrace を眺めてみます。
pry-byebug を入れて pry-backtrace と打つと backtrace が見られます。
さて覗いてみると

多い。111もあります。
折角 byebug で repl も動くことなので up していきます。
途中で String を freeze しているころを見付けます。
噂の物体を副産物で見付けた気分ですね。
どんどん up していきます。
actionview/lib/action_view/renderer/template_renderer.rb の render_with_layout くらいから view という変数がちらほら出てきますね。あやしい。
view は context という名前になったりしながら連れ回されているようです。
actionview/lib/action_view/rendering.rb の _render_template までそれっぽいのがありますが、actionpack/lib/action_controller/metal/streaming.rb の _render_template あたりから出てこなくなります。
この辺りに真相が潜んでいそうです。
というか metal は見覚えがありますね。 ActionView::Base.new しているのも metal の helper でした。


結局どこでインスタンス変数を渡しているのか

最後に view っぽいのを扱っているのは actionview/lib/action_view/rendering.rb の _render_template でした。
context に view_context を代入しています。
view_context の定義に view_assigns という怪しさ満点のものを発見。
しかし rendering.rb に view_assigns は無い。
名前が分かればとりあえず git grep します。
actionpack/lib/abstract_controller/rendering.rb に定義を発見しました。
instance_variables を取ってきてhash にしています。
slice しているのは @ を取りのぞくためですね。
ここでおもしろいのは protected_vars を reject していること。
@_formats などは controller から渡さないようにしているようです。
view_assigns は AbstractController::Rendering に定義されています。
ということは ApplicationController が AbstractController::Rendering を継承していれば、ユーザ定義のコントローラは view_assigns を経由でインスタンス変数を取得して view を生成していそうですね。
となれば気になるのは UsersController の ancestors です。
と AbstractController::Rendering がばっちりありますね。56行目です。
という訳で「何故 View は Controller のインスタンス変数へとアクセスできるのか」を発見できました。
それは「Controller が View を Rendering する時に自分のインスタンス変数を渡してやっているから」です。


view_assigns を上書きするとどうなるか

実装が分かれば遊びたくなるのが常。
自分はきちんとコードが読めたのかも含めてちょっと遊んでみます。
内容は @users という変数を無理矢理作ってやるというもの。
この状態で user#index にアクセスすると DB の中身に関係無く、定義された内容が表示されました。
やはり view に渡すためのインスタンス変数を取得するメソッドは AbstractController::Rendering#view_assign で間違いない様子。
ということで無事 Rails の中からお目当てのものを見付けられました。
めでたしめでたし。


おわり

というおはなしなのでした。
読むのに pry-byebug が便利でした。
むしろ無かったら見付けられなかったかもしれない。
結論としては Controller で view_assigns を上書きすると大変なことになりそう、って感じです。


みなさま良い年末をー。

2016/11/29

Homebrew で Agda 2.5.1.2 を入れる

いつの間にか Homebrew で直接 Agda をインストールできるようになっていたので入れてみたログ。


環境

  • Mac OSX Yosemte 10.10.5
  • Homebrew 1.1.2
  • Homebrew/homebrew-core (git revision a06e; last commit 2016-11-29)
  • GNU Emacs 25.1.1
  • Agda 2.5.1.2


Agda のインストール

Homebrew が直接 formula を提供しているので
  • $ brew install agda
だけでOK。便利。


Agda の設定

  • $ agda-mode setup
するか、その時に表示される
(load-file (let ((coding-system-for-read 'utf-8))
                (shell-command-to-string "agda-mode locate")))
を ~/.emacs や ~/.emacs.d/init.el なりに書いておくとOK。
なんと便利なことに bottle の agda には std-lib が同梱されているので、いきなり open import Relation.Binary.PropositionalEquality とか書いて使うことができます。


特殊文字(Unicode の East Asian Ambiguous) の設定

素の emacs では agda-mode で利用する特殊文字(∏ など)があると表示が乱れます。
これはいくつかの記号の幅が固定されておらず、国によって幅が定義される文字である East Asian Ambigous 文字がソースに含まれる時に発生する問題です。
日本語フォントは基本的に幅2なのですが、英語では幅1らしい。
設定をしないとEmacsが幅を1で処理するため、表示される日本語フォントの幅と合わずに表示が乱れてしまいます。
これを解決する elisp が hamano/locale-eaw に公開されているようなので使ってみます。
README にあるように eaw.el を ~/.emacs/site-lisp に配置して
(add-to-list 'load-path "~/.emacs.d/site-lisp")
(require 'eaw)
(eaw-fullwidth)
を ~/.emacs なり ~/.emacs.d/init.el に書きます。
そうするとEmacs が特殊文字の幅を2として処理してくれます。
ちなみに Terminal や tmux なども East Asian Ambiguous を幅2に設定するのを忘れないように。
過去に自分で書いた elisp もあるのですが割とその場しのぎで書いていたので、これからは eaw.el を使っていこうかなとか。


参考文献

2016/10/07

macOS Sierra にした

気が向いたので Mac OSX Yosemite から macOS Sierra にアップデートしました。

Snow Leopard -> Mountain Lion -> Yosemite のタイミングでクリーンインストールしているので、一つ飛ばしくらいのペースで掃除したくなるようです。


クリーンインストール手順としてはこちらを参考にしました。
Yosemite の時に Time Machine でバックアップを取って、 Sierra にアップデートした後に SSD をフォーマットして再インストール。
フォーマットの際に Case-Sensitive な方を選んだら Yosemite の時は Case-Sensitive じゃなかったようで復元できませんと言われてしまった。
もう一度フォーマットして入れなおし。


Time Machine から復元するのは account と Computer & Network Settings のみ。
/usr/local の下とかを掃除したかったので account の other data は復元せず。
ついでに Application も無しで。そうすると Application 本体は無いけれど入れ直すと設定は残ってたりします。


クリーンインストールした後の環境再構築は Homebrew を入れただけ。
使っていた Formula は Brewfile にまとめていたので brew bundle しておしまい。
私が Brewfile を書いた時とフォーマットが変わっていた + bundle コマンドが分離されて Brewdle になっていたのでそこだけ変更したくらい。
Application もほとんど Cask で入れていたので brew bundle でまとめて入れてしまう。


ちょっと気になった点としては
zsh を起動した時に

Ignore insecure directories and continue [y] or abort compinit [n]?
と出てくる。
compinit でロードされるディレクトリのパーミッションが怪しいと出るようです。具体的には group に write がたってた。
compinit した時に指摘されたディレクトリを chmod g-w して解決。


という感じでそんなに変なこともなく移行完了。
130G くらい空いてすっきり。
今のところ Sierra の評判はそんなに良くないのだけれどどうなるかな。

2016/09/29

Implementing a JIT Compiled Language with Haskell and LLVM を chapter 3 までやってみた

Haskell + LLVM で言語を作ってみる Implementing a JIT Compiled Language with Haskell and LLVM というページがあったのでちょっとやってみました。
LLVM-IR を吐くところまでは動いたのでそのメモ。
作成した repository は github の atton-/kaleidoscope にあります。


ページに書かれているコードを写経していたら chapter 3 くらいから問題発生。
Webに書かれていることを写経してもコンパイルが通らない。
本家のコードを chapter 2 で定義した Syntaxchapter 3 で定義された Syntax は違うようです。
他にもWebには書かれていない関数があったりしたので、エラーが出たら本家のコードを見つつ chapter 3 の Code Generation までは書けました。

ここで追加で問題発生。 llvm-general を ghci から使おうとすると

<interactive>: /usr/lib/llvm-3.5/lib/libLLVMSupport.a: unhandled ELF relocation(RelA) type 42

と出て動かない。
OSX 10.10.5 / Ubuntu 16.04 / Fedora 23 / Fedora24  on Docker で動かしたり stack を使ったりしたが解決せず。
ちなみに OSX では
lookupSymbol failed in relocateSection (RELOC_GOT)
/usr/local/Cellar/llvm35/3.5.1/lib/llvm-3.5/lib/libLLVMProfileData.a: unknown symbol `___dso_handle'
と出て動かなかったです。

https://github.com/DanielG/ghc-mod/issues/762 とかを参考にしながら
--ghc-options="-opta-Wa,-mrelax-relocations=no"
を付けて cabal で install したり stack の stack.yaml に書いたりしましたが動かず。
最終的に ghci では動かないけれど ghc では動きました。どうも良く分からない……
Fedora 23 on Docker で動かした時の Dockerfile はこれです。
一応 Ubuntu 16.04 でも ghc でなら動いたはずです。


Haskell の環境構築とかデバッグとかのノウハウの不足を感じる。
環境構築で結構力尽きた感も若干あるけれどどこまで続くかな。

2016/08/31

FFBT67M/EB を買った

Majestouch MINILA Air US67キー 茶軸(FFBT67M/EB) を買いました。外付けキーボードですね。

普段は MacBookPro のキーボードを使っているのですが、ある時左手首が痛くなる。
何もしてなければ大丈夫なのですがキーボードを使ったり捻ると痛い。
一週間くらい経っても治らないので人に聞いたり調べてみたりする。
なので病院で診察されたわけでは無いのですがどうやら腱鞘炎。
腱鞘炎は薬とかでぽんと治る類いのものでは無いらしく、病院に行っても湿布を貰っておしまいだとか。
普段から気をつけて直すタイプの病気とのことなので、作業時の姿勢を気にしてみることに。

具体的には机とモニタとキーボードの高さ。
手首を痛めた時は机が高く、椅子に座っている時に肘の角度がが90度よりも小さい状態。
メインモニタは MacBookPro のモニタで、サブとして右側に外付けのディスプレイを使っていました。
まずモニタを目の高さにするためにメインモニタをディスプレイに変更。 MacBookPro を右側に置くようにしました。
キーボードは肘の高さくらいになるように机の高さを変更。これで直角になる
ちなみに正しい姿勢の情報源はヘルシープログラマだったかな。

一応効果はあったようで、2週間もするとキーボードを使い続けても痛みは再発しないようになりました。



ちなみにキーボードの選定理由ですが他の人と被らないようにした結果です。
Happy Hacking Keyboard と RealForce はユーザが周りにいたのでそれ以外にしてみようかな、と。
Twitter で黒軸とか赤軸とかがあるのは知っていたのでその辺りを探しに行ってみる。
秋葉原のツクモで 黒/赤/茶/青 軸を試しに打てるコーナーがあって、試してみて一番しっくりきたのが茶軸だったので茶軸を購入。
ちなみに茶軸にしようか赤軸にしようか迷ってました。両方とも軽いので。
黒軸がとても重くて何故長時間使う人向けなのか分からなかった。疲れないのかな。
テンキーはいらないのでUS67キー版を買う。USなのはスパルタンVimとかの影響ですね。

有効にしている DIP スイッチは 2 と 5 です。
control を a の左に持ってきたいので ctrl と caps を交換。
FFBT67M/EB では Esc と ~/` が同じキーで、どちらかは Fn を押しながらでないと入力できない。
普段使いが多いのは ~/` なので Fn を押しながらでないと入力できないように。
vim でも ^[ 派なのであまり困ってないです。
DIP でキー入れ替えした時用にキートップを変えられるようになってるのは良いですね。

使ってみた感想としてはそんなに大きな感想は無し。
タカタカ打ってるのが楽しいくらいかな。
自分がキーボードにそんなにこだわりを持っていないのが分かりました。
Win/Alt/App キーは Mac のキーのどれに対応してるか慣れるのに時間がかかったので次買うなら Apple 純正のやつでも良いかもしれない。

2016/07/13

オープンソースカンファレンス沖縄2016へ行ってきた

2016/07/02(Sat) にオープンソースカンファレンス沖縄2016 へ行ってきました。

OSC沖縄に行くのは三度目でしょうか。
今回もブース展示の手伝いのような参加でした。

今回のブース展示は研究室でやってること+IGDA琉球大学でやってること、でした。
研究室のパネルは画面配信システム TreeVNC と 分散ネットワークフレームワークAlice、独自言語 Continuation based C とそれで実装しようとしているOS Gears OS をまとめたもの。
もう1つのパネルはIGDA 琉球大学でやってることとして Unity で過去に作ったゲームをまとめたもの。

聞いた発表としては Hadoop と Sparkのお話
Hadoop といえば MapReduce という印象でしたが YARN が登場したことで MapReduce 以外の計算もできるみたいですね。派生も大量。
YARN自体は分散されてなく単体で管理してて、リソースのノードを追加するとどんどん容量が増えるように見えるとのこと。
あと HDFS はファイルを三重に保存するらしいのですが、ペタオーダーで三倍になってしまうのは物理的につらいので、これからは45%くらいを分散して配置して容量を節約しよう、みたいな流れがあるとか(具体的なパーセント忘れた)。
Spark は REPL もあるし cluster に入らなくても local で環境を上げてくれたり、通信を減らすために可能な計算はまとめてくれたり、メモリに計算結果をキャッシュできたりと便利お手軽なようです。
なんだかんだ Hadoop は触ったこと無いので始めて聞く話が多かったです。良い入門話だった。
過去の発表のスライドは slideshare に公開しているとのことでしたがこのブログ記事を書いた時点ではOSCのスライドは無かったです。

ブースのお隣りさんは MyDNS の方でした。
MyDNS が個人サービスなのは知らなかった。
ユーザからのIPv4の申告をDBに入れて DNS を提供してる、らしいです。
バックエンドが DB の DNS をメンテしてたりする身としてはあるある話が多かったです。
IPv6 の逆引きを用意しろといった Google の意向には逆らえないとか。
FreeRADIUS で何か踏んだことがあるとか。
ちなみに MyDNS では PowerDNS を使ってるらしいです。
あとIPv4は3万件とかあって年々増え続けてるけれど IPv6 のレコードは3千件程度だとか。
まだ v6 の普及は遠いのかな。

懇親会はビーチパーティー。
会場の撤去を手伝った結果ダウンして早期撤退しました。

今年のアンケートくじ引きとじゃんけんは何も当たらず。残念。

2016/06/26

ハッカーズチャンプルー2016 に行ってきた

2016/06/25(Sat) に ハッカーズチャンプルー2016 に行ってきました。

カンファレンスの部懇親会に参加。
なんだかんだ4年連続で参加していますね。時が経つのは早い。


カンファレンスは Go と Perl 成分が多かった感触。
Mackerel や Infrastructure as a Code の話は「おー所謂モダンな開発って感じかねー」とか思いながら聞いてた。
最近 Go の話を良く聞きますね。 okinawa-go とか。
@CodeHex さんの LT では「Go を始めて触ったけれどここがわかんない」という声も。
分からない部分をきちんと共有するのは重要だと思います。
一番印象に残っている発表は負荷分散の話。
DBの水平分散時にサーバを倍々で増やしていくのはいろいろと都合が良さそう。
キャッシュの話も聞きたかった。
実際巨大なキャッシュや分散が必要になる規模はどのくらいなのだろうか。


懇親会は @tompng さんの minecraft で computer を作った話のインパクトが強力でした。
minecraft やったこと無いですけれど、フラクタルを計算して3Dプリントできるらしい。
なにそれ聞いたことある話と違う、といった感じ。
2時間あっという間でご飯食べる暇がほとんどなかったくらいでした。
今までの懇親会で一番人と話した気がします。
あとおもしろTシャツは印象に残りやすいですし話かけやすくて良いですね。
次は何かおもしろTシャツ着ていこうかな。
学生料金は非常にうれしかったです。ありがとうございました。
それもあってかカンファレンスも懇親会もちらほら学生を見た気がする。
場所がKBCだったことも関係あったりするのかな。


来年はどうなりますかねー。
今年も運営の方々お疲れさまでした + ありがとうございました。

2016/05/22

akatsuki 読み会をした

2016/05/15(Sun) に akatsuki 読み会を開催しました。

akatsuki とは私の所属する琉球大学情報工学科で運用しているユーザ用 Web コンソールです。
IP/VMの申請や作成といった学科のシステム運用に必要な様々な機能が入っている Rails Application です。
2015/09 辺りに学科サーバの更新があり、それに伴い学科新システムの一部として開発しました。
学科のユーザ向けの説明会の資料はこちら
特定の人々向けなのでかなり情報を省いています。
なお、この記事を書いている段階ではソースが学科内限定公開になっています。


読み会について

読み会を行なったのは主に後輩への引き継ぎのためです。
akatsuki の機能は学科向けの機能も多く、学科システムを把握しておかないとメンテナンスがつらいかなという懸念もあったので、各機能の実装箇所の概観を把握のために読み会を開催しました。
システム管理するメンバー向け資料はこちら。さらに情報が省かれています。


この記事について

読み会の補足用です。やっぱり特定の人用になっています。
実は akatsuki で使っているノウハウを切り出してこのブログにまとめていて、


勝手にFAQ

  • どうして名前が akatsuki なの?
    • システム管理チームのメンバーのイニシャルをまとめると作れたから。
    • 名付けの時にいた人達の趣味であるという説もある。一人前のレディ的な。
  • デザインは?
    • ちゃんと bootstrap 当ててるじゃないですか。
    • それはさておきデザイン担当の人がいたのでその人が当ててくれるかも。
  • LocalRecord ってなに? Localしか無くない?
    • 元は外向けのDNSも akatsuki で管理しようかという考えもあったので
    • GlobalRecord とか SakuraRecord とか作るつもりだった名残です。
  • さくらクラウドの管理は?
    • fog-sakuracloud とかあるのでその辺でどうにかなるかも

まとめ

ということで特定の人達向けの資料を充実させるための記事でした。

2016/05/04

Agda 2.5.1 でライブラリのパスを設定する

Agda のバージョンを上げたらライブラリのパスの指定方法が変わったらしいので再設定したログ。


環境

  • Mac OSX Yosemite 10.10.5
  • GHC 7.10.3
  • cabal-install 1.22.9.0
  • Agda 2.5.1
  • agda-stdlib 0.12.0 (84ad2bf993e8256e8989f5466c0db0817473b2d6)


設定方法

前までは init.el 辺りで agda2-include-dirs に library の path を list で設定する方法だったのですが、 2.5.1 からは agda2-program-args に入れるか library mamangement を使えとのこと

library management は特定のフォーマットでライブラリのパスや依存が書けるものらしいですが、使ってるライブラリもそんなに無いので agda2-program-args を指定する方法でやってみます。
-iDIR か -lLIB 辺りのフォーマットにして設定しろとのことです。

私は使うライブラリを ~/Library/Agda2 の下に symlink を貼る形にしてるので、 ~/Library/Agda2/* を展開してフルパスにして -i を付けて設定してます。

具体的にはこんな感じ。
(setq agda2-program-args (mapcar (lambda (path) (concat "-i" (expand-file-name path))) (file-expand-wildcards "~/library/Agda2/*")))
ちなみに前まではこんな感じ。
(setq agda2-include-dirs (mapcar (lambda (path) (expand-file-name path)) (file-expand-wildcards "~/Library/Agda2/*")))
(add-to-list 'agda2-include-dirs ".")
設定したら無事動いてめでたしめでたし。


参考

2016/04/30

NFS と intr オプション

CentOS 7 で NFS を mount しているとたまに kernel がハングする時があったのでそのログとか対処法とか。


環境


  • CentOS : 7.1.1503
  • kernel : 3.10.0-327.4.5.el7.x86_64 (だったと思う)
  • nfs-utils : 1.3.0-0.21.el7.x86_64


状況

/var/log/messages を見ると
hogehoge kernel: nfs: server 10.20.30.40 not responding, still tryinghogehoge kernel: nfs: server 10.20.30.40 not responding, timed out
とか出てる。どうやら nfs までのネットワークか nfs 本体が不安定な時があるらしい。

最悪の場合のログがこれ。 ssh すらできなくなる。
INFO: task kworker/u289:1:113889 blocked for more than 120 seconds.
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
kworker/u289:1  D ffff885eff613680     0 113889      2 0x00000080
Workqueue: writeback bdi_writeback_workfn (flush-0:36)
ffff885c819e7c88 0000000000000046 ffff885e59db0000 ffff885c819e7fd8
ffff885c819e7fd8 ffff885c819e7fd8 ffff885e59db0000 ffff885ca53efd90
ffff88607ff66220 0000000000000080 0000000000000000 ffff885e64f15268
Call Trace:
[<ffffffff816098d9>] schedule+0x29/0x70
[<ffffffff811f066a>] inode_sleep_on_writeback+0x9a/0xd0
[<ffffffff81098240>] ? wake_up_bit+0x30/0x30
[<ffffffff811f1aa0>] wb_writeback+0x170/0x2f0
[<ffffffff811f31cb>] bdi_writeback_workfn+0x2cb/0x460
[<ffffffff8108f0cb>] process_one_work+0x17b/0x470
[<ffffffff8108fe9b>] worker_thread+0x11b/0x400
[<ffffffff8108fd80>] ? rescuer_thread+0x400/0x400
[<ffffffff8109727f>] kthread+0xcf/0xe0
[<ffffffff810971b0>] ? kthread_create_on_node+0x140/0x140
[<ffffffff81614358>] ret_from_fork+0x58/0x90
[<ffffffff810971b0>] ? kthread_create_on_node+0x140/0x140
INFO: task scp:114899 blocked for more than 120 seconds.
"echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
scp             D ffff885eff533680     0 114899      1 0x00000080
ffff885d75dafb78 0000000000000082 ffff88bce8d14fa0 ffff885d75daffd8
ffff885d75daffd8 ffff885d75daffd8 ffff88bce8d14fa0 ffff885eff533f48
ffff88607ff624e8 0000000000000002 ffffffff811562e0 ffff885d75dafbf0
Call Trace:
[<ffffffff811562e0>] ? wait_on_page_read+0x60/0x60
[<ffffffff81609bdd>] io_schedule+0x9d/0x130
[<ffffffff811562ee>] sleep_on_page+0xe/0x20
[<ffffffff816079b0>] __wait_on_bit+0x60/0x90
[<ffffffff81156076>] wait_on_page_bit+0x86/0xb0
[<ffffffff81098280>] ? autoremove_wake_function+0x40/0x40
[<ffffffff811561b1>] filemap_fdatawait_range+0x111/0x1b0
[<ffffffff81156277>] filemap_fdatawait+0x27/0x30
[<ffffffff811f0568>] __writeback_single_inode+0x1b8/0x220
[<ffffffff811f1467>] writeback_single_inode+0xe7/0x1b0
[<ffffffff811f156e>] sync_inode+0x3e/0x60
[<ffffffffa06ea1bc>] nfs_wb_all+0x5c/0x100 [nfs]
[<ffffffffa06df410>] nfs_setattr+0x1e0/0x1f0 [nfs]
[<ffffffff811e3739>] notify_change+0x279/0x3d0
[<ffffffff811c4b13>] do_truncate+0x73/0xc0
[<ffffffff811c9168>] ? __sb_start_write+0x58/0x110
[<ffffffff811c4ea4>] do_sys_ftruncate.constprop.17+0x114/0x170
[<ffffffff811c4f3e>] SyS_ftruncate+0xe/0x10
[<ffffffff81614409>] system_call_fastpath+0x16/0x1b
/home を nfs の上に置いてるからかもしれないけれど何もできなくなるので、だいたい再起動することになる。
負荷が高い時に発生するのかと思って再現させようとしても耐える時は耐える。
特に私が見てない時に他の人が使って止まってしまったことがほとんどなので、原因も対処方も若干憶測が入ってるのがちょっとつらい。


対処

クライアント側で intr オプション付けると良さそう。 mount コマンドなら
$ mount --verbose -t nfs -o intr 10.20.30.40:/path/to/mount-target /path/to/mount-point
とか。 /etc/fstab だと hard/soft の部分を hard,intr にする。
nfs のマウントには soft と hard の二種類があって、soft は NFS サーバが応答しなくなった時にエラーを返すらしい。
でも帰ってきたエラーをアプリケーション側が上手くハンドルしないとファイル壊れちゃうので hard が推奨。
hard はサーバが応答しなくなっても待ち続ける。soft のようにファイルが壊れることもないらしいし、一時的にサーバが落ちても大丈夫なのでNFSサーバの再起動とかしても問題無い。
けれど待ち続けてる間で kernel task が 120 秒とかを越えると kernel panic しちゃうみたい。
hard を付けた状態で panic するんじゃなくて kernel が task を止められるように intr を付けておくと panic しなくなった。
設定後4ヶ月くらい様子を見ているけれど再現はしていないっぽい。


まとめ

NFS の mount option に hard を指定する場合は intr も一緒に付けておいた方が良さそう。


参考