chdir引起的磁盤目錄佔用的一種場景

進程佔用磁盤的排查方式

工作中遇到了進程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
  • 堆棧
  • 共享內存
  • 打開的文件描述符
  • 執行時關閉標誌
  • 信號控制設定
  • 進程組號
  • 當前工作目錄
  • 根目錄
  • 文件方式創建屏蔽字
  • 資源限制
  • 控制終端

其中可能引起佔用的有兩個點,一個爲打開的文件描述符,一個爲當前工作目錄。

  1. 如果子進程包含打開的文件描述符,則lsof會顯示打開的文件句柄的路徑。但從代碼中看進程X的實現代碼確實不存在打開句柄的情況
  2. 故而更有可能的是子進程對父進程工作目錄的繼承,而引起的對路徑的佔用。

工作目錄

關於工作目錄,我們最常用的就是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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章