看完這篇,你應該就知道什麼是Linux了~

Linux的一切皆文件

看完這篇,你應該就知道什麼是Linux了~

Linux 中的各種事物比如像文檔、目錄(Mac OS X 和 Windows 系統下稱之為文件夾)、鍵盤、監視器、硬盤、可移動媒體設備、打印機、調制解調器、虛擬終端,還有進程間通信(IPC)和網絡通信等輸入/輸出資源都是定義在文件系統空間下的字節流。

一切都可看作是文件,其最顯著的好處是對於上面所列出的輸入/輸出資源,只需要相同的一套 Linux 工具、實用程序和 API。你可以使用同一套api(read, write)和工具(cat , 重定向, 管道)來處理unix中大多數的資源.

設計一個系統的終極目標往往就是要找到原子操作,一旦鎖定了原子操作,設計工作就會變得簡單而有序。“文件”作為一個抽象概念,其原子操作非常簡單,只有讀和寫,這無疑是一個非常好的模型。通過這個模型,API的設計可以化繁為簡,用戶可以使用通用的方式去訪問任何資源,自有相應的中間件做好對底層的適配。

現代操作系統為解決信息能獨立於進程之外被長期存儲引入了文件,文件作為進程創建信息的邏輯單元可被多個進程併發使用。在 UNIX 系統中,操作系統為磁盤上的文本與圖像、鼠標與鍵盤等輸入設備及網絡交互等 I/O 操作設計了一組通用 API,使他們被處理時均可統一使用字節流方式。換言之,UNIX 系統中除進程之外的一切皆是文件,而 Linux 保持了這一特性。為了便於文件的管理,Linux 還引入了目錄(有時亦被稱為文件夾)這一概念。目錄使文件可被分類管理,且目錄的引入使 Linux 的文件系統形成一個層級結構的目錄樹

在Linux系統中,一切都是文件,理解文件系統,對於學習Linux來說,是一個非常有必要的前提

Linux上的文件系統一般來說就是EXT2或EXT3,但這篇文章並不準備一上來就直接講它們,而希望結合Linux操作系統並從文件系統建立的基礎——硬盤開始,一步步認識Linux的文件系統。

1. 機械硬盤的物理存儲機制

  • 現代計算機大部分文件存儲功能都是由機械硬盤這種設備提供的。(現在的SSD和閃存從概念和邏輯上都部分繼承自機械硬盤,所以使用機械硬盤來進行理解也是沒有問題的)
  • 機械硬盤能實現信息存儲的功能基於:磁性存儲介質能夠被磁化,且磁化後會長久保留被磁化的狀態,這種被磁化狀態能夠被讀取出來,同時這種磁化狀態還能夠不斷被修改,磁化正好有兩個方向,所以可以表示0和1。
  • 於是硬盤就是把這種磁性存儲介質做成一個個盤片,每一個盤片上都分佈著數量巨大的磁性存儲單位,使用磁性讀寫頭對盤片進行寫入和讀取(從原理上類似黑膠唱片的播放)。
  • 一個硬盤中的磁性存儲單位數以億計(1T硬盤就有約80億個),所以需要一套規則來規劃信息如何存取(比如一本存儲信息的書我們還會分為頁,每一頁從上到下從左到右讀取,同時還有章節目錄)
  • 於是就有了這些物理、邏輯概念:
  • 一個硬盤有多張盤片疊成,不同盤片有編號
  • 每張盤片上的存儲顆粒成環形一圈圈地排布,每一圈稱為磁道,有編號
  • 每條磁道上都有一圈存儲顆粒,每512*8(512字節,0.5KB)個存儲顆粒作為一個扇區,扇區是硬盤上存儲的最小物理單位
  • N個扇區可以組成簇,N取決於不同的文件系統或是文件系統的配置,簇是此文件系統中的最小存儲單位
  • 所有盤面上的同一磁道構成一個圓柱,稱為柱面,柱面是系統分區的最小單位
看完這篇,你應該就知道什麼是Linux了~


