「device is busy」でアンマウントできない時の対処

「device is busy」でアンマウントできない時の対処

「device is busy」とは何が起きているのか?

結論: アンマウント対象のファイルシステムを、まだ誰か(プロセス・別マウント・swap 等)が使っている状態。カーネルが EBUSY を返して umount を拒否している。外す前に「何が掴んでいるか」を特定するのが先決。

umount が次のように弾かれる典型。

umount: /mnt/data: target is busy.

古いディストリや一部ツールでは同じ状態が device is busy / device or resource busyerrnoEBUSY)として現れる。メッセージは違っても原因は同じで、対象を参照しているものが残っている。

掴んでいる主体は大きく次の系統に分かれる。切り分けの優先順位もこの順。

  • A. プロセスがファイルを開いている(最頻)— マウント配下のファイルを開いたまま / 実行中バイナリ / ログ書き込み中
  • B. カレントディレクトリがマウント内— シェルや常駐プロセスの cwd が /mnt/data 配下にある
  • C. マウントが入れ子— その上に bind マウントや overlay が重なっている
  • D. swap / loop など別用途で使用中— 対象デバイスを swap や loop デバイスとして使っている

device is busyRead-only file system は別物。前者は「使用中で外せない」、後者は「書き込み禁止状態」。エラー文を取り違えると対処を誤る。read-only については 「Read-only file system」の対処 を参照。

誰が掴んでいるかを特定するには?

結論: まず fuser -vm <マウントポイント> で「そのファイルシステムを使う全プロセス」を一覧する。ACCESS 列で開いているファイル(f)・カレントディレクトリ(c)・実行中(e)・mmap(m) を区別できる。補完として lsof を使う。

fuser でマウント単位に洗い出す

-m はマウントポイント(またはブロックデバイス)を指定し、そのファイルシステムを利用する全プロセスを返す。-v で詳細表示。

fuser -vm /mnt/data
                     USER        PID ACCESS COMMAND
/mnt/data:           root     kernel mount /mnt/data
                     alice       2314 ..c.. bash
                     alice       2890 F.... tail

ACCESS 列の意味を読む。これが「なぜ busy か」の直接の答えになる。

  • c … そのプロセスの カレントディレクトリ がマウント配下(→ B のパターン)
  • e … マウント配下のバイナリを 実行中
  • f … ファイルを オープン中(大文字 F は書き込みオープン)
  • r … ルートディレクトリとして使用
  • m … ファイルを mmap(共有ライブラリ等)

上の例なら、bash(cwd が中)と tail(ファイルを開いている)が原因。

lsof で個別ファイルまで追う

どのファイルを掴んでいるか具体的に知りたいときは lsof。マウントポイント配下を再帰的に見るなら +D、デバイス単位なら +f --

# マウントポイント配下で開かれているファイル一覧
lsof +D /mnt/data

# ブロックデバイス単位で見る(マウントポイントが既に壊れている場合に有効)
lsof +f -- /dev/sdb1

lsof +D はツリー全体を stat するため大きなディレクトリでは遅い。素早く原因を掴むなら fuser -vm を先に、詳細確認に lsof を使うのが実務的。

掴んでいるプロセスを止めて外すには?

結論: まず原因プロセスを 正常終了(cd で抜ける / サービス停止 / TERM)させてから umount。それでも残るなら fuser -k で強制終了するが、SIGKILL はデータ損失リスクがあるので最後の手段。

1. 安全な順序:自分で抜ける・止める

  • 自分のシェルの cwd が中にあるだけなら、まず外に出る。
cd /
  • サービスが掴んでいるなら、そのサービスを止める(kill より確実で安全)。
sudo systemctl stop myapp.service
  • 個別プロセスは PID を確認して穏当なシグナルから。
kill 2890        # SIGTERM(後始末の余地を与える)

2. 最後の手段:fuser -k で一括終了

正常終了で抜けないプロセスは fuser -k でまとめて殺せる。ただし -k は既定で SIGKILL を送るため、書き込み中なら破損し得る。

# 中身を確認してから(-i で対話確認)
sudo fuser -kim /mnt/data
/mnt/data:            2890c  2314c
Kill process 2890 ? (y/N) y
  • -k … 利用プロセスにシグナル送信(既定 SIGKILL)
  • -i … 1 件ずつ確認(事故防止に強く推奨)
  • -m … マウント単位

プロセスを片付けたら再度 umount する。

sudo umount /mnt/data

それでも外れない:lazy / force umount は使ってよいか?

結論: 即座にツリーから切り離したいなら umount -l(lazy)。応答しない NFS には umount -f(force)。どちらも「掴んでいる側を解決しない」回避策なので、原因を放置したまま常用しないこと。

lazy umount(-l

ファイルシステムを 今すぐツリーから外し、参照が消え次第クリーンアップする。掴んでいるプロセスを落とせない/落としたくない場合の緊急避難。

sudo umount -l /mnt/data

注意点:

  • マウントポイントは見えなくなるが、開いていた FD は生きたまま(プロセスは古いファイルを掴み続ける)。完全な解放はプロセス終了後。
  • 同じデバイスをすぐ再マウントすると、裏で残った参照と競合することがある。
  • 未書き込みデータのフラッシュ完了を保証しない。重要 FS では原因解決を優先する。

force umount(-f

主に 応答しない NFS 向け。サーバがダウンしてハングした NFS マウントを強制的に切り離す。

sudo umount -f /mnt/nfs

ローカルの ext4/xfs では -f はあまり効かない(busy の原因がローカルプロセスなので)。NFS のハングは 「Stale file handle」の対処 も併読。

プロセスが見当たらないのに busy なときは?

結論: fuser / lsof に何も出ないのに busy なら、原因は「プロセスの開いたファイル」以外。入れ子マウント・swap・loop デバイス・NFS エクスポートの 4 つを順に疑う。

1. 入れ子マウント(bind / overlay)を確認

対象の 上にさらに別マウント が乗っていると busy になる。findmnt -R でツリーを見て、子マウントから順に外す。

findmnt -R /mnt/data
TARGET            SOURCE    FSTYPE OPTIONS
/mnt/data         /dev/sdb1 ext4   rw,relatime
└─/mnt/data/cache tmpfs     tmpfs  rw

この場合は子の /mnt/data/cache を先に umount する。Docker の overlay や mount --bind でよく起きる。

2. swap として使われていないか

対象パーティションを swap に使っていると当然外せない。swapon --show で確認し、swapoff する。

swapon --show
sudo swapoff /dev/sdb2

3. loop デバイスが掴んでいないか

イメージファイルを loop マウントしている場合、loop デバイス経由の参照が残る。losetup -a で確認して解放する。

losetup -a
sudo losetup -d /dev/loop0

4. NFS でエクスポート中でないか

そのファイルシステムを NFS サーバとしてエクスポートしていると busy になる。exportfs で解除する。

sudo exportfs -ua          # 全エクスポート一時解除

最短フロー: ① fuser -vm /mnt/data で誰が掴むか確認 → ② 正常終了(cd / systemctl stop / kill)→ ③ 再 umount → 残れば ④ findmnt -Rswapon --showlosetup -a で非プロセス要因を確認 → ⑤ 緊急時のみ umount -l。原因特定を飛ばさないのが事故防止の唯一の鍵。

まとめ / 次に読む