Linux文件系統詳解


從操作系統的角度詳解Linux文件系統層次、文件系統分類、文件系統的存儲結構、不同存儲介質的區別(RAM、ROM、Flash)、存儲節點inode。本文參考

http://blog.chinaunix.net/uid-8698570-id-1763151.html
http://www.iteye.com/topic/816268
http://soft.chinabyte.com/os/142/12315142.shtml
http://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/
http://blog.csdn.net/kension/article/details/3796603
http://www.360doc.com/content/11/0915/17/3200886_148505332.shtml
 

 

LINUX系統中有一個重要的概念:一切都是文件。 其實這是UNIX哲學的一個體現,而Linux是重寫UNIX而來,所以這個概念也就傳承了下來。在UNIX系統中,把一切資源都看作是文件,包括硬件設備。UNIX系統把每個硬件都看成是一個文件,通常稱為設備文件,這樣用戶就可以用讀寫文件的方式實現對硬件的訪問。這樣帶來優勢也是顯而易見的:

         UNIX 權限模型也是圍繞文件的概念來建立的,所以對設備也就可以同樣處理了。
 

  1. 硬盤驅動

  常見的硬盤類型有PATA, SATA和AHCI等,在Linux系統中,對不同硬盤所提供的驅動模塊一般都存放在內核目錄樹drivers/ata中,而對於一般通用的硬盤驅動,也許會直接被編譯到內核中,而不會以模塊的方式出現,可以通過查看/boot/config-xxx.xxx文件來確認:

  CONFIG_SATA_AHCI=y

  2. General Block Device Layer

  這一層的作用,正是解答了上面提出的第一個問題,不同的硬盤驅動,會提供不同的IO接口,內核認為這種雜亂的接口,不利於管理,需要把這些接口抽象一下,形成一個統一的對外接口,這樣,不管你是什么硬盤,什么驅動,對外而言,它們所提供的IO接口沒什么區別,都一視同仁的被看作塊設備來處理。

  所以,如果在一層做的任何修改,將會直接影響到所有文件系統,不管是ext3,ext4還是其它文件系統,只要在這一層次做了某種修改,對它們都會產生影響。

  3. 文件系統

  文件系統這一層相信大家都再熟悉不過了,目前大多Linux發行版本默認使用的文件系統一般是ext4,另外,新一代的btrfs也呼之欲出,不管什么樣的文件系統,都是由一系列的mkfs.xxx命令來創建,如:

  mkfs.ext4 /dev/sda

  mkfs.btrfs /dev/sdb

  內核所支持的文件系統類型,可以通過內核目錄樹 fs 目錄中的內容來查看。

  4. 虛擬文件系統(VFS)

  Virtual File System這一層,正是用來解決上面提出的第二個問題,試想,當我們通過mkfs.xxx系列命令創建了很多不同的文件系統,但這些文件系統都有各自的API接口,而用戶想要的是,不管你是什么API,他們只關心mount/umount,或open/close等操作。

  所以,VFS就把這些不同的文件系統做一個抽象,提供統一的API訪問接口,這樣,用戶空間就不用關心不同文件系統中不一樣的API了。VFS所提供的這些統一的API,再經過System Call包裝一下,用戶空間就可以經過SCI的系統調用來操作不同的文件系統。

  VFS所提供的常用API有:

  mount(), umount() …

  open(),close() …

  mkdir() …
 

     和文件系統關系最密切的就是存儲介質,存儲介質大致有RAM,ROM,磁盤磁帶,閃存等。

     閃存(Flash Memory)是一種長壽命的非易失性(在斷電情況下仍能保持所存儲的數據信息)的存儲器,數據刪除不是以單個的字節為單位而是以固定的區塊為單位(注意:NOR Flash 為字節存儲。),區塊大小一般為256KB到20MB。閃存是電子可擦除只讀存儲器(EEPROM)的變種,EEPROM與閃存不同的是,它能在字節水平上進行刪除和重寫而不是整個芯片擦寫,這樣閃存就比EEPROM的更新速度快。由於其斷電時仍能保存數據,閃存通常被用來保存設置信息,如在電腦的BIOS(基本輸入輸出程序)、PDA(個人數字助理)、數碼相機中保存資料等。
     外存通常是磁性介質或光盤,像硬盤,軟盤,磁帶,CD等,能長期保存信息,並且不依賴於電來保存信息,但是由機械部件帶動,速度與CPU相比就顯得慢的多。內存指的就是主板上的存儲部件,是CPU直接與之溝通,並用其存儲數據的部件,存放當前正在使用的(即執行中)的數據和程序,它的物理實質就是一組或多組具備數據輸入輸出和數據存儲功能的集成電路,內存只用於暫時存放程序和數據,一旦關閉電源或發生斷電,其中的程序和數據就會丟失。
     RAM又分為動態的和靜態。。靜態被用作cache,動態的常用作內存。。網上說閃存不能代替DRAM是因為閃存不像RAM(隨機存取存儲器)一樣以字節為單位改寫數據,因此不能取代RAM。這個以后可以了解下硬件的知識再來辨別.
 

  Linux下的文件系統結構如下:

  Linux啟動時,第一個必須掛載的是根文件系統;若系統不能從指定設備上掛載根文件系統,則系統會出錯而退出啟動。之后可以自動或手動掛載其他的文件系統。因此,一個系統中可以同時存在不同的文件系統。
  不同的文件系統類型有不同的特點,因而根據存儲設備的硬件特性、系統需求等有不同的應用場合。在嵌入式Linux應用中,主要的存儲設備為RAM(DRAM, SDRAM)和ROM(常采用FLASH存儲器),常用的基於存儲設備的文件系統類型包括:jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs等。
  1. 基於FLASH的文件系統
  Flash(閃存)作為嵌入式系統的主要存儲媒介,有其自身的特性。 Flash的寫入操作只能把對應位置的1修改為0,而不能把0修改為1(擦除Flash就是把對應存儲塊的內容恢復為1),因此,一般情況下,向Flash寫入內容時,需要先擦除對應的存儲區間,這種擦除是以塊(block)為單位進行的。
 閃存主要有NOR和NAND兩種技術。Flash存儲器的擦寫次數是有限的,NAND閃存還有特殊的硬件接口和讀寫時序。因此,必須針對Flash的硬件特性設計符合應用要求的文件系統;傳統的文件系統如ext2等,用作Flash的文件系統會有諸多弊端。
  在嵌入式Linux下,MTD(Memory Technology Device,存儲技術設備)為底層硬件(閃存)和上層(文件系統)之間提供一個統一的抽象接口,即Flash的文件系統都是基於MTD驅動層的(參見上面的Linux下的文件系統結構圖)。使用MTD驅動程序的主要優點在於,它是專門針對各種非易失性存儲器(以閃存為主)而設計的,因而它對Flash有更好的支持、管理和基於扇區的擦除、讀/寫操作接口。
  順便一提,一塊Flash芯片可以被划分為多個分區,各分區可以采用不同的文件系統;兩塊Flash芯片也可以合並為一個分區使用,采用一個文件系統。即文件系統是針對於存儲器分區而言的,而非存儲芯片。
  (1) jffs2
  JFFS文件系統最早是由瑞典Axis Communications公司基於Linux2.0的內核為嵌入式系統開發的文件系統。JFFS2是RedHat公司基於JFFS開發的閃存文件系統,最初是針對RedHat公司的嵌入式產品eCos開發的嵌入式文件系統,所以JFFS2也可以用在Linux, uCLinux中。
  Jffs2: 日志閃存文件系統版本2 (Journalling Flash FileSystem v2)
  主要用於NOR型閃存,基於MTD驅動層,特點是:可讀寫的、支持數據壓縮的、基於哈希表的日志型文件系統,並提供了崩潰/掉電安全保護,提供“寫平衡”支持等。缺點主要是當文件系統已滿或接近滿時,因為垃圾收集的關系而使jffs2的運行速度大大放慢。
  目前jffs3正在開發中。關於jffs系列文件系統的使用詳細文檔,可參考MTD補丁包中mtd-jffs-HOWTO.txt。
  jffsx不適合用於NAND閃存主要是因為NAND閃存的容量一般較大,這樣導致jffs為維護日志節點所占用的內存空間迅速增大,另外,jffsx文件系統在掛載時需要掃描整個FLASH的內容,以找出所有的日志節點,建立文件結構,對於大容量的NAND閃存會耗費大量時間。
   (2) yaffs:Yet Another Flash File System
  yaffs/yaffs2是專為嵌入式系統使用NAND型閃存而設計的一種日志型文件系統。與jffs2相比,它減少了一些功能(例如不支持數據壓縮),所以速度更快,掛載時間很短,對內存的占用較小。另外,它還是跨平台的文件系統,除了Linux和eCos,還支持WinCE, pSOS和ThreadX等。
  yaffs/yaffs2自帶NAND芯片的驅動,並且為嵌入式系統提供了直接訪問文件系統的API,用戶可以不使用Linux中的MTD與VFS,直接對文件系統操作。當然,yaffs也可與MTD驅動程序配合使用。
  yaffs與yaffs2的主要區別在於,前者僅支持小頁(512 Bytes) NAND閃存,后者則可支持大頁(2KB) NAND閃存。同時,yaffs2在內存空間占用、垃圾回收速度、讀/寫速度等方面均有大幅提升。
  (3) Cramfs:Compressed ROM File System
  Cramfs是Linux的創始人 Linus Torvalds參與開發的一種只讀的壓縮文件系統。它也基於MTD驅動程序。
  在cramfs文件系統中,每一頁(4KB)被單獨壓縮,可以隨機頁訪問,其壓縮比高達2:1,為嵌入式系統節省大量的Flash存儲空間,使系統可通過更低容量的FLASH存儲相同的文件,從而降低系統成本。
  Cramfs文件系統以壓縮方式存儲,在運行時解壓縮,所以不支持應用程序以XIP方式運行,所有的應用程序要求被拷到RAM里去運行,但這並不代表比Ramfs需求的RAM空間要大一點,因為Cramfs是采用分頁壓縮的方式存放檔案,在讀取檔案時,不會一下子就耗用過多的內存空間,只針對目前實際讀取的部分分配內存,尚沒有讀取的部分不分配內存空間,當我們讀取的檔案不在內存時,Cramfs文件系統自動計算壓縮后的資料所存的位置,再即時解壓縮到RAM中。
  另外,它的速度快,效率高,其只讀的特點有利於保護文件系統免受破壞,提高了系統的可靠性。
  由於以上特性,Cramfs在嵌入式系統中應用廣泛。
  但是它的只讀屬性同時又是它的一大缺陷,使得用戶無法對其內容對進擴充。?
  Cramfs映像通常是放在Flash中,但是也能放在別的文件系統里,使用loopback 設備可以把它安裝別的文件系統里。
  (4) Romfs
  傳統型的Romfs文件系統是一種簡單的、緊湊的、只讀的文件系統,不支持動態擦寫保存,按順序存放數據,因而支持應用程序以XIP(eXecute In Place,片內運行)方式運行,在系統運行時,節省RAM空間。uClinux系統通常采用Romfs文件系統。
  其他文件系統:fat/fat32也可用於實際嵌入式系統的擴展存儲器(例如PDA, Smartphone, 數碼相機等的SD卡),這主要是為了更好的與最流行的Windows桌面操作系統相兼容。ext2也可以作為嵌入式Linux的文件系統,不過將它用於FLASH閃存會有諸多弊端。
  2. 基於RAM的文件系統
  (1) Ramdisk
  Ramdisk是將一部分固定大小的內存當作分區來使用。它並非一個實際的文件系統,而是一種將實際的文件系統裝入內存的機制,並且可以作為根文件系統。將一些經常被訪問而又不會更改的文件(如只讀的根文件系統)通過Ramdisk放在內存中,可以明顯地提高系統的性能。
  在Linux的啟動階段,initrd提供了一套機制,可以將內核映像和根文件系統一起載入內存。
  (2)ramfs/tmpfs
  Ramfs是Linus Torvalds開發的一種基於內存的文件系統,工作於虛擬文件系統(VFS)層,不能格式化,可以創建多個,在創建時可以指定其最大能使用的內存大小。(實際上,VFS本質上可看成一種內存文件系統,它統一了文件在內核中的表示方式,並對磁盤文件系統進行緩沖。)
  Ramfs/tmpfs文件系統把所有的文件都放在RAM中,所以讀/寫操作發生在RAM中,可以用ramfs/tmpfs來存儲一些臨時性或經常要修改的數據,例如/tmp和/var目錄,這樣既避免了對Flash存儲器的讀寫損耗,也提高了數據讀寫速度。
  Ramfs/tmpfs相對於傳統的Ramdisk的不同之處主要在於:不能格式化,文件系統大小可隨所含文件內容大小變化。
  Tmpfs的一個缺點是當系統重新引導時會丟失所有數據。
  3. 網絡文件系統NFS (Network File System)
  NFS是由Sun開發並發展起來的一項在不同機器、不同操作系統之間通過網絡共享文件的技術。在嵌入式Linux系統的開發調試階段,可以利用該技術在主機上建立基於NFS的根文件系統,掛載到嵌入式設備,可以很方便地修改根文件系統的內容。
  以上討論的都是基於存儲設備的文件系統(memory-based file system),它們都可用作Linux的根文件系統。實際上,Linux還支持邏輯的或偽文件系統(logical or pseudo file system),例如procfs(proc文件系統),用於獲取系統信息,以及devfs(設備文件系統)和sysfs,用於維護設備文件。
  附錄:NOR閃存與NAND閃存比較
