首頁  >  文章  >  運維  >  從 lsof 開始,深入理解 Linux 虛擬檔案系統

從 lsof 開始,深入理解 Linux 虛擬檔案系統

Linux中文社区
Linux中文社区轉載
2023-08-04 16:15:491616瀏覽

背景

有有時會出現這樣的情況,磁碟空間顯示已經被佔滿,但是在檢視磁碟的具體檔案佔用情況時,發現磁碟仍有很大的空餘空間。
1.執行<span style="font-size: 15px;">df</span>#指令查看磁碟使用情況,發現磁碟已經滿了。
-bash-4.2$ df -ThFilesystem     Type      Size  Used Avail Use% Mounted on/dev/vda1      ext4       30G    30G 0         100% /devtmpfs       devtmpfs  489M     0  489M   0% /devtmpfs          tmpfs     497M     0  497M   0% /dev/shmtmpfs          tmpfs     497M   50M  447M  11% /runtmpfs          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.为何会出现这样的情况呢?
因为虽然文件已被删除,但是一些进程仍然打开这些文件,因此其占用的磁盘空间并没有被释放。执行<span style="font-size: 15px;">lsof</span> 命令显示打开已删除的文件。将有问题的进程重启(或,清空),磁盘空间就会得到释放。
-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)

那么,Linux 的文件系统,到底为什么这么设计呢?要了解这些,就要先弄清楚并不容易,下面将从一些基本概念入手,一步步将这些梳理清楚:
  • 什么是虚拟文件系统(VFS:virtual filesystem)?

  • 什么是通用文件模型?

    • 超级块对象(superblock object)

    • 索引节点对象(inode object)

    • 文件对象(file object)

    • 目录项对象(dentry object)

    • 文件的概念

  • 文件的表达

    • 内存表达

    • 磁盘表达

  • 目录树的构建

    • 軟體連結vs 硬連結

  • #檔& 磁碟管理

    • 索引節點狀態

  • 檔& 行程管理

    • 作業:

      ##開啟&刪除

虛擬檔案系統(virtual filesystem)
下圖顯示了Linux 作業系統中負責檔案管理的基本元件。上半區域為使用者模式,下半區域為核心模式。應用程式使用標準庫libc來存取文件,庫將請求映射到系統調用,以便進入內核模式。

從 lsof 開始,深入理解 Linux 虛擬檔案系統

#######
所有與檔案相關的操作的入口都是虛擬檔案系統(VFS),而非特定的額檔案系統(如Ext3、ReiserFS和NFS)。 VFS 提供了系統函式庫和特定檔案系統之間的介面。因此,VFS 不僅充當抽象層,而且實際上它提供了一個檔案系統的基本實現,可以由不同的實作來使用和擴展。因此,要了解檔案系統是如何運作的,就要先了解VFS 。

通用檔案模型

VFS 的主要想法在於引入了一個通用檔案模型(common file model)。通用檔案模型由以下物件類型組成:

超級區塊物件(superblock object)

記憶體:檔案系統安裝時創建,存放檔案系統的相關資訊
磁碟:對應於存放在磁碟上的檔案系統控制區塊(filesystem control block)

索引節點物件( inode object)

##記憶體:存取時創建,存放關於具體檔案的一般資訊(

inode 結構磁碟:對應於存放在磁碟上的檔案控制區塊(file control block)
每個索引節點物件都有索引節點號,唯一標識檔案系統的檔案

檔案物件(file object)

#記憶體:開啟檔案時創建,存放開啟檔案與行程之間進行互動的有關資訊(file 結構
開啟檔案訊息,僅當進程存取檔案期間存在於內核記憶體中。

目錄項目物件(dentry object)

#記憶體:目錄項目一旦被讀入內存,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对象,再检查匹配的目录项,反复执行以上过程,直至找到对应的文件的索引节点,并创建索引节点对象。

软链接 vs 硬链接

软链接是一个普通的文件,其中存放的是另外一个文件的路径名。硬链接则指向同一个索引节点,硬链接数记录在索引节点对象的 i_nlink 字段。当<span style="font-size: 15px;color: rgb(68, 68, 68);">i_nlink</span>字段为零时,说明没有硬链接指向该文件。