磁頭讀寫文件的時候,首先是分區讀寫的,由inode編號(區內唯一的編號後面介紹)找到對應的磁道和扇區,然後一個柱面一個柱面地進行讀寫。機械硬盤的讀寫控制系統是一個令人歎為觀止的精密工程(一個盤面上有幾億個存儲單位,每個磁道寬度不到幾十納米,磁盤每分鐘上萬轉),同時關於讀寫的邏輯也是有諸多細節(比如扇區的編號並不是連續的),非常有意思,可以自行搜索文章拓展閱讀。有了硬盤並不意味著LInux可以立刻把它用來存儲,還需要組合進Linux的文件體系才能被Linux使用。

2.Linux文件體系

Linux以文件的形式對計算機中的數據和硬件資源進行管理,也就是徹底的一切皆文件,反映在Linux的文件類型上就是:普通文件、目錄文件(也就是文件夾)、設備文件、鏈接文件、管道文件、套接字文件(數據通信的接口)等等。而這些種類繁多的文件被Linux使用目錄樹進行管理, 所謂的目錄樹就是以根目錄(/)為主,向下呈現分支狀的一種文件結構。不同於純粹的ext2之類的文件系統,我把它稱為文件體系,一切皆文件和文件目錄樹的資源管理方式一起構成了Linux的文件體系,讓Linux操作系統可以方便使用系統資源。

所以文件系統比文件體系涵蓋的內容少很多,Linux文件體系主要在於把操作系統相關的東西用文件這個載體實現:文件系統掛載在操作系統上,操作系統整個系統又放在文件系統裡。但本文中文件體系的相關內容不是很多,大部分地方都可以用文件系統代替文件體系。

1. Linux中的文件類型:

1.1. 普通文件(-)

從Linux的角度來說,類似mp4、pdf、html這樣應用層面上的文件類型都屬於普通文件

Linux用戶可以根據訪問權限對普通文件進行查看、更改和刪除

1.2. 目錄文件(d,directory file)

目錄文件對於用慣Windows的用戶來說不太容易理解,目錄也是文件的一種

目錄文件包含了各自目錄下的文件名和指向這些文件的指針,打開目錄事實上就是打開目錄文件,只要有訪問權限,你就可以隨意訪問這些目錄下的文件(普通文件的執行權限就是目錄文件的訪問權限),但是隻有內核的進程能夠修改它們

雖然不能修改,但是我們能夠通過vim去查看目錄文件的內容

1.3. 符號鏈接(l,symbolic link)

這種類型的文件類似Windows中的快捷方式,是指向另一個文件的間接指針,也就是我們常說的軟鏈接

1.4. 塊設備文件(b,block)和字符設備文件(c,char)

這些文件一般隱藏在/dev目錄下,在進行設備讀取和外設交互時會被使用到

比如磁盤光驅就是塊設備文件,串口設備則屬於字符設備文件

系統中的所有設備要麼是塊設備文件,要麼是字符設備文件,無一例外

1.5. FIFO(p,pipe)

管道文件主要用於進程間通訊。比如使用mkfifo命令可以創建一個FIFO文件,啟用一個進程A從FIFO文件裡讀數據,啟動進程B往FIFO裡寫數據,先進先出,隨寫隨讀。

1.6. 套接字(s,socket)

用於進程間的網絡通信,也可以用於本機之間的非網絡通信

這些文件一般隱藏在/var/run目錄下,證明著相關進程的存在

Linux 的文件是沒有所謂的擴展名的,一個 Linux文件能不能被執行與它是否可執行的屬性有關,只要你的權限中有 x ,比如[ -rwx-r-xr-x ] 就代表這個文件可以被執行,與文件名沒有關係。跟在 Windows下能被執行的文件擴展名通常是 .com .exe .bat 等不同。

不過,可以被執行跟可以執行成功不一樣。比如在 root 主目彔下的 install.log 是一個文本文件,修改權限成為 -rwxrwxrwx 後這個文件能夠真的執行成功嗎? 當然不行,因為它的內容根本就沒有可以執行的數據。所以說,這個 x 代表這個文件具有可執行的能力, 但是能不能執行成功,當然就得要看該文件的內容了。

