進程佔用磁盤的排查方式
工作中遇到了進程X 佔用磁盤(或者說目錄),引起磁盤無法格式化(可以近似認爲目錄無法被刪除)的問題,之前出現這種情況,多爲進程在磁盤(目錄)上擁有打開的文件句柄,使用lsof命令可以看到有佔用句柄的進程,故而在要進行磁盤格式化前後增加了模塊退出機制,去除模塊的對磁盤的佔用。但本次的問題出現情況不同,對應進程X 從表現上看確實存在對磁盤的佔用,使用lsof或者fuser命令都可以查看到佔用磁盤路徑的進程pid列表中存在對應進程X。但從代碼層面看,進程X確實不涉及到對磁盤的佔用。
fuser - identify processes using files or sockets
-m NAME, --mount NAME
指定文件或者掛載的設備
Usage:
fuser -m "/path/"
lsof - 列出當前系統打開文件
Usage:
lsof "/path"
父子進程關聯
排查過程中發現,殺死進程X 單獨啓動,發現對磁盤目錄的佔用就去除了。
因之前遇到過由於未設置 FD_CLOEXEC 標記位,而出現了代碼中只起了一個監聽套接字,但在netstat中出現了有兩個監聽相同端口的套接字的奇怪現象,最終發現是由於在創建套接字時,沒有 cloexec,而導致套接字被子進程所繼承導致。故而懷疑該佔用是不是也是由於父進程的操作而引起的,因爲對應進程X 恰好是由進程A 通過system調用啓動的。
system實際的執行流程就是調用,fork->exec->wait。而fork的過程中,子進程會繼承父進程的如下資源
- 用戶號UIDs和用戶組號GIDs
- 環境 Envronment
- 堆棧
- 共享內存
- 打開的文件描述符
- 執行時關閉標誌
- 信號控制設定
- 進程組號
- 當前工作目錄
- 根目錄
- 文件方式創建屏蔽字
- 資源限制
- 控制終端
其中可能引起佔用的有兩個點,一個爲打開的文件描述符,一個爲當前工作目錄。
- 如果子進程包含打開的文件描述符,則lsof會顯示打開的文件句柄的路徑。但從代碼中看進程X的實現代碼確實不存在打開句柄的情況
- 故而更有可能的是子進程對父進程工作目錄的繼承,而引起的對路徑的佔用。
工作目錄
關於工作目錄,我們最常用的就是cd命令,通過cd命令,修改我們當前所在的shell的工作目錄。調整了我們調用其他可執行文件的相對位置的起點。針對unix,可以使用 getcwd來獲取當前的工作目錄,也可以通過chdir來切換當前工作目錄。
getcwd - copies an absolute pathname of the current working directory to the array pointed to by buf, which is of length size
Usage:
char szBuf[1024] = {0};
getcwd(szBuf, sizeof(szBuf));
chdir - changes the current working directory of the calling process to the directory specified in path
int chdir(const char *path);
通過排查找到父進程A 確實新引入了chdir,將工作目錄切換到了磁盤路徑,並在此後不再切換工作目錄。
通過在模塊結束時,重新將chdir工作目錄切換到默認的工作目錄,重新啓動進程A,可以發現通過system調用的進程X不再佔用 磁盤路徑。磁盤可以正常被格式化。
這裏的默認工作目錄是什麼呢?其實也就是進程A的父進程的工作目錄,進程A是在開機啓動過程中啓動的,故而繼承了系統shell的工作目錄,這個工作目錄是在/etc/bashrc中配置的。
這裏要注意另外一點,父進程中切換工作目錄是會影響後面system調用啓動的子進程,但是子進程中調用chdir,或者腳本中調用cd,是不會影響到父進程的工作目錄的。
參考
Linux中父子進程的繼承關係
https://blog.csdn.net/feiyagogogo/article/details/79671398
popen/system與fork函數
https://blog.csdn.net/Cyrus_wen/article/details/80018721