NOR FLASH
接口時序同SRAM,易使用
讀取速度較快
擦除速度慢,以64-128KB的塊為單位
寫入速度慢(因為一般要先擦除)
隨機存取速度較快,支持XIP(eXecute In Place,芯片內執行),適用於代碼存儲。在嵌入式系統中,常用於存放引導程序、根文件系統等。
單片容量較小,1-32MB
最大擦寫次數10萬次

NAND FLASH
地址/數據線復用,數據位較窄
讀取速度較慢
擦除速度快,以8-32KB的塊為單位
寫入速度快
順序讀取速度較快,隨機存取速度慢,適用於數據存儲(如大容量的多媒體應用)。在嵌入式系統中,常用於存放用戶文件系統等。
單片容量較大,8-128MB,提高了單元密度
 
 
三、文件存儲結構
 
介紹文件存儲結構前先來看看文件系統如何划分磁盤,創建一個文件、目錄、鏈接的過程。
 
1.物理磁盤到文件系統
我們知道文件最終是保存在硬盤上的。硬盤最基本的組成部分是由堅硬金屬材料制成的塗以磁性介質的盤片,不同容量硬盤的盤片數不等。每個盤片有兩面,都可記錄信息。盤片被分成許多扇形的區域,每個區域叫一個扇區,每個扇區可存儲128×2的N次方(N=0.1.2.3)字節信息。在DOS中每扇區是128×2的2次方=512字節,盤片表面上以盤片中心為圓心,不同半徑的同心圓稱為磁道。硬盤中,不同盤片相同半徑的磁道所組成的圓柱稱為柱面。磁道與柱面都是表示不同半徑的圓,在許多場合,磁道和柱面可以互換使用,我們知道,每個磁盤有兩個面,每個面都有一個磁頭,習慣用磁頭號來區分。扇區,磁道(或柱面)和磁頭數構成了硬盤結構的基本參數,幫這些參數可以得到硬盤的容量,基計算公式為:
存儲容量=磁頭數×磁道(柱面)數×每道扇區數×每扇區字節數
要點:
(1)硬盤有數個盤片,每盤片兩個面,每個面一個磁頭
(2)盤片被划分為多個扇形區域即扇區
(3)同一盤片不同半徑的同心圓為磁道
(4)不同盤片相同半徑構成的圓柱面即柱面
(5)公式: 存儲容量=磁頭數×磁道(柱面)數×每道扇區數×每扇區字節數
(6)信息記錄可表示為:××磁道(柱面),××磁頭,××扇區
那么這些空間又是怎么管理起來的呢?unix/linux使用了一個簡單的方法。 
它將磁盤塊分為以下三個部分:
1)        超級塊,文件系統中第一個塊被稱為超級塊。這個塊存放文件系統本身的結構信息。比如,超級塊記錄了每個區域的大小,超級塊也存放未被使用的磁盤塊的信息。
2)        I-切點表。超級塊的下一個部分就是i-節點表。每個i-節點就是一個對應一個文件/目錄的結構,這個結構它包含了一個文件的長度、創建及修改時間、權限、所屬關系、磁盤中的位置等信息。一個文件系統維護了一個索引節點的數組,每個文件或目錄都與索引節點數組中的唯一一個元素對應。系統給每個索引節點分配了一個號碼,也就是該節點在數組中的索引號,稱為索引節點號
3)        數據區。文件系統的第3個部分是數據區。文件的內容保存在這個區域。磁盤上所有塊的大小都一樣。如果文件包含了超過一個塊的內容,則文件內容會存放在多個磁盤塊中。一個較大的文件很容易分布上千個獨產的磁盤塊中。
 
