從 lsof 開始,深入理解 Linux 虛擬檔案系統
導讀 | 有時會出現這樣的情況,磁碟空間顯示已經被佔滿,但是在檢視磁碟的具體檔案佔用情況時,發現磁碟仍然有很大的空餘空間。 |
有時會出現這樣的情況,磁碟空間顯示已經被佔滿,但是在檢視磁碟的具體檔案佔用情況時,發現磁碟仍然有很大的空餘空間。
1.執行df 檢視磁碟使用情況,發現磁碟已經滿了。
-bash-4.2$ df -Th Filesystem Type Size Used Avail Use% Mounted on /dev/vda1 ext4 30G 30G 0 100% / devtmpfs devtmpfs 489M 0 489M 0% /dev tmpfs tmpfs 497M 0 497M 0% /dev/shm tmpfs tmpfs 497M 50M 447M 11% /run tmpfs tmpfs 497M 0 497M 0% /sys/fs/cgroup
2.執行 du 檢視各個目錄的磁碟佔用情況,把各個目錄檔案的大小相加,發現並沒有佔滿磁碟,有10多G空間莫名失蹤。
-bash-4.2$ du -h --max-depth=1 /home16M /home/logs11G /home/serverdog11G /home
3.為何會出現這樣的情況呢?
因為雖然檔案已被刪除,但是一些程式仍然開啟這些檔案,因此其佔用的磁碟空間並沒有被釋放。執行lsof 命令顯示開啟已刪除的檔案。將有問題的程式重啟(或,清空),磁碟空間就會得到釋放。
-bash-4.2# lsof | grep deletemysqld 2470 mysql 4u REG 253,1 0 523577 /var/tmp/ibfTeQFn (deleted) mysqld 2470 mysql 5u REG 253,1 0 523579 /var/tmp/ibaHcIdW (deleted) mysqld 2470 mysql 6u REG 253,1 0 523581 /var/tmp/ibLjiALu (deleted) mysqld 2470 mysql 7u REG 253,1 0 523585 /var/tmp/ibCFnzTB (deleted) mysqld 2470 mysql 11u REG 253,1 0 523587 /var/tmp/ibCjuqva (deleted)
那麼, 的檔案系統,到底為什麼這麼設計呢?要了解這些,就要先弄清楚並不容易,下面將從一些基本概念入手,一步步將這些梳理清楚:
- 什麼是虛擬檔案系統(VFS:virtual filesystem)?
- 什麼是通用檔案模型?
- 超級塊物件(superblock object)
- 索引節點物件(inode object)
- 檔案物件(file object)
- 目錄項物件(dentry object)
- 檔案的概念
- 檔案的表達
- 記憶體表達
- 磁碟表達
- 目錄樹的構建
- 軟連結 vs 硬連結
- 檔案 & 磁碟管理
- 索引節點狀態
- 檔案 & 程式管理
- 操作:
- 開啟&刪除
下圖顯示了 Linux 作業系統中負責檔案管理的基本元件。上半區域為使用者模式,下半區域為核心模式。應用程式使用標準庫libc來訪問檔案,庫將請求對映到系統呼叫,以便進入核心模式。
所有與檔案相關的操作的入口都是虛擬檔案系統(VFS),而非特定的額檔案系統(如Ext3、ReiserFS和NFS)。VFS 提供了系統庫和特定檔案系統之間的介面。因此,VFS 不僅充當抽象層,而且實際上它提供了一個檔案系統的基本實現,可以由不同的實現來使用和擴充套件。因此,要了解檔案系統是如何工作的,就要先了解VFS 。
VFS 的主要思想在於引入了一個通用檔案模型(common file model)。通用檔案模型由以下物件型別組成:
記憶體:檔案系統安裝時建立,存放檔案系統的有關資訊
磁碟:對應於存放在磁碟上的檔案系統控制塊(filesystem control block)
記憶體:訪問時建立,存放關於具體檔案的一般資訊(inode 結構)
磁碟:對應於存放在磁碟上的檔案控制塊(file control block)
每個索引節點物件都有一個索引節點號,唯一地標識檔案系統的檔案
記憶體:開啟檔案時建立,存放 開啟檔案 與程式之間進行互動的有關資訊(file 結構)
開啟檔案資訊,僅當程式訪問檔案期間存在於核心記憶體中。
記憶體:目錄項一旦被讀入記憶體,VFS就會將其轉換成dentry 結構的目錄項物件
磁碟:特定檔案系統以特定的方式儲存在磁碟上
存放目錄項(即,檔名稱)與對應檔案進行連結的有關資訊
綜合來說,Linux 的 根檔案系統(system’s root filessystem) 是核心啟動mount的第一個檔案系統。核心程式碼映像檔案儲存在根檔案系統中,而系統引導啟動程式會在根檔案系統掛載之後,從中把一些基本的初始化 和服務等載入到記憶體中去執行(檔案系統和核心是完全獨立的兩個部分)。其他檔案系統,則後續通過 或命令作為子檔案系統安裝在已安裝檔案系統的目錄上,最終形成整個目錄樹。
start_kernel vfs_caches_init mnt_init init_rootfs // 註冊rootfs檔案系統 init_mount_tree // 掛載rootfs檔案系統 … rest_init kernel_thread(kernel_init, NULL, CLONE_FS);
就單個檔案系統而言,在檔案系統安裝時,建立超級塊物件;沿樹查詢檔案時,總是首先從初識目錄的中查詢匹配的目錄項,以便獲取相應的索引節點,然後讀取索引節點的目錄檔案,轉化為dentry物件,再檢查匹配的目錄項,反覆執行以上過程,直至找到對應的檔案的索引節點,並建立索引節點物件。
軟連結是一個普通的檔案,其中存放的是另外一個檔案的路徑名。硬連結則指向同一個索引節點,硬連結數記錄在索引節點物件的 i_nlink 欄位。當i_nlink欄位為零時,說明沒有硬連結指向該檔案。
下圖是一個簡單示例,說明程式是怎樣與檔案進行互動。三個不同程式開啟同一個檔案,每個程式都有自己的檔案物件,其中兩個程式使用同一個硬連結(每個硬連結對應一個目錄物件),兩個目錄項物件都指向同一個 索引節點物件。
索引節點的資料又由兩部分組成:記憶體資料和磁碟資料。Linux 使用 Write back 作為索引節點的資料一致性策略。對於索引節點的資料,當檔案被開啟時,才會載入索引節點到記憶體;當不再被程式使用,則從記憶體踢出;如果中間有更新,則需要把資料寫回磁碟。
* "in_use" - valid inode, i_count > 0, i_nlink > 0 * "dirty" - as "in_use" but also dirty * "unused" - valid inode, i_count = 0
索引節點是否仍在使用,是通過 open() 和 close() 操作建立和銷燬檔案物件,檔案物件通過索引節點提供的 iget 和 iput 更新索引節點的i_count欄位,以完成使用計數。open 操作使得 i_count 加一, close 操作使得 i_count 減一。在 close 操作時判斷索引節點是否釋放,如果 i_count = 0,則意味著不再有程式引用,將會從記憶體釋放。
檔案 & 磁碟管理
檔案與磁碟管理聯絡最緊密的操作,莫過於touch和rm操作,而尤以後者最為關鍵。通過strace(或 dtruss),檢視 rm 的實際的系統呼叫
# dtruss rm tmp ... geteuid(0x0, 0x0, 0x0) = 0 0 ioctl(0x0, 0x4004667A, 0x7FFEE06F09C4) = 0 0 lstat64("tmp\0", 0x7FFEE06F0968, 0x0) = 0 0 access("tmp\0", 0x2, 0x0) = 0 0 unlink("tmp\0", 0x0, 0x0) = 0 0
可以發現 rm 實際是通過 unlink 完成的。unlink代表刪除目錄項,以及減少其索引節點的計數。由通用檔案模型可知,父目錄本身同樣是一個檔案,也就意味著目錄項是其檔案資料的一部分。刪除目錄項等價於從父目錄的檔案中刪除資料,也就意味著首先要開啟父目錄的檔案。那麼,刪除操作即可理解為:
- 刪除命令(一個程式)使用 open 操作獲得父目錄檔案物件
- 通過 iget 增加 目錄檔案的索引節點物件計數
- 讀取目錄檔案資料
- 將目錄檔案資料轉化為目錄項物件
- 由於目錄項包含檔案的索引節點,類似的,需要通過 iget 增加檔案的索引節點物件計數
- 刪除目錄的目錄項
- 減少檔案索引節點物件的硬連結計數i_nlink
- 通過 iput 結束對檔案索引節點物件的操作,使用計數 i_count 減一
- 判斷i_count是否為零,如果為零,則釋放記憶體
- 然後,判斷i_nlink是否為零,如果為零,則釋放磁碟空間
- 通過 iput 結束對目錄索引節點物件的操作。
回頭來看遇到的問題,其實可以從兩個角度來理解:
檔案系統與檔案、磁碟管理與檔案、程式管理與檔案,最核心的都是檔案的索引,而不是檔案的資料。把資料和索引分開是理解檔案系統的關鍵。
由於作業系統使用 Write back 的策略,意味著只有先釋放記憶體,才有可能釋放磁碟。
從上面的模型可以很清楚的理解,因為目錄已經沒有索引到檔案了,但是開啟檔案還有索引到檔案,所以不能立刻釋放磁碟空間。
為什麼 lsof 可以找到已刪除未釋放的檔案呢?
lsof,顧名思義:list open files,該命令的原理就是查詢開啟檔案的列表,因此可以找到已刪除未釋放的檔案。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2854615/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 從rm到linux虛擬檔案系統Linux
- Linux系統篇-檔案系統&虛擬檔案系統Linux
- 詳解 Linux 中的虛擬檔案系統Linux
- Linux 核心101:虛擬檔案系統的使命Linux
- 深入理解 ext4 等 Linux 檔案系統Linux
- 深入理解虛擬機器之類檔案結構虛擬機
- 深入理解Java虛擬機器(類檔案結構)Java虛擬機
- 深入理解Java虛擬機器 – 類檔案結構Java虛擬機
- 深入理解 python 虛擬機器:pyc 檔案結構Python虛擬機
- Linux Centos系統 磁碟分割槽和檔案系統管理 (深入理解)LinuxCentOS
- 理解Linux檔案系統之 inodeLinux
- Linux深入探索12-檔案系統Linux
- 深入理解Promise從這裡開始Promise
- 《深入理解Java虛擬機器》-(實戰)練習修改class檔案Java虛擬機
- 類檔案結構——深入理解Java虛擬機器 筆記三Java虛擬機筆記
- Linux系統中虛擬裝置檔案的各種實用用法Linux
- VM 虛擬機器linux從主機複製檔案到虛擬機器錯誤虛擬機Linux
- 深入理解 python 虛擬機器:破解核心魔法——反序列化 pyc 檔案Python虛擬機
- 深入理解java虛擬機器Java虛擬機
- linux系統檔案開啟數Linux
- 微軟開始擁抱開源社群 exFAT檔案系統向Linux開源微軟Linux
- Linux作業系統分析 | 深入理解系統呼叫Linux作業系統
- 深入理解Java虛擬機器(一)Java虛擬機
- 深入理解Java虛擬機器(二)Java虛擬機
- Linux檔案系統Linux
- [Linux]檔案系統Linux
- 虛擬機器之linux系統命令虛擬機Linux
- windows如何傳檔案到linux虛擬機器WindowsLinux虛擬機
- 深入學習Java虛擬機器——類檔案結構Java虛擬機
- Linux系統檔案系統及檔案基礎篇Linux
- 深入理解虛擬機器之垃圾回收虛擬機
- 【深入理解Java虛擬機器】垃圾回收Java虛擬機
- 深入理解javascript系列(十九):從Promise開始到async/awaitJavaScriptPromiseAI
- 深入理解Java虛擬機器 – 閱讀class檔案的三種姿勢(連載2)Java虛擬機
- 論Linux檔案系統Linux
- Linux AUFS 檔案系統Linux
- linux的檔案系統Linux
- 從零開始實現React(一):JSX和虛擬DOMReactJS