orchestrator: NBDProvider.Close() syncs device before disconnecting, causing spurious EIO on sandbox cleanup after VM crash
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 75/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 静か
- 技術スタック
- go
調査の方向性
packages/orchestrator/pkg/sandbox/rootfs/nbd.go から始め、NBDProvider.Close() と sync() に注目してください。VM のクラッシュ後のクリーンアップ動作を確認します。sync() の EIO は WARN としてログに記録し、クリーンアップエラーとして伝播させない一方で、その他の sync エラーは引き続き伝播させる必要があります。
索引モデルが issue の本文から書いたものです。
説明
Describe the bug
When a Firecracker VM exits abnormally (OOM-kill, crash, etc.), NBDProvider.Close() in packages/orchestrator/pkg/sandbox/rootfs/nbd.go calls sync() before mnt.Close(). Because the NBD device is already in an error state after the VM dies, the ioctl(BLKFLSBUF) + fsync inside sync() returns EIO. This causes every sandbox cleanup after an abnormal VM exit to log:
failed to cleanup sandbox: error flushing cow device: failed to fsync path: input/output error
even though no data loss has occurred — the error is an expected consequence of the VM being dead, not a real storage failure.
Root cause
NBDProvider.Close() (line 130 of rootfs/nbd.go):
func (o *NBDProvider) Close(ctx context.Context) error {
var errs []error
err := o.sync(ctx) // ← calls BLKFLSBUF ioctl + fsync on /dev/nbdX
if err != nil {
errs = append(errs, fmt.Errorf("error flushing cow device: %w", err))
}
err = o.mnt.Close(ctx) // ← disconnects the NBD device (too late)
...
}
sync() (line 162) opens /dev/nbdX, issues BLKFLSBUF, then calls flush() which does syscall.Fsync. When the VM has already crashed, the NBD device is in error state and Fsync returns syscall.EIO. The error propagates up through Sandbox.Close() → setupSandboxLifecycle() which logs it at ERROR level.
Expected behavior
EIO from sync() during sandbox cleanup should be treated as an expected condition (VM died, no data to flush) and logged at WARN level rather than propagating as an error that triggers the "failed to cleanup sandbox" ERROR log.
Impact
- Spurious
"failed to cleanup sandbox"ERROR log on every abnormal VM exit - Noise in production alerting / on-call signals
Suggested fix
In NBDProvider.Close(), detect syscall.EIO from sync() and downgrade to a warning:
err := o.sync(ctx)
if err != nil {
if errors.Is(err, syscall.EIO) {
logger.L().Warn(ctx, "error flushing cow device (VM likely crashed, ignoring)", zap.Error(err))
} else {
errs = append(errs, fmt.Errorf("error flushing cow device: %w", err))
}
}
Environment
- Bare-metal deployment with Nomad
- Observed under high sandbox creation load (thundering herd from client retries)
- 主要言語
- Go
- スター
- 1.6k
- フォーク
- 438
- PR マージ指標
- 30日以内にマージされた PR はありません
環境構築
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
e2b-dev/runtime のほかの issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
sandbox cache: StartRemoving state transition not broadcast, all allocations see stale Running stateオープン
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
メンテナーはふだん 1 日以内に返信
-
難易度 1/5 1時間未満 初心者へのやさしさ 86/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
e2b-dev/runtime の issue をすべて見る
似ている issue
-
area/proxy kind/bug priority/backlog triage/accepted
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
lexfrei/cloudflare-tunnel-gateway-controller#840 ·
メンテナーはふだん 1 日以内に返信
-
area:chat bug sev:papercut
難易度 2/5 1〜3時間 初心者へのやさしさ 86/100
Agent-Field/CodeAF#1592 ·
メンテナーはふだん 1 日以内に返信
-
kind/bug
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
メンテナーはふだん 7 日以内に返信
-
bug needs triage
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
メンテナーはふだん 1 日以内に返信
-
bug P2 reliability
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
afreidah/s3-orchestrator#1564 ·
メンテナーはふだん 1 日以内に返信