雖然如此,不過我們仍然希望能從擴展名來了解該文件是什麼東西,所以一般我們還是會以適當的擴展名來表示該文件是什麼種類的。

所以Linux 系統上的文件名真的只是讓你瞭解該文件可能的用途而已, 真正的執行與否仍然需要權限的規範才行。比如常見的/bin/ls 這個顯示文件屬性的指令要是權限被修改為無法執行,那麼ls 就變成不能執行了。這種問題最常發生在文件傳送的過程中。例如你在網絡上下載一個可執行文件,但是偏偏在你的 Linux 系統中就是無法執行,那就可能是檔案的屬性被改變了。而且從網絡上傳送到你 的 Linux 系統中,文件的屬性權限確實是會被改變的

2. Linux目錄樹

對Linux系統和用戶來說,所有可操作的計算機資源都存在於目錄樹這個邏輯結構中,對計算機資源的訪問都可以認為是目錄樹的訪問。就硬盤來說,所有對硬盤的訪問都變成了對目錄樹中某個節點也就是文件夾的訪問,訪問時不需要知道它是硬盤還是硬盤中的文件夾。

目錄樹的邏輯結構也非常簡單,就是從根目錄(/)開始,不斷向下展開各級子目錄。

3.硬盤分區

硬盤分區是硬盤結合到文件體系的第一步,本質是「硬盤」這個物理概念轉換成「區」這個邏輯概念,為下一步格式化做準備。

所以分本身並不是必須的,你完全可以把一整塊硬盤作為一個區。但從數據的安全性以及系統性能角度來看,分區還是有很多用處的,所以一般都會對硬盤進行分區。

講分區就不得不先提每塊硬盤上最重要的第一扇區,這個扇區中有硬盤主引導記錄(Master boot record, MBR) 及分區表(partition table), 其中 MBR 佔有 446 bytes,而分區表佔有 64 bytes。硬盤主引導記錄放有最基本的引導加載程序,是系統開機啟動的關鍵環節,在附錄中有更詳細的說明。而分區表則跟分區有關,它記錄了硬盤分區的相關信息,但因分區表僅有 64bytes , 所以最多隻能記彔四塊分區(分區本身其實就是對分區表進行設置)。

只能分四個區實在太少了,於是就有了擴展分區的概念,既然第一個扇區所在的分區表只能記錄四條數據, 那我可否利用額外的扇區來記錄更多的分區信息。

把普通可以訪問的分區稱為主分區,擴展分區不同於主分區,它本身並沒有內容,它是為進一步邏輯分區提供空間的。在某塊分區指定為擴展分區後,就可以對這塊擴展分區進一步分成多個邏輯分區。操作系統規定:

  1. 四塊分區每塊都可以是主分區或擴展分區
  2. 擴展分區最多隻能有一個(也沒必要有多個)
  3. 擴展分區可以進一步分割為多個邏輯分區
  4. 擴展分區只是邏輯概念,本身不能被訪問,也就是不能被格式化後作為數據訪問的分區,能夠作為數據訪問的分區只有主分區和邏輯分區
  5. 邏輯分區的數量依操作系統而不同,在 Linux 系統中,IDE 硬盤最多有 59 個邏輯分區(5 號到 63 號), SATA 硬盤則有 11 個邏輯分區(5 號到 15 號)
  6. 一般給硬盤進行分區時,一個主分區一個擴展分區,然後把擴展分區劃分為N個邏輯分區是最好的

是否可以不要主分區呢?不知道,但好像不用管,你創建分區的時候會自動給你配置類型

特殊的,你最好單獨分一個swap區(內存置換空間),它獨為一類,功能是:當有數據被存放在物理內存裡面,但是這些數據又不是常被 CPU 所取用時,那麼這些不常被使用的程序將會被丟到硬盤的 swap 置換空間當中, 而將速度較快的物理內存空間釋放出來給真正需要的程序使用

