所有計算機操作系統都在引導時檢查它們掛載的文件系統是否是一致的,也就是說,確認它們的內部數據結構和映射到的相關存儲沒有錯誤。UNIX、Linux® 和其他類 UNIX 操作系統采用一種聰明的方法檢查文件系統的一致性(通常使用 fast
命令)。當這些系統掛載文件系統時,它們在文件系統頭中設置一個值,把文件系統標為 DIRTY
,這意味著它正在使用,在向它寫入更新時可能暫時處於不一致的狀態。在系統關閉期間卸載文件系統時,把它們標為 CLEAN
。在重新引導系統時,只需要檢查仍然標為 DIRTY
的文件系統的一致性。
在系統關閉過程中,會自動地卸載文件系統,這通常在終止所有非系統進程之後進行。但是,卸載文件系統仍然可能失敗並顯示以下消息:
$ sudo umount /mnt/NAS umount: /mnt/NAS: device is busy
在這裡,busy
意味著一個進程正在寫這個文件系統或者進程是從它運行的。在這兩種情況下,都無法卸載文件系統,這是計算機系統的基本規則之一。如果不采用這個規則,可以在進程正在寫文件系統包含的文件時卸載文件系統,就會讓文件處於不一致的狀態,而文件系統本身標為 CLEAN
。
umount
命令的標准 Linux 版本包含一個延遲卸載選項 -l
,它有助於卸載正在使用的文件系統。這個命令需要 Linux 內核 2.4.11 或更高版本,目前這通常沒問題。執行 umount -l /name/of/file system
可以讓指定的文件系統與系統的目錄層次結構脫離,讓新進程不能使用這個文件系統,然後當正在訪問它的所有進程都終止時卸載它。這很方便,但是當需要馬上卸載文件系統時它並不合適。
如果需要馬上卸載文件系統,而文件系統報告忙碌,還有其他辦法。如果您是系統的惟一用戶,那麼只需終止阻止文件系統卸載的進程。這需要查看所有窗口,尋找並終止正在寫這個分區或使用它作為當前工作目錄的暫停的進程或後台進程。但是,在有許多本地用戶和遠程用戶的多用戶系統上,這種方法是不實際的。幸運的是,開放源碼社區提供了一些命令,可以輕松地識別並終止這些進程。
用 lsof
尋找打開的文件
lsof
(list open files) 命令列出特定的文件系統、目錄或設備上所有打開的文件以及與它們相關聯的進程。在大多數 UNIX 和類 UNIX 系統上都可以使用 lsof
命令,包括 IBM® AIX®、Berkeley Software Distribution (BSD®)、Hewlett Packard UNIX (HP-UX®)、Linux 和 Solaris®。關於獲取適合自己系統的 lsof
的信息請參見 參考資料。
在默認情況下,lsof
命令列出當前打開的所有文件、共享庫和目錄,並提供盡可能多的相關信息。即使在負載很輕的系統上,這個命令的輸出也非常長,因此通常通過命令行參數指定一個目錄名,或者使用管道篩選它的輸出。例如,假設希望卸載掛載在 /opt2 目錄上的文件系統。為了查看與 /opt2 目錄相關聯的所有進程,應該執行 清單 1 所示的命令。
$ lsof /opt2 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME bash 23334 wvh cwd DIR 8,17 4096 2 /opt2 more 23402 wvh cwd DIR 8,17 4096 2 /opt2 more 23402 wvh 3r REG 8,17 10095 264 /opt2/resume.txt
需要終止所有這些進程,然後才能卸載 /opt2 分區。因為這個列表中的進程都不能寫任何文件,所以可以使用 kill
命令並指定第二列中列出的進程 ID (PID) 以終止它們,然後就可以順利地卸載分區。注意,PID 23402 與最後兩行相關聯 — 第一行表示 more
命令以 /opt2 作為當前工作目錄 (cwd
),第二行表示 more
命令打開了 /opt2/resume.txt 文件。
但是,假設 lsof
命令的輸出像 清單 2 這樣。
但是,fuser
命令的默認輸出不便於最終用戶使用,即使按 Linux 標准來看也是如此。fuser
命令提供一個 -v
選項,它在 fuser
命令的輸出中增加一些與標准 ps
命令相似的輸出,見 清單 7。
$ fuser -v /mnt/yellowmachine USER PID ACCESS COMMAND /mnt/yellowmachine: wvh 23334 ..c.. bash wvh 23697 ..c.. emacs
這更方便,因為它至少指出了進程是什麼程序。在通過 fuser
命令獲得 PID 信息之後,可以在終止進程之前結合使用標准的 ps
和 egrep
命令了解盡可能詳細的相關信息,見 清單 8。
# ps alxww |egrep '23334|23697' 4 1000 23334 23332 20 0 18148 2076 wait Ss pts/13 0:00 -bash 0 1000 23697 23334 20 0 75964 12352 poll_s S+ pts/13 0:00 emacs -nw file2.txt 0 0 23703 23665 20 0 6060 632 - R+ pts/16 0:00 egrep 23334|23697
然後,可以使用標准的 kill
命令手工終止指定的進程,或者像下一節中解釋的,使用 fuser
命令的一些高級功能自動地終止它們。
用 fuser
終止進程
在通過參數指定掛載點時,fuser
命令的 -k
選項會自動地終止找到的進程。當然,必須作為根用戶執行 fuser
命令,才能終止屬於其他用戶的進程,見 清單 9。
清單 9. 終止與掛載的 NFS 文件系統相關聯的進程
# fuser -k /mnt/yellowmachine /mnt/yellowmachine: 23334c 23697c Could not kill process 23697: No such process
在這裡,第二個進程 (emacs) 是第一個進程 (bash shell) 的子進程,因此在 fuser
命令殺死第一個進程時它就會終止。
如果希望指定底層物理設備名,而不是它包含的文件系統的掛載點,那麼還必須指定 -m
選項,見 清單 10。
清單 10. 掛載點和設備的進程列表
# fuser -v /opt2 USER PID ACCESS COMMAND /opt2: wvh 23712 ..c.. bash wvh 23753 ..c.. emacs # fuser -v /dev/sdb1 # fuser -vm /dev/sdb1 USER PID ACCESS COMMAND /dev/sdb1: wvh 23712 ..c.. bash wvh 23753 ..c.. emacs
第一個命令返回的輸出符合預期,因為它引用文件系統的掛載點。第二個命令表明,不能使用標准的 fuser
選項直接查詢底層設備。第三個命令說明,-m
選項允許直接指定設備。可以在第一個和第三個命令中添加 -k
選項,從而終止與 /dev/sdb1 設備上的文件系統相關聯的進程。
結束語
有時候,為了應對一些緊急情況或者刪除掛載的 CD-ROM 或 DVD 等設備,Linux 或 UNIX 系統管理員需要卸載分區。在由於設備忙系統不允許刪除它的情況下,檢查系統上的所有進程是一個很煩人、很緩慢的過程。lsof
和 fuser
命令有助於識別阻止文件系統卸載的進程。如果情況非常緊急,fuser
命令甚至可以替您終止它們。