Linux硬碟看起來還有空間卻不能寫:查inode與已刪開啟檔

網站上傳失敗,訊息說「No space left on device」,但df看起來還有容量。先不要刪一批不認識的檔案:可能是inode已用完,也可能看錯了檔案系統。另一種情況是檔案已刪,空間卻遲遲不回來,因為程序仍把它開著。

這兩種問題的查法不同。inode不足會讓新檔案無法建立,即使資料區還有容量;已刪開啟檔則可能讓目錄裡看不到的內容,仍佔著檔案系統空間。先把寫入位置、容量、inode與開啟檔對上,再決定處理方式。

查真正寫入的那個路徑

不要只看根目錄的df。網站上傳、暫存、備份與日誌可能在不同掛載點,出錯的是暫存目錄,網站素材目錄卻還有空間。把命令中的路徑換成實際失敗位置,先做唯讀查詢:

df -h /實際寫入目錄
df -i /實際寫入目錄

第一行看資料區容量,第二行看inode使用量。記下Filesystem、掛載點、可用容量與IFree,不要只抄最後的百分比。容器裡的路徑可能是獨立volume或tmpfs,也可能落在容器可寫層;主機和容器看到的結果需要按實際掛載對照。

空檔案也需要inode

大量零位元組的小檔案,幾乎不佔資料容量,仍需要檔案系統的識別資源。除了普通檔案,目錄也會使用inode。若IFree是0,建立新檔可能失敗;不能因檔案都很小,就認為它們沒有影響。

本文用專用容器的1MiB tmpfs重現,明確限制16個inode。起初根目錄使用1個,建立15個空檔後,df仍顯示1024KiB可用,inode卻已16/16,第16個檔案建立失敗。

容量:1024 KiB,可用 1024 KiB
inode:16 個,已用 16 個,可用 0 個
touch: No space left on device

清掉這15個專用測試檔後,inode回到已用1個、可用15個。這說明容量和inode是不同限制;例子是受限tmpfs,不能把它的inode設定方法直接搬到ext4或其他正式檔案系統。

找到小檔來源,才安排清理

若inode確實耗盡,先核對哪個應用持續產生暫存、快取或工作檔。大量失敗重試、沒有到期清理的快取與堆積佇列,都可能留下許多小檔,但不能只憑目錄名稱叫cache就直接刪掉。

有GNU du的環境,可用inode統計比較目標目錄的子層:

du --inodes -x --max-depth=1 /要核對的目錄

這是GNU選項,BusyBox或其他版本未必相同。查之前先看當地工具手冊;大型目錄的掃描也會花時間與I/O,限定相關位置,不要一開始遞迴全機。權限不足或掃描中資料變動,也會影響結果。

清理應按應用的保留與到期規則,由負責人確認檔案用途、備份與恢復方式。只刪已確認可丟棄的資料,並處理持續產生檔案的原因;不然暫時空出inode,很快又會塞滿。

如果問題是幾十萬個小檔,刪掉一個很大的備份,可能釋放大量容量,卻只多出很少inode。反過來,清掉許多零位元組檔案,容量數字可能幾乎不變,inode卻明顯恢復。處理目標要和耗盡的資源一致。

同一個inode也可能有多個硬連結名稱,所以檔名數不一定等於inode數。不要把find數出的行數直接當成df -i的總用量;目錄結構、硬連結與工具統計範圍都要一起看。

刪掉名稱,程序還可能把檔案開著

Linux移除檔案名稱後,若仍有程序開啟該檔,內容可以繼續存在。直到指向它的最後一個檔案描述符關閉,且沒有其他硬連結保留名稱,空間才有條件釋放。

本文另建立512KiB檔案,讓同一個測試shell用描述符3保持開啟。移除檔名後,du在目錄裡看到0KiB,但df仍顯示已用512KiB,描述符指向的路徑帶有deleted。關閉這個描述符後,df才回到已用0KiB。

階段                 df 已用       du 目錄用量
檔案存在且開啟       512 KiB       512 KiB
檔名移除、仍開啟     512 KiB         0 KiB
最後描述符關閉         0 KiB         0 KiB

用lsof找仍被持有的已刪檔

在已有lsof且具備查看權限的Linux環境,先查連結數少於1的開啟檔:

lsof +L1

核對程序名稱、PID、檔案描述符、裝置與檔名,確認它屬於哪個檔案系統和服務。不要看到deleted就結束所有程序;有些程式正常使用匿名或已移除的暫存檔,是否異常還要看持有大小與生命週期。

查不到也不等於沒有開啟檔。工具是否存在、查看權限、程序命名空間與容器隔離,都可能限制你看到的範圍。交維護者時保留必要欄位,避免公開私人路徑或客戶資料。

讓服務正常釋放,不要盲目砍程序

若確認某服務持有已刪的大日誌,按它的官方輪替與重新開啟日誌流程處理。不同服務的重新載入方式不同,不能把一個訊號當成所有程式通用命令。需要重新啟動時,也先確認業務影響和恢復安排。

不要直接對陌生PID使用kill -9,也不要把/proc裡的描述符當成可以任意清空的檔案。這可能破壞正在寫入的資料;找到持有者,是為了交給正確的服務流程釋放。

同一個檔案可能被多個描述符或程序持有。關掉其中一個,不代表最後一個也已關閉;若用量沒有下降,重新核對剩餘持有者,而不是重複刪那個已經不存在的名稱。服務是否會重新開啟同名日誌,也要另行確認。

df與du不同,不只這一個原因

du計算的是走訪到的目錄內容,df看的是檔案系統統計。掛載點、權限、硬連結、保留空間與掃描期間的資料變化,都可能讓兩者不同。先用相同檔案系統和明確範圍比較,不能看到數字不一致就認定一定有已刪開啟檔。

容量和inode都有餘量,寫入仍失敗時,另外查完整錯誤、唯讀掛載、權限、配額與應用限制。先縮小是哪一層拒絕寫入,不必把每個問題都塞進「硬碟滿了」。

處理後,用同一個寫入位置重新查df與df -i,再完成一個已授權的小型寫入驗證。記下釋放了哪一類資源、由哪個服務處理,並確認檔案沒有繼續無限制增長。數字下降只證明資源變化,網站上傳或備份是否恢復仍要按具體功能核對。

參考資料

原文鏈接:https://wntheme.com/linux-disk-inode-open-files/,轉載請註明出處。
0

評論0

顯示驗證碼
沒有帳號?註冊  忘記密碼?