nfs が umount できなかった。kill できないプロセスができちゃった。

えー結論からすると nfs を使ってるときには以下の3点に注意。

1. nfs client 側で umount せずに nfs server が動いているマシンを停止させない。
2. 上記状態になってしまったときに df -k など mount された状態を前提としたコマンドを実行させない。
3. 実行してしまって STAT が D の状態になってしまったプロセスが生まれてしまったらリブートしか解決方法はない。

です。では、何故こんな状態になってしまったか、ポカミスについて備忘録として情報公開です。

- スポンサーリンク -

まず一番の原因として nfs client の接続を切らずに nfs server が動いているサーバを停止しちゃいました。これが前日にやったこと。バッチ処理で df -k の実行が走りました。

la-day.png

この通りロードアベレージが急上昇しました。df -k によって本来 mount されている nfs server 上のマウントポイントにアクセスできないので、df -k が disk sleep 状態に陥ります。ps aux でみるとこんな感じ。

[root@dev000 root]# ps aux
USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND
・・・
root     19242  0.0  0.0 35040  628 ?        D    04:02   0:00 df -h
・・・

プロセスの状態が ”D” つまり割り込み不可のスリープ状態になってしまっています。/proc/プロセスID/status で詳細状態を確認できます。

[root@dev000 root]# cat /proc/19242/status
Name:   df
State:  D (disk sleep)
Tgid:   19242
Pid:    19242
PPid:   19241
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 256
Groups: 0 1 2 3 4 6 10 
VmSize:    35040 kB
VmLck:         0 kB
VmRSS:       628 kB
VmData:      160 kB
VmStk:        32 kB
VmExe:        32 kB
VmLib:      2368 kB
SigPnd: 0000000000000100
ShdPnd: 0000000000000100
SigBlk: fffffffffffffeff
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 00000000fffffeff
CapEff: 00000000fffffeff

STAT が D のプロセスはどうやっても kill できません。というか kill シグナルすら受け取れません。結果 I/O 待ち状態のプロセスになります。ロードアベレージの計算上、実際には全然負荷がかかっていない状態にもかかわらず、ロードアベレージがぐーんと上がった状態になります。これは精神上良くない。

なんてことを調べる前に fuser を実行してファイルやソケットを使用しているプロセスを特定しようとしたら更にプロセスがささってしまう。その時点でロードアベレージは計算上更にあがることに・・・なので2段階に上昇になっています。

[root@dev000 root]# ps aux
USER       PID %CPU %MEM   VSZ  RSS TTY      STAT START   TIME COMMAND
・・・
root     13569  0.0  0.0 41184 1580 ?        D    11:34   0:00 -bash
root     15465  0.0  0.0 35028  448 ?        D    11:42   0:00 fuser -v /mnt/dev001
・・・

[root@dev000 root]# cat /proc/15465/status
Name:   fuser
State:  D (disk sleep)
Tgid:   15465
Pid:    15465
PPid:   1
TracerPid:      0
Uid:    0       0       0       0
Gid:    0       0       0       0
FDSize: 256
Groups: 0 1 2 3 4 6 10 
VmSize:    35028 kB
VmLck:         0 kB
VmRSS:       448 kB
VmData:      156 kB
VmStk:        36 kB
VmExe:        20 kB
VmLib:      2368 kB
SigPnd: 0000000000000100
ShdPnd: 0000000000020103
SigBlk: fffffffffffffeff
SigIgn: 0000000000000000
SigCgt: 0000000000000000
CapInh: 0000000000000000
CapPrm: 00000000fffffeff
CapEff: 00000000fffffeff

結局、割り込み不可のスリープ状態のプロセスを正常な状態に戻すにはサーバのリブートしか選択肢はありませんでした。

リブートする前に、あれこれ試してみました。

まず umount について。nfs client 側で umount せずに nfs server が動いているマシンを停止すると umount -f も効かない。

umount -f /mnt/dev001

Cannot MOUNTPROG RPC: RPC: ポートマッパーの失敗です - RPC: 受け取れません
umount2: デバイスもしくはリソースがビジー状態です
umount: /mnt/dev001: デバイスを使用中です

[root@dev000 root]# mount
/dev/sda2 on / type ext3 (rw)
none on /proc type proc (rw)
none on /dev/pts type devpts (rw,gid=5,mode=620)
usbdevfs on /proc/bus/usb type usbdevfs (rw)
/dev/sda1 on /boot type ext3 (rw)
none on /dev/shm type tmpfs (rw)
devweb:/usr/local/src/share on /mnt/dev001 type nfs 

どうやらこんな時には umount -l が有効のようです。エラーは出力されるものの、一応 umount されるみたい。

umount -l /mnt/dev001

[root@dev000 root]# umount -l /mnt/dev001
Cannot MOUNTPROG RPC: RPC: ポートマッパーの失敗です - RPC: タイムアウトしました

[root@dev000 root]# mount
/dev/sda2 on / type ext3 (rw)
none on /proc type proc (rw)
none on /dev/pts type devpts (rw,gid=5,mode=620)
usbdevfs on /proc/bus/usb type usbdevfs (rw)
/dev/sda1 on /boot type ext3 (rw)
none on /dev/shm type tmpfs (rw)

linux を長年扱ってきましたが、こんなポカミスをしてしまったのは初めてなので STAT が D で刺さってしまったときの対応について初めて学習しました。もう一度(自分に対して)言いますが nfs を使っている場合の注意点。

1. nfs client 側で umount せずに nfs server が動いているマシンを停止させない。
2. 上記状態になってしまったときに df -k など mount された状態を前提としたコマンドを実行させない。
3. 実行してしまって STAT が D の状態になってしまったプロセスが生まれてしまったらリブートしか解決方法はない。

- スポンサーリンク -