文件 & 进程管理

下图是一个简单示例,说明进程是怎样与文件进行交互。三个不同进程打开同一个文件,每个进程都有自己的文件对象,其中两个进程使用同一个硬链接(每个硬链接对应一个目录对象),两个目录项对象都指向同一个 索引节点对象。

從 lsof 開始,深入理解 Linux 虛擬檔案系統

索引节点的数据又由两部分组成:内存数据和磁盘数据。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

索引節點是否仍在使用,是透過 <span style="font-size: 15px;">open()</span> 和 <span style="font-size: 15px;">close ()</span> 作業建立和銷毀檔案對象,檔案物件透過索引節點提供的 <span style="font-size: 15px;">iget</span> 和  <span style="font-size: 15px;">#iput</span>  更新索引節點的i_count字段,以完成使用計數。 open 操作使得 i_count 加一, close 操作使得 i_count 減一。在 close 操作時判斷索引節點是否釋放,如果 i_count = 0,則表示不再有進程引用,將會從記憶體釋放。

檔案& 磁碟管理

檔案與磁碟管理連結最緊密的操作,莫過於<span style="font-size: 15px;">touch </span><span style="font-size: 15px;">rm</span>操作,而特別以後者最為關鍵。透過strace(或 dtruss),查看 rm 的實際的系統呼叫

#
# dtruss rm tmp...geteuid(0x0, 0x0, 0x0)         = 0 0ioctl(0x0, 0x4004667A, 0x7FFEE06F09C4)         = 0 0lstat64("tmp\0", 0x7FFEE06F0968, 0x0)         = 0 0access("tmp\0", 0x2, 0x0)         = 0 0unlink("tmp\0", 0x0, 0x0)         = 0 0

可以发现 rm 实际是通过 unlink 完成的。unlink代表删除目录项,以及减少其索引节点的计数。由通用文件模型可知,父目录本身同样是一个文件,也就意味着目录项是其文件数据的一部分。删除目录项等价于从父目录的文件中删除数据,也就意味着首先要打开父目录的文件。那么,删除操作即可理解为:

  1. 删除命令(一个进程)使用 open 操作获得父目录文件对象

  2. 通过 <span style="font-size: 15px;color: rgb(68, 68, 68);">iget</span> 增加 目录文件的索引节点对象计数

  3. 读取目录文件数据

  • 将目录文件数据转化为目录项对象

  • 由于目录项包含文件的索引节点,类似的,需要通过 iget 增加文件的索引节点对象计数

  • 删除目录的目录项

  • 减少文件索引节点对象的硬链接计数i_nlink

  • 通过 <span style="font-size: 15px;color: rgb(68, 68, 68);">iput</span> 结束对文件索引节点对象的操作,使用计数 i_count 减一

    • 判断i_count是否为零,如果为零,则释放内存

    • 然后,判断i_nlink是否为零,如果为零,则释放磁盘空间

  • 通过 iput 结束对目录索引节点对象的操作。

  • 總結

    回頭來看遇到的問題,其實可以從兩個角度來理解:

    索引與資料

    檔案系統與檔案、磁碟管理與檔案、行程管理與文件,最核心的都是檔案的索引,而不是檔案的資料。把資料和索引分開是理解檔案系統的關鍵。


    從 lsof 開始,深入理解 Linux 虛擬檔案系統

    快取策略

    由於作業系統使用Write back的策略,意味著只有先釋放內存,才有可能釋放磁碟。

    Why lsof ?

    從上面的模型可以很清楚的理解,因為目錄已經沒有索引到文件了,但是打開文件還有索引到文件,所以不能立刻釋放磁碟空間。
    為什麼 lsof 可以找到已刪除未釋放的檔案?
    lsof,顧名思義:list open files,該命令的原則就是查找開啟檔案的列表,因此可以找到已刪除未釋放的檔案。
#

以上是從 lsof 開始,深入理解 Linux 虛擬檔案系統的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:Linux中文社区。如有侵權,請聯絡admin@php.cn刪除