4.格式化

我們知道Linux操作系統支持很多不同的文件系統,比如ext2、ext3、XFS、FAT等等,而Linux把對不同文件系統的訪問交給了VFS(虛擬文件系統),VFS能訪問和管理各種不同的文件系統。所以有了區之後就需要把它格式化成具體的文件系統以便VFS訪問。

標準的Linux文件系統Ext2是使用「基於inode的文件系統」

我們知道一般操作系統的文件數據除了文件實際內容外, 還帶有很多屬性,例如 Linux 操作系統的文件權限(rwx)與文件屬性(擁有者、群組、 時間參數等),文件系統通常會將屬性和實際內容這兩部分數據分別存放在不同的區塊

在基於inode的文件系統中,權限與屬性放置到 inode 中,實際數據放到 data block 區塊中,而且inode和data block都有編號

Ext2 文件系統在此基礎上

文件系統最前面有一個啟動扇區(boot sector)

這個啟動扇區可以安裝開機管理程序, 這個設計讓我們能將不同的引導裝載程序安裝到個別的文件系統前端,而不用覆蓋整個硬盤唯一的MBR, 也就是這樣才能實現多重引導的功能

把每個區進一步分為多個塊組 (block group),每個塊組有獨立的inode/block體系

如果文件系統高達數百 GB 時,把所有的 inode 和block 通通放在一起會因為 inode 和 block的數量太龐大,不容易管理

這其實很好理解,因為分區是用戶的分區,實際計算機管理時還有個最適合的大小,於是計算機會進一步的在分區中分塊

(但這樣豈不是可能出現大文件放不了的問題?有什麼機制善後嗎?)

每個塊組實際還會分為分為6個部分,除了inode table 和 data block外還有4個附屬模塊,起到優化和完善系統性能的作用

所以整個分區大概會這樣劃分:


看完這篇,你應該就知道什麼是Linux了~


1. inode table

主要記錄文件的屬性以及該文件實際數據是放置在哪些block中,它記錄的信息至少有這些:

大小、真正內容的block號碼(一個或多個)

訪問模式(read/write/excute)

擁有者與群組(owner/group)

各種時間:建立或狀態改變的時間、最近一次的讀取時間、最近修改的時間

沒有文件名!文件名在目錄的block中!

一個文件佔用一個 inode,每個inode有編號

Linux 系統存在 inode 號被用完但磁盤空間還有剩餘的情況

注意,這裡的文件不單單是普通文件,目錄文件也就是文件夾其實也是一個文件,還有其他的也是

inode 的數量與大小在格式化時就已經固定了,每個inode 大小均固定為128 bytes (新的ext4 與xfs 可設定到256 bytes)

文件系統能夠建立的文件數量與inode 的數量有關,存在空間還夠但inode不夠的情況

系統讀取文件時需要先找到inode,並分析inode 所記錄的權限與使用者是否符合,若符合才能夠開始實際讀取 block 的內容

inode 要記錄的資料非常多,但偏偏又只有128bytes , 而inode 記錄一個block 號碼要花掉4byte ,假設我一個文件有400MB 且每個block 為4K 時, 那麼至少也要十萬條block 號碼的記錄!inode 哪有這麼多空間來存儲?為此我們的系統很聰明的將inode 記錄block 號碼的區域定義為12個直接,一個間接, 一個雙間接與一個三間接記錄區(詳細見附錄)

2. data block

放置文件內容數據的地方

在格式化時block的大小就固定了,且每個block都有編號,以方便inode的記錄

原則上,block 的大小與數量在格式化完就不能夠再改變了(除非重新格式化)

在Ext2文件系統中所支持的block大小有1K, 2K及4K三種,由於block大小的區別,會導致該文件系統能夠支持的最大磁盤容量與最大單一文件容量各不相同:

Block 大小 1KB 2KB 4KB

最大單一檔案限制 16GB 256GB 2TB

最大檔案系統總容量 2TB 8TB 16TB

每個block 內最多隻能夠放置一個文件的資料,但一個文件可以放在多個block中(大的話)

若文件小於block ,則該block 的剩餘容量就不能夠再被使用了(磁盤空間會浪費)

所以如果你的檔案都非常小,但是你的block 在格式化時卻選用最大的4K 時,可能會產生容量的浪費

既然大的block 可能會產生較嚴重的磁碟容量浪費,那麼我們是否就將block 大小定為1K ?這也不妥,因為如果block 較小的話,那麼大型檔案將會佔用數量更多的block ,而inode 也要記錄更多的block 號碼,此時將可能導致檔案系統不良的讀寫效能

事實上現在的磁盤容量都太大了,所以一般都會選擇4K 的block 大小

3. superblock

記錄整個文件系統相關信息的地方,一般大小為1024bytes,記錄的信息主要有:

block 與inode 的總量

未使用與已使用的inode / block 數量

一個valid bit 數值,若此文件系統已被掛載,則valid bit 為0 ,若未被掛載,則valid bit 為1

block 與inode 的大小 (block 為1, 2, 4K,inode 為128bytes 或256bytes);

其他各種文件系統相關信息:filesystem 的掛載時間、最近一次寫入資料的時間、最近一次檢驗磁碟(fsck) 的時間

Superblock是非常重要的, 沒有Superblock ,就沒有這個文件系統了,因此如果superblock死掉了,你的文件系統可能就需要花費很多時間去挽救

每個塊都可能含有superblock,但是我們也說一個文件系統應該僅有一個superblock 而已,那是怎麼回事?事實上除了第一個塊內會含有superblock 之外,後續的塊不一定含有superblock,而若含有superblock則該superblock主要是做為第一個塊內superblock的備份,這樣可以進行superblock的救援

4. Filesystem Description

文件系統描述

這個區段可以描述每個block group的開始與結束的block號碼,以及說明每個區段(superblock, bitmap, inodemap, data block)分別介於哪一個block號碼之間

5. block bitmap

塊對照表

如果你想要新增文件時要使用哪個block 來記錄呢?當然是選擇「空的block」來記錄。那你怎麼知道哪個block 是空的?這就得要通過block bitmap了,它會記錄哪些block是空的,因此我們的系統就能夠很快速的找到可使用的空間來記錄

同樣在你刪除某些文件時,那些文件原本佔用的block號碼就得要釋放出來, 此時在block bitmap 中對應該block號碼的標誌位就得要修改成為「未使用中」

6. inode bitmap

與block bitmap 是類似的功能,只是block bitmap 記錄的是使用與未使用的block 號碼, 至於inode bitmap 則是記錄使用與未使用的inode 號碼

5.掛載

在一個區被格式化為一個文件系統之後,它就可以被Linux操作系統使用了,只是這個時候Linux操作系統還找不到它,所以我們還需要把這個文件系統「註冊」進Linux操作系統的文件體系裡,這個操作就叫「掛載」 (mount)。

掛載是利用一個目錄當成進入點(類似選一個現成的目錄作為代理),將文件系統放置在該目錄下,也就是說,進入該目錄就可以讀取該文件系統的內容,類似整個文件系統只是目錄樹的一個文件夾(目錄)。

這個進入點的目錄我們稱為「掛載點」。

由於整個 Linux 系統最重要的是根目錄,因此根目錄一定需要掛載到某個分區。 而其他的目錄則可依用戶自己的需求來給予掛載到不同的分去。

到這裡Linux的文件體系的構建過程其實已經大體講完了,總結一下就是:硬盤經過分區和格式化,每個區都成為了一個文件系統,掛載這個文件系統後就可以讓Linux操作系統通過VFS訪問硬盤時跟訪問一個普通文件夾一樣。這裡通過一個在目錄樹中讀取文件的實際例子來細講一下目錄文件和普通文件。

6.目錄樹的讀取過程

首先我們要知道

  1. 每個文件(不管是一般文件還是目錄文件)都會佔用一個inode
  2. 依據文件內容的大小來分配一個或多個block給該文件使用
  3. 創建一個文件後,文件完整信息分佈在3處地方,生成2個新文件:
  4. 3.1 文件名記錄在該文件所在目錄的目錄文件的block中,沒有新文件生成
  5. 3.2 文件屬性、權限信息、記錄具體內容的block編號記錄在inode中,inode是新生成文件
  6. 3.3 文件具體內存記錄在block中,block是新生成文件
  7. 因為文件名的記錄是在目錄的block當中,「新增/刪除/更名文件名」與目錄的w權限有關
  8. 所以在Linux/Unix中,文件名稱只是文件的一個屬性,叫別名也好,叫綽號也罷,僅為了方便用戶記憶和使用,但系統內部並不需要用文件名來定為文件位置,這樣處理最直觀的好處就是,你可以對正在使用的文件改名,換目錄,甚至放到廢紙簍,都不會影響當前文件的使用,這在Windows裡是無法想象的。比如你打開個Word文件,然後對其進行重命名操作,Windows會告訴你門兒都沒有,關閉文件先!但在Mac裡就毫無壓力,因為Mac的操作系統同樣採用了inode的設計。

創建文件過程

當在ext2下建立一個一般文件時, ext2 會分配一個inode 與相對於該文件大小的block 數量給該文件

  1. 例如:假設我的一個block 為4 Kbytes ,而我要建立一個100 KBytes 的文件,那麼linux 將分配一個inode 與25 個block 來儲存該文件
  2. 但同時請注意,由於inode 僅有12 個直接指向,因此還要多一個block 來作為區塊號碼的記錄


創建目錄過程

當在ext2文件系統建立一個目錄時(就是新建了一個目錄文件),文件系統會分配一個inode與至少一塊block給該目錄

  1. inode記錄該目錄的相關權限與屬性,並記錄分配到的那塊block號碼
  2. 而block則是記錄在這個目錄下的文件名與該文件對應的inode號
  3. block中還會自動生成兩條記錄,一條是.文件夾記錄,inode指向自身,另一條是..文件夾記錄,inode指向父文件夾

從目錄樹中讀取某個文件過程

  1. 因為文件名是記錄在目錄的block當中,因此當我們要讀取某個文件時,就一定會經過目錄的inode與block ,然後才能夠找到那個待讀取文件的inode號碼,最終才會讀到正確的文件的block內的資料。
  2. 由於目錄樹是由根目錄開始,因此操作系統先通過掛載信息找到掛載點的inode號,由此得到根目錄的inode內容,並依據該inode讀取根目錄的block信息,再一層一層的往下讀到正確的文件。
  3. 舉例來說,如果我想要讀取/etc/passwd 這個文件時,系統是如何讀取的呢?
  4. 先看一下這個文件以及有關路徑文件夾的信息:
1$ ll -di / /etc /etc/passwd
2 128 dr-xr-x r-x . 17 root root 4096 May 4 17:56 /
333595521 drwxr-x r-x . 131 root root 8192 Jun 17 00:20 /etc
436628004 -rw-r-- r-- . 1 root root 2092 Jun 17 00:20 /etc/passwd

於是該文件的讀取流程為:

  1. /的inode:
  2. 通過掛載點的信息找到inode號碼為128的根目錄inode,且inode規定的權限讓我們可以讀取該block的內容(有r與x)
  3. /的block:
  4. 經過上個步驟取得block的號碼,並找到該內容有etc/目錄的inode號碼(33595521)
  5. etc/的inode:
  6. 讀取33595521號inode得知具有r與x的權限,因此可以讀取etc/的block內容
  7. etc/的block:
  8. 經過上個步驟取得block號碼,並找到該內容有passwd文件的inode號碼(36628004)
  9. passwd的inode:
  10. 讀取36628004號inode得知具有r的權限,因此可以讀取passwd的block內容
  11. passwd的block:
  12. 最後將該block內容的資料讀出來


分享到:


相關文章: