如何確保在卸載檔案系統之前殺死所有進程?

如何確保在卸載檔案系統之前殺死所有進程?

我正在嘗試卸載一個繁忙的檔案系統,該檔案系統上的多執行緒程式正在發生連續的 I/O 讀取和寫入,因此 umount 命令失敗。

root@ubuntu:~ # umount /mount/v1
umount: /mount/v1: target is busy.
        (In some cases useful info about processes that use
         the device is found by lsof(8) or fuser(1))

現在,我嘗試使用以下命令終止所有進程

/sbin/fuser -m /mount/v1 -k

但根據定影命令

fusionr -k 或 -K 可能無法偵測並終止程式開始運行後立即建立的新進程。

這就是我的情況,因為某些線程可能同時發出 IO 請求。當我再次卸載檔案系統時,它再次說它正忙,這變成了一個循環。

我的問題是,如何確保沒有新進程能夠對檔案系統進行一次讀取/寫入操作

/sbin/fuser -m /mount/v1 -k

發出命令以便可以正常卸載檔案系統。

答案1

這裡有兩種方法,如果您不信任您的應用程序,可以直接轉到第二種方法。

1.umount --lazy

如果那些幹擾進程沒有chdir())進入安裝點(例如使用絕對路徑)並且您知道它們最終會放棄,那麼在 Linux 上您可以使用umount --lazy:核心將從目錄樹狀結構中取消檔案系統的映射,使其無法存取新的訪問並在最後一個引用消失時自動卸載它。引用可以是打開的 fd、一個 cwd、一個內部掛載點(最後一個可能會很糟糕)...

但這不會影響進程/線程將引用保留在“內部”,例如仍然打開文件描述符或具有西德裡面。那麼這將變得更加困難,因為現在檔案系統不再可訪問,並且追蹤違規進程/執行緒變得更加困難(例如:fuser -m將不再找到它們)。因此,您需要進程才能正確執行此方法。

2.冷凍機組

應該適用的替代解決方案行為不好進程:將所有這些進程(和執行緒)分組到同一個冷凍機 cgroup 中。將它們全部凍結,防止它們將資源使用添加到掛載點(通過分叉/克隆/打開新的 fd)。即使您在第一次循環中錯過了一些,您最終也會在後續迭代中捕獲所有新內容。由於它們現在已被凍結,因此不會發生新的活動:您現在可以將它們全部殺死。對於 cgroups v1,已經由作業系統初始化(例如:透過系統或者CG經理,否則你必須弄清楚如何安裝 freeze cgroup 子系統),這樣的東西應該​​有效。請注意,顯然寫入cgroup.procs應該包括應該出現的所有線程,tasks但有不可靠行為的報告,所以以防萬一我也迭代線程,即使這可能不需要(即:tasks可能已經正確填充了線程,所以循環for t是多餘的)。

mkdir -p /sys/fs/cgroup/freezer/prepareumount

echo FROZEN > /sys/fs/cgroup/freezer/prepareumount/freezer.state

for i in $(seq 1 10); do
    for p in $(fuser -m /mount/v1 2>/dev/null); do
        echo $p > /sys/fs/cgroup/freezer/prepareumount/cgroup.procs
        for t in $(ps -L -o tid= -p $p); do
            echo $t > /sys/fs/cgroup/freezer/prepareumount/tasks
        done
    done
done

#give time to an overloaded kernel to freeze everything (FREEZING->FROZEN)
while ! cat /sys/fs/cgroup/freezer/prepareumount/freezer.state | grep -q FROZEN; do
    sleep 0.1
done

# kills, delayed
for i in $(cat /sys/fs/cgroup/freezer/prepareumount/cgroup.procs); do
    kill -KILL $i
done

# actual kills happen now, at once
echo THAWED > /sys/fs/cgroup/freezer/prepareumount/freezer.state

sleep 1
umount /mount/v1

如果使用 cgroups v2,則必須對此進行調整。

相關內容