- 文件建立過程
- inode解析
此次來講文件系統. 文件系統是很是重要的, 提升磁盤使用率, 減少磁盤磨損等等都是文件系統要解決的問題. 市面上的文件系統也是數不勝數, 比較經常使用的像ext4, xfs以及ntfs等等, 國內的像鵝廠的tfs, 而後還有sun號稱"last word in file system"的ZFS, 學習ZFS而來的btrfs.html
下面上一張Linux文件系統組件的體系結構圖, 是我整合了多方文獻並結合本身的經驗畫出來的. 能夠看出, 最重要的就是vfs, 正是由於它, 才讓Linux能夠同時支持多種的文件系統. 舉個例子, 好比你裝了雙系統mint+windows, 在mint中, 你能夠看到windows的ntfs磁盤, 可是返回了windows, 你就看不到mint的磁盤了.node
那Linux支持哪些文件系統呢? 來到源碼的fs文件夾, Linux支持的文件系統可多了去了, 注意看藍色的.linux
磁盤扇區什麼的就很少說了. 也許會出一篇談存儲介質的文章, 說說ssd結構啥的. 直接跳過硬件從文件系統結構開始. 注意, 我說的是通用模型, 每一個fs的具體實現有差別, 並且差別蠻大的. ext家族是Linux默認的fs了, 事實上ext2/ext3和ext4差別也很大.git
- superblock: 記錄此fs的總體信息, 包括inode/block的總量、使用量、剩餘量, 以及文件系統的格式與相關信息等;
- inode table: superblock以後就是inode table, 存儲了所有inode.
- data block: inode table以後就是data block. 文件的內容保存在這個區域. 磁盤上全部塊的大小都同樣.
- inode: 記錄文件的屬性, 同時記錄此文件的數據所在的block號碼. 每一個inode對應一個文件/目錄的結構, 這個結構它包含了一個文件的長度、建立及修改時間、權限、所屬關係、磁盤中的位置等信息.
- block: 實際記錄文件的內容. 一個較大的文件很容易分佈上千個獨產的磁盤塊中, 並且, 通常都不連續, 太散會致使讀寫性能急劇降低.
好, 我猜你和我同樣是右腦思惟, 上圖就好:windows
能夠看出來, 這是多層索引結構的文件系統. 用b+樹是最佳解決方案, 好比btrfs. inode table指向inode, inode指向一個或者多個block, 注意, 圖中仍是直接指向, 後面還會講述多層指向. 最怕的就是inode指向的block太散. 一個比較好的解決辦法就是在文件末尾不斷添加數據, 而不是新建文件.bash
新建一個文件和文件夾, 用stat指令查看文件信息.數據結構
touch hello
stat hello
mkdir hellodir
stat hellodir
複製代碼
能夠看到一些信息. 例如一個目錄初始大小就是4KB, 8個block, 一個扇區就是512B, 一個io block是4KB, 對應第一幅圖的General Block Device Layer層. 這些其實不看也知道, 前提是這是常規的fs.多線程
建立成功一個文件有4步:函數
- 存儲屬性: 也就是文件屬性的存儲, 內核先找到一塊空的inode. 例如, 以前的1049143. 內核把文件的信息記錄其中. 如文件的大小、文件全部者、和建立時間等, 用stat指令均可以看到.
- 存儲數據: 即文件內容的存儲, 比方創建一個1B的文件, 那一個block, 8個扇區, 內核把數據放到一個空閒邏輯塊中也就是空閒block中. 很明顯, 碎片化的問題已經呈如今這裏了. 1B它也要用4K對吧.
- 記錄分配狀況: 假如數據保存到了3個block中, 位置要記錄到inode的磁盤序號列表中. 這3個編號分別放在最開始的3個位置. 而後讀的時候會一次性讀, 能夠看個人第二張圖. 固然了fat就沒有inode, 它在一個塊中放了下一個塊的位置, 造成鏈, u盤就是這種fs.
- 添加文件名到目錄: 文件名和inode之間的對應關係將文件名和文件以及文件的內容屬性鏈接起來, 找到文件名就找到文件的inode,經過inode就能找到文件的屬性和內容. 換句話說, 就是機器看的和人看的作銜接, 例如網址和ip. 固然, 若是你看inode就能區分文件, 第四步能夠不要(手動滑稽).
目錄的話, 就是多了.文件(指向本身), ..文件(指向上級目錄). 而後添加本身的inode到上級目錄. 看圖就秒懂了.性能
用df指令能夠看inode的總數和使用量.
df -i
複製代碼
dumpe2fs打開指定磁盤能夠看inode的大小, 這裏是256.
inode如何記錄文件而且最大是多少呢? inode記錄block號碼的區域定義爲12個直接, 一個間接, 一個雙間接與一個三間接記錄區. 一個inode是4B, 這樣用4K的block能夠有1K的inode.
- 直接: 12 * 4K
- 間接: (4K / 4) * 4K
- 雙間接: (4K / 4) * (4K / 4) * 4K
- 三間接: (4K / 4) * (4K / 4) * (4K / 4) * 4K
因此的話, 4T, are you OK? 算歸算, fs在不斷髮展, 這是過期的大小了. ext4的話單個文件能夠到達16TB, fs可達1EB. 可是注意, ext4的做者都說了, ext4只是過渡, btrfs會更棒, 那事實上, cent os用的xfs也很很棒.
建立以後固然要打開了, 打開文件也是有一系列過程的. 先來看看兩個指令:
sysctl -a | grep fs.file-max
複製代碼
ulimit -n
複製代碼
- 第一個指令查看os最大打開數, 這是系統級限制.
- 第二個指令查看單進程最大打開數, 這是用戶級限制.
- 爲了管理進程, 操做系統要對每一個進程所作的事情進行清楚地描述, 爲此, 操做系統使用數據結構來表明處理不一樣的實體, 這個數據結構就是一般所說的進程描述符或進程控制塊(PCB). 通俗來說就是操做系統中描述進程的結構體叫作PCB.
- Linux內核經過一個被稱爲進程描述符的task_struct結構體來管理進程, 這個結構體包含了一個進程所需的全部信息. 它定義在include/linux/sched.h文件中. 這不是此次的重點, 可是這個task_struct結構體確實很重要, 也很複雜.
- 每一個進程都會被分配一個task_struct結構, 它包含了這個進程的全部信息, 在任什麼時候候操做系統都能跟蹤這個結構的信息.
文件描述符表(file_struct): 該表記錄進程打開的文件. 它的表項裏面有一個指針, 指向存放在內核空間的文件表中的一個表項. 它向用戶提供一個簡單的文件描述符(fd), 使得用戶能夠經過方便地訪問一個文件. 例如, 當進程使用open打開一個文件時, 內核就會在這個表中添加一個表項. 若是對同一個文件打開屢次, 那麼將有多個表項. 使用dup時, 也會增長一個表項.
文件表: 文件表保存了進程對文件讀寫的偏移量. 該表還保存了進程對文件的存取權限等等. 好比, 進程以O_RDONLY方式打開文件, 這將記錄到對應的文件表表項中. 而後每一個表有一個指向inode table中inode的指針. 結合以前的圖片看, 全部結構就聯繫起來了, 因此inode是核心點.
上圖上圖:
- 在進程A中, 文件描述符1和2都指向了同一個打開的文件表A. 這多是經過調用dup()、dup2()、fcntl()或者對同一個文件屢次調用了open()函數而造成的.
- 進程A的文件描述符0和進程B的文件描述符2都指向了同一個打開的文件表A. 這種情形多是在調用fork()後出現的(即, 進程A、B是父子進程關係), 或者當某進程經過UNIX域套接字將一個打開的文件描述符傳遞給另外一個進程時, 也會發生. 再者是不一樣的進程獨自去調用open函數打開了同一個文件, 此時進程內部的描述符正好分配到與其餘進程打開該文件的描述符同樣.
- 此外, 進程A的描述符0和進程B的描述符255分別指向不一樣的打開文件表, 但這些文件表均指向inode table的相同條目(假設), 也就是指向同一個文件. 發生這種狀況是由於每一個進程各自對同一個文件發起了open()調用。同一個進程兩次打開同一個文件, 也會發生相似狀況.
爲何要說這些狀況呢? 由於若是沒有理解清楚這些, 在作多進程多線程read和write的時候頗有可能會致使讀取和寫入混亂.
看了很是多很棒的文章, 這裏也分享給你們.
- blog.csdn.net/yuexiaxiaox…
- www.ibm.com/developerwo…
- c.biancheng.net/cpp/html/27…
- www.ruanyifeng.com/blog/2011/1…
- www.cnblogs.com/xiaojiang10…
- blog.csdn.net/cywosp/arti…
- blog.csdn.net/luotuo44/ar…
- blog.csdn.net/MBuger/arti…
- blog.csdn.net/u014379540/…
- zhuanlan.zhihu.com/p/34280875
- blog.csdn.net/gatieme/art…
- gityuan.com/2017/07/30/…
此次從結構上逐步往內解剖文件系統, inode是核心點. 固然還有兩篇甚至更多的後續文章, 最後會寫個簡單的用戶態文件系統, 喜歡記得點個贊或者關注我哦~