Linux正統的文件系統(如ext2、ext3)一個文件由目錄項、inode和數據塊組成。
目錄項:包括文件名和inode節點號。
Inode:又稱文件索引節點,是文件基本信息的存放地和數據塊指針存放地。
數據塊:文件的具體內容存放地。


Linux正統的文件系統(如ext2、3等)將硬盤分區時會划分出目錄塊、inode Table區塊和data block數據區域。一個文件由一個目錄項、inode和數據區域塊組成。Inode包含文件的屬性(如讀寫屬性、owner等,以及指向數據塊的指針),數據區域塊則是文件內容。當查看某個文件時,會先從inode table中查出文件屬性及數據存放點,再從數據塊中讀取數據。

文件存儲結構大概如下:



其中目錄項的結構如下(每個文件的目錄項存儲在改文件所屬目錄的文件內容里):


圖4:目錄項結構 

其中文件的inode結構如下(inode里所包含的文件信息可以通過stat filename查看得到):


以上只反映大體的結構,linux文件系統本身在不斷發展。但是以上概念基本是不變的。且如ext2、ext3、ext4文件系統也存在很大差別,如果要了解可以查看專門的文件系統介紹。
2. 創建一個文件的過程

我們從前面可以知道文件的內容和屬性是分開存放的,那么又是如何管理它們的呢?現在我們以創建一個文件為例來講解。
在命令行輸入命令:
$ who > userlist
當完成這個命令時。文件系統中增加了一個存放命令who輸出內容的新文件userlist,那么這整個過程到底是怎么回事呢?
文件主要有屬性、內容以及文件名三項。內核將文件內容存放在數據區,文件屬性存放在i-節點,文件名存放在目錄中。
創建成功一個文件主要有以下四個步驟:
1)        存儲屬性 也就是文件屬性的存儲,內核先找到一塊空的i-節點。例如,內核找到i-節點號921130。內核把文件的信息記錄其中。如文件的大小、文件所有者、和創建時間等。
2)        存儲數據 即文件內容的存儲,由於該文件需要3個數據塊。因此內核從自由塊的列表中找到3個自由塊。如600、200、992,內核緩沖區的第一塊數據復制到塊600,第二和第三分別復制到922和600.
3)        記錄分配情況,數據保存到了三個數據塊中。所以必須要記錄起來,以后再找到正確的數據。分配情況記錄在文件的i-節點中的磁盤序號列表里。這3個編號分別放在最開始的3個位置。
4)        添加文件名到目錄,新文件的名字是userlist 內核將文件的入口(47,userlist)添加到目錄文件里。文件名和i-節點號之間的對應關系將文件名和文件和文件的內容屬性連接起來,找到文件名就找到文件的i-節點號,通過i-節點號就能找到文件的屬性和內容。
代碼具體實現過程參考:
3.創建一個目錄的過程

前面說了創建一個文件的大概過程,也了解文件內容、屬性以及入口的保存方式,那么創建一個目錄時又是怎么回事呢?
我現在test目錄使用命令mkdir 新增一個子目錄child:

從用戶的角度看,目錄child是目錄test的一個子目錄,那么在系統中這層關系是怎么實現的呢?實際上test目錄包含一個指向子目錄child的i-節點的鏈接,原理跟普通文件一樣,因為目錄也是文件。

目錄其實也是文件,只是它的內容比較特殊。所以它的創建過程和文件創建過程一樣,只是第二步寫的內容不同。
1)      系統找到空閑的i-節點號887220,寫入目錄的屬性
2)      找到空閑的數據塊1002來存儲目錄的內容,只是目錄的內容比較特殊,包含文件名字列表,列表一般包含兩個部分:i-節點號和文件名,這個列表其實也就是文件的入口,新建的目錄至少包含三個目錄”.”和”..”其中”.”指向自己,”..”指向上級目錄,我們可以通過比較對應的i-節點號來驗證,887270 對應着上級目錄中的child對應的i-節點號
3)      記錄分配情況。這個和創建文件完全一樣
4)      添加目錄的入口到父目錄,即在父目錄中的child入口。

一般都說文件存放在某個目錄中,其實目錄中存入的只是文件在i-節點表的入口,而文件的內容則存儲在數據區。我們一般會說“文件userlist在目錄test中”,其實這意味着目錄test中有一個指向i-節點921130的鏈接,這個鏈接所附加的文件名為userlist,這也可以這樣理解:目錄包含的是文件的引用,每個引用被稱為鏈接。文件的內容存儲在數據塊。文件的屬性被記錄在一個被稱為i-節點的結構中。I-節點的編號和文件名關聯起來存在目錄中。
注意:其中“.”表示是當前目錄。而“..”是當前目錄的父目錄。但也有特殊情況:如我們查看根目錄/的情況:

發現“.”和“..”都指向i-節點2。實際上當我們用mkfs創建一個文件系統時,mkfs都會將根目錄的父目錄指向自己。所以根目錄下.和..指向同一個i-節點也不奇怪了。
代碼具體實現參考:

4. 理解鏈接

我們知道文件都有文件名與數據,這在 Linux 上被分成兩個部分:用戶數據 (user data) 與元數據 (metadata)。用戶數據,即文件數據塊 (data block),數據塊是記錄文件真實內容的地方;而元數據則是文件的附加屬性,如文件大小、創建時間、所有者等信息。在 Linux 中,元數據中的 inode 號(inode 是文件元數據的一部分但其並不包含文件名,inode 號即索引節點號)才是文件的唯一標識而非文件名。文件名僅是為了方便人們的記憶和使用,系統或程序通過 inode 號尋找正確的文件數據塊。圖 1.展示了程序通過文件名獲取文件內容的過程。
圖 1. 通過文件名打開文件

圖 1. 通過文件名打開文件

清單 3. 移動或重命名文件
復制代碼
# stat /home/harris/source/glibc-2.16.0.tar.xz File: `/home/harris/source/glibc-2.16.0.tar.xz' Size: 9990512 Blocks: 19520 IO Block: 4096 regular file Device: 807h/2055d Inode: 2485677 Links: 1 Access: (0600/-rw-------) Uid: ( 1000/ harris) Gid: ( 1000/ harris) ... ... # mv /home/harris/source/glibc-2.16.0.tar.xz /home/harris/Desktop/glibc.tar.xz # ls -i -F /home/harris/Desktop/glibc.tar.xz 2485677 /home/harris/Desktop/glibc.tar.xz
復制代碼

 


在 Linux 系統中查看 inode 號可使用命令 stat 或 ls -i(若是 AIX 系統,則使用命令 istat)。清單 3.中使用命令 mv 移動並重命名文件 glibc-2.16.0.tar.xz,其結果不影響文件的用戶數據及 inode 號,文件移動前后 inode 號均為:2485677。
為解決文件的共享使用,Linux 系統引入了兩種鏈接:硬鏈接 (hard link) 與軟鏈接(又稱符號鏈接,即 soft link 或 symbolic link)。

具體關系可以看下圖:
 
為 Linux 系統解決了文件的共享使用,還帶來了隱藏文件路徑、增加權限安全及節省存儲等好處。若一個 inode 號對應多個文件名,則稱這些文件為硬鏈接。換言之,硬鏈接就是同一個文件使用了多個別名(見 圖 2.hard link 就是 file 的一個別名,他們有共同的 inode)。硬鏈接可由命令 link 或 ln 創建。如下是對文件 oldfile 創建硬鏈接。
link oldfile newfile
ln oldfile newfile
由於硬鏈接是有着相同 inode 號僅文件名不同的文件,因此硬鏈接存在以下幾點特性:
文件有相同的 inode 及 data block;
只能對已存在的文件進行創建;
不能交叉文件系統進行硬鏈接的創建;
不能對目錄進行創建,只可對文件創建;
刪除一個硬鏈接文件並不影響其他有相同 inode 號的文件。
 
創建一個鏈接的步驟大概如下:
1)  通過原文件的文件名找到文件的i-節點號
2)  添加文件名關聯到目錄,新文件的名字是mylink 內核將文件的入口(921130,mylink)添加到目錄文件里。
和創建文件的過程比較發現,鏈接少了寫文件內容的步驟,完全相同的是把文件名關聯到目錄這一步
現在.i- 節點號921130對應了兩個文件名。鏈接數也會變成2個,文件的內容並不會發生任何變化。前面我們已經講了:目錄包含的是文件的引用,每個引用被稱為鏈接。所以鏈接文件和原始文件本質上是一樣的,因為它們都是指向同一個i-節點。由於此原因也就可以理解鏈接的下列特性:你改變其中任何一個文件的內容,別的鏈接文件也一樣是變化;另外如果你刪除某一個文件,系統只會在所指向的i-節點上把鏈接數減1,只有當鏈接數減為零時才會真正釋放i-節點。
硬鏈接有兩個特點:
1)不能跨文件系統
2)不能對目錄
清單 4. 硬鏈接特性展示
復制代碼
# ls -li total 0 // 只能對已存在的文件創建硬連接 # link old.file hard.link link: cannot create link `hard.link' to `old.file': No such file or directory # echo "This is an original file" > old.file # cat old.file This is an original file # stat old.file File: `old.file' Size: 25 Blocks: 8 IO Block: 4096 regular file Device: 807h/2055d Inode: 660650 Links: 2 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) ... // 文件有相同的 inode 號以及 data block # link old.file hard.link | ls -li total 8 660650 -rw-r--r-- 2 root root 25 Sep 1 17:44 hard.link 660650 -rw-r--r-- 2 root root 25 Sep 1 17:44 old.file // 不能交叉文件系統 # ln /dev/input/event5 /root/bfile.txt ln: failed to create hard link `/root/bfile.txt' => `/dev/input/event5': Invalid cross-device link // 不能對目錄進行創建硬連接 # mkdir -p old.dir/test # ln old.dir/ hardlink.dir ln: `old.dir/': hard link not allowed for directory # ls -iF 660650 hard.link 657948 old.dir/ 660650 old.file
復制代碼

 

軟鏈接與硬鏈接不同,若文件用戶數據塊中存放的內容是另一文件的路徑名的指向,則該文件就是軟連接。軟鏈接就是一個普通文件,只是數據塊內容有點特殊。軟鏈接有着自己的 inode 號以及用戶數據塊(見 圖 2.)。因此軟鏈接的創建與使用沒有類似硬鏈接的諸多限制:
軟鏈接有自己的文件屬性及權限等;
可對不存在的文件或目錄創建軟鏈接;
軟鏈接可交叉文件系統;
軟鏈接可對文件或目錄創建;
創建軟鏈接時,鏈接計數 i_nlink 不會增加;
刪除軟鏈接並不影響被指向的文件,但若被指向的原文件被刪除,則相關軟連接被稱為死鏈接(即 dangling link,若被指向路徑文件被重新創建,死鏈接可恢復為正常的軟鏈接)。
圖 2. 軟鏈接的訪問
軟鏈接
實際上只是一段文字,里面包含着它所指向的文件的名字,系統看到軟鏈接后自動跳到對應的文件位置處進行處理;相反,硬鏈接為文件開設一個新的目錄項,硬鏈接與文件原有的名字是平權的,在Linux看來它們是等價的。由於這個原因,硬鏈接不能連接兩個不同文件系統上的文件。

軟連接與windows下的快捷方式類似
至於硬連接,舉個例子說吧,你把dir1/file1硬連接到dir2/file2, 就是在dir2下建立一個dir1/file1的鏡像文件file2,它與file1是占用一樣大的空間的,並且改動兩者中的一個,另一個也會發生同樣的改動.
軟連接和硬連接可以這樣理解:
硬連接就像一個文件有多個文件名,
軟連接就是產生一個新文件(這個文件內容,實際上就是記當要鏈接原文件路徑的信息),這個文件指向另一個文件的位置,
硬連接必須在同一文件系統中,而軟連接可以跨文件系統
硬連接 :源文件名和鏈接文件名都指向相同的物理地址,目錄不能夠有硬連接,文件在磁盤中只有一個復制,可以節省硬盤空間,由於刪除文件要在同一個索引節點屬於唯一的連接時才能成功,因此可以防止不必要的誤刪除軟連接(符號連接)用ln -s命令創建文件的符號連接,符號連接是linux特殊文件的一種,作為一個文件,它的資料是它所連接的文件的路徑名,類似於硬件方式,******可以刪除原始文件 而連接文件仍然存在。********
清單 5. 軟鏈接特性展示
復制代碼
# ls -li total 0 // 可對不存在的文件創建軟鏈接 # ln -s old.file soft.link # ls -liF total 0 789467 lrwxrwxrwx 1 root root 8 Sep 1 18:00 soft.link -> old.file // 由於被指向的文件不存在,此時的軟鏈接 soft.link 就是死鏈接 # cat soft.link cat: soft.link: No such file or directory // 創建被指向的文件 old.file,soft.link 恢復成正常的軟鏈接 # echo "This is an original file_A" >> old.file # cat soft.link This is an original file_A // 對不存在的目錄創建軟鏈接 # ln -s old.dir soft.link.dir # mkdir -p old.dir/test # tree . -F --inodes . ├── [ 789497] old.dir/ │ └── [ 789498] test/ ├── [ 789495] old.file ├── [ 789495] soft.link -> old.file └── [ 789497] soft.link.dir -> old.dir/
復制代碼

 

 
 
四、文件節點inode
可以看到inode節點好比是文件的大腦,下面就詳細介紹一下inode。
1.inode是什么 
     理解inode,要從文件儲存說起。
     扇區(sector):硬件(磁盤)上的最小的操作單位,是操作系統和塊設備(硬件、磁盤)之間傳送數據的單位。
     block由一個或多個sector組成,文件系統中最小的操作單位;OS的虛擬文件系統從硬件設備上讀取一個block,實際為從硬件設備讀取一個或多個sector。對於文件管理來說,每個文件對應的多個block可能是不連續的;
     block最終要映射到sector上,所以block的大小一般是sector的整數倍。不同的文件系統block可使用不同的大小,操作系統會在內存中開辟內存,存放block到所謂的block buffer中。在Ext2中,物理塊的大小是可變化的,這取決於在創建文件系統時的選擇,之所以不限制大小,也正體現了Ext2的靈活性和可擴充性。通常,Ext2的物理塊占一個或幾個連續的扇區,顯然,物理塊的數目是由磁盤容量等硬件因素決定的。具體文件系統所操作的基本單位是邏輯塊,只在需要進行I/O操作時才進行邏輯塊到物理塊的映射,這顯然避免了大量的I/O操作,因而文件系統能夠變得高效。邏輯塊作為一個抽象的概念,它必然要映射到具體的物理塊上去,因此,邏輯塊的大小必須是物理塊大小的整數倍,一般說來,兩者是一樣大的。
     通常,一個文件占用的多個物理塊在磁盤上是不連續存儲的,因為如果連續存儲,則經過頻繁的刪除、建立、移動文件等操作,最后磁盤上將形成大量的空洞,很快磁盤上將無空間可供使用。因此,必須提供一種方法將一個文件占用的多個邏輯塊映射到對應的非連續存儲的物理塊上去,Ext2等類文件系統是用索引節點解決這個問題的。
   
文件數據都儲存在"塊"中,那么很顯然,我們還必須找到一個地方儲存文件的元信息,比如文件的創建者、文件的創建日期、文件的大小等等。這種儲存文件元信息的區域就叫做inode,中文譯名為"索引節點"。
在Unix/Linux上,一個文件由一個inode 表示。inode在系統管理員看來是每一個文件的唯一標識,在系統里面,inode是一個結構,存儲了關於這個文件的大部分信息。 
2.inode內容
inode包含文件的元信息,具體來說有以下內容:
*文件的字節數
*文件擁有者的UserID*文件的GroupID
*文件的讀、寫、執行權限
*文件的時間戳,共有三個:ctime指inode上一次變動的時間,mtime指文件內容上一次變動的時間,atime指文件上一次打開的時間。
*鏈接數,即有多少文件名指向這個inode*文件數據block的位置可以用stat命令,查看某個文件的inode信息:statexample.txt
總之,除了文件名以外的所有文件信息,都存在inode之中。至於為什么沒有文件名,下文會有詳細解釋。
inode中存儲了一個文件的以下信息:
3.inode結構

 

復制代碼
struct inode {
        struct hlist_node       i_hash;              /* 哈希表 */ struct list_head i_list; /* 索引節點鏈表 */ struct list_head i_dentry; /* 目錄項鏈表 */ unsigned long i_ino; /* 節點號 */ atomic_t i_count; /* 引用記數 */ umode_t i_mode; /* 訪問權限控制 */ unsigned int i_nlink; /* 硬鏈接數 */ uid_t i_uid; /* 使用者id */ gid_t i_gid; /* 使用者id組 */ kdev_t i_rdev; /* 實設備標識符 */ loff_t i_size; /* 以字節為單位的文件大小 */ struct timespec i_atime; /* 最后訪問時間 */ struct timespec i_mtime; /* 最后修改(modify)時間 */ struct timespec i_ctime; /* 最后改變(change)時間 */ unsigned int i_blkbits; /* 以位為單位的塊大小 */ unsigned long i_blksize; /* 以字節為單位的塊大小 */ unsigned long i_version; /* 版本號 */ unsigned long i_blocks; /* 文件的塊數 */ unsigned short i_bytes; /* 使用的字節數 */ spinlock_t i_lock; /* 自旋鎖 */ struct rw_semaphore i_alloc_sem; /* 索引節點信號量 */ struct inode_operations *i_op; /* 索引節點操作表 */ struct file_operations *i_fop; /* 默認的索引節點操作 */ struct super_block *i_sb; /* 相關的超級塊 */ struct file_lock *i_flock; /* 文件鎖鏈表 */ struct address_space *i_mapping; /* 相關的地址映射 */ struct address_space i_data; /* 設備地址映射 */ struct dquot *i_dquot[MAXQUOTAS]; /* 節點的磁盤限額 */ struct list_head i_devices; /* 塊設備鏈表 */ struct pipe_inode_info *i_pipe; /* 管道信息 */ struct block_device *i_bdev; /* 塊設備驅動 */ unsigned long i_dnotify_mask; /* 目錄通知掩碼 */ struct dnotify_struct *i_dnotify; /* 目錄通知 */ unsigned long i_state; /* 狀態標志 */ unsigned long dirtied_when; /* 首次修改時間 */ unsigned int i_flags; /* 文件系統標志 */ unsigned char i_sock; /* 可能是個套接字吧 */ atomic_t i_writecount; /* 寫者記數 */ void *i_security; /* 安全模塊 */ __u32 i_generation; /* 索引節點版本號 */ union { void *generic_ip; /* 文件特殊信息 */ } u; };
復制代碼
inode就是一個文件的一部分描述,不是全部,在內核中,inode對應了這樣一個實際存在的結構。
復制代碼
縱觀整個inode的C語言描述,沒有發現關於文件名的東西,也就是說文件名不由inode保存,實際上系統是不關心文件名的,對於系統中任何的操作,大部分情況下你都是通過文件名來做的,但系統最終都要通過找到文件對應的inode來操作文件,由inode結構中 *i_op指向的接口來操作。
文件系統如何存取文件的:
     1)、根據文件名,通過Directory里的對應關系,找到文件對應的Inodenumber
     2)、再根據Inodenumber讀取到文件的Inodetable
     3)、再根據Inodetable中的Pointer讀取到相應的Blocks
這里有一個重要的內容,就是Directory,他不是我們通常說的目錄,而是一個列表,記錄了一個文件/目錄名稱對應的Inodenumber。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM