本文主要是基於百度文庫的《Linux2.4.30內核文件系統學習(多圖).doc》和360doc的《Linux內核虛擬文件系統》修改而來,當然還參考了其他的一些文檔,在此就不一一列出了。本來在看到這些文章後,都沒有勇氣再寫點文件系統方面的東西了,這些文章實在太精彩了。最後還是鼓足勇氣決定把整理的資料增加了一點自己的理解寫下來,主要目的是讓各位高手看看我的理解是否正確,另外就是備忘。
1、如何描述一個文件
我們先看看一個文件在內存和磁盤上是如何描述的。每個文件至少要有一個數據結構存放該文件的信息,包括uid、gid、flag、文件長度、文件內容存放位置的數據結構等。在Linux中這個數據結構被稱爲inode,本來inode中也應該包括文件名稱等信息,但是由於符號鏈接的存在,導致一個文件可能存在多個文件名稱,因此把和文件名稱相關的信息從inode中提出,專門放到dentry 結構中。dentry通過其成員變量d_inode 指向對應的inode數據結構。如下圖所示
圖1
另外,inode結構中還包括了成員i_fop,其類型是struct file_operations,其中包括的針對該文件的一些操作接口,如上圖所示。
2、根據路徑名尋找目標文件
在Linux中目錄也被作爲文件看待,只是目錄是一種比較特殊的文件。其特殊之處在於文件的內容是該目錄中文件和子目錄的dentry的描述符,通過這些dentry的描述符可以找到文件或子目錄的dentry,進而找到相應的inode。
下面我們看看如果根據絕對路徑尋找一個文件/tmp/temp/abc的。
1、 首先找到根文件系統的根目錄文件的 dentry 和 inode
2、由這個 inode 提供的操作接口 i_op->lookup(),找到下一層節點 ‘tmp’ 的 dentry 和 inode
3、由 ‘tmp’ 的 inode 找到 ‘temp’ 的 dentry 和 inode
4、最後由 ‘temp’ 的 inode 找到 ‘abc’ 的 dentry 和 inode
可以看到,整個尋找過程是一個遞歸的過程。
我們再看看如何通過相對路徑尋找文件/tmp/temp/abc,假如我們目前的工作目錄爲/tmp/temp/dir_a 中,比如我們通過拷貝命令拷貝該文件:cp ../abc ./
如何通過相對路徑尋找文件呢?我們來看看dentry這個數據結構的成員,其中有一個是d_parent,數據結構定義如下
struct dentry { 刪除了無關的成員
struct dentry *d_parent; /* parent directory */
struct inode *d_inode; /* Where the name belongs to - NULL is * negative */
unsigned char d_iname[DNAME_INLINE_LEN]; /* small names */
}
d_parent指向了本目錄的父目錄的dentry,這樣就在通過“..”時就是通過該指針找到的父目錄dentry,找到父母inode,進而找到父目錄下的所有文件的信息。
3、進程中打開的文件
一個文件可以被多次打開,並且多個進程對一個文件的訪問權限可能不同,因此打開方式就會不同(只讀、讀寫、可執行)。而dentry 和 inode 只能描述一個物理的文件,無法描述“打開”這個概念。
因此有必要引入 file 結構,來描述一個“被打開的文件”。每打開一個文件,就創建一個 file 結構。
file 結構中包含以下信息:
打開這個文件的進程的 uid,pid
打開的方式
讀寫的方式
當前在文件中的位置
實際上,打開文件的過程正是建立file, dentry, inode 之間的關聯的過程。如下圖
圖2
在進程中如何和打開的文件相關聯呢?我們來看看進程的數據結構
struct task_struct { 只保留了相關信息
struct files_struct *files; /* open file information */
}
每個進程包括“files”成員,其類型爲files_struct。如下圖所示
圖3
進程中所有打開的文件的指針都存在了fd_arrary[]數組中。
4、虛擬文件系統
Linux 通過虛擬文件系統 (VFS) 來支持不同的具體的文件系統,那麼 VFS 到底是什麼?
從程序員的角度看, VFS 就是一套代碼框架(framework),它將用戶與具體的文件系統隔離開來。每個要通過mount 命令掛接到Linux系統的存儲設備,如磁盤、光盤等(它們各自對應具體的文件系統),每個設備對應的文件系統都要按照VFS的要求提供一套統一的接口。這樣,用戶就可以使用這些統一的接口在不同的文件系統中拷貝數據了。參考下圖
安裝一個文件系統,除了需要“被安裝設備”外,還要指定一個“安裝點”。“安裝點”是已經存在的一個目錄節點。例如把/dev/sda1 安裝到 /mnt/win 下,那麼 /mnt/win 就是“安裝點”。
可是文件系統要先安裝後使用。因此,要使用 /mnt/win 這個“安裝點”,必然要求它所在文件系統已也經被安裝。
也就是說,安裝一個文件系統,需要另外一個文件系統已經被安裝。
這是一個雞生蛋,蛋生雞的問題:最頂層的文件系統是如何被安裝的?
答案是,最頂層文件系統的時候是被安裝在“根安裝點”上的,而根安裝點不屬於任何文件系統,它對應的 dentry 、inode 是由內核在初始化階段憑空構造出來的。
最頂層的文件系統叫做“根文件系統”。Linux 在啓動的時候,要求用戶必須指定一個“根設備”,內核在初始化階段,將“根設備”安裝到“根安裝點”上,從而有了根文件系統。這樣,文件系統纔算準備就緒。此後,用戶就可以通過 mount 命令來安裝新的設備。
5、mount 設備(文件系統)
我們通過mount命令向Linux系統mount了一個設備。其實該命令觸發了兩個過程,一個是文件系統註冊過程(當然,如果文件系統已註冊過的話,就不需要該步驟了),另一個纔是真正意義上的mount設備的過程。
文件系統註冊過程
Linux內核是可加載的,許多模塊式可選的,只有真正需要使用時才加載他們。文件系統註冊過程就是把對應某類型文件系統相關的模塊加載到內核,並創建相關的數據結構。每個文件系統模塊都有一個初始化例程,它的作用就是VFS中進行註冊,即填寫一個叫做file_system_type的數據結構。所有已註冊的文件系統的file_system_type結構形成一個鏈表,我們把這個鏈表稱爲註冊鏈表。
圖5
每個設備在mount時都要搜索該註冊鏈表,選擇適合自己設備文件系統的一項,並從中取出read_super()函數獲取設備的超級塊(存儲在具體設備上,記錄存儲設備各種信息的一個存儲塊),並解析其內容。因爲每種類型文件系統的超級塊的格式不同,並且各自有特定的信息,每種文件系統必須使用對應的解析函數,否則內核就因爲不認識該文件系統而無法完成安裝。這就是註冊文件系統的意義所在。
設備真正mount過程
總體數據結構,參考下圖
圖6
1、 創建一個設備的 vfsmount
2、爲“被安裝設備”創建一個 super_block,並由具體的文件系統來設置這個 super_block。在super_block中包含了該類型設備操作的各種接口的結構成員s_op,類型爲super_operations。
3、 爲被安裝設備的根目錄節點創建 dentry
4、 爲被安裝設備的根目錄節點創建 inode, 並由 super_block->s_op->read_inode() 來設置此 inode
5、 將 super_block 與“被安裝設備“根目錄節點 dentry 關聯起來
6、 將 super_block中的s_root與“被安裝設備”的根目錄節點 dentry 關聯起來
如圖6所示,在linux2.4.30中有三條鏈表,文件系統類型結構file_system_type的鏈表頭爲file_systems,超級塊結構super_block的鏈表頭爲super_blocks,掛接點結構vfsmount的鏈表頭爲vfsmntlist。
在Linux3.3.5中只有兩條鏈表結構,文件系統類型結構file_system_type的鏈表頭爲file_systems,超級塊結構super_block的鏈表頭爲super_blocks。數據結構vfsmount 的結構定義還存在,但已經沒有了mnt_list成員了。
6、掛接設備中查找文件的過程
下面的流程參考了linux3.3.5中的數據結構。
例如要打開 /mnt/win/dir1/abc 這個文件,就是根據這個路徑,找到目標節點 ‘abc’ 對應的 dentry ,進而得到 inode 的過程。
尋找過程大致如下:
1、 首先找到根文件系統的根目錄節點 dentry 和 inode
2、 由這個 inode 提供的操作接口 i_op->lookup(),找到下一層節點 ‘mnt’ 的 dentry 和 inode
3、 由 ‘mnt’ 的 inode 找到 ‘win’ 的 dentry 和 inode
4、 由於 ‘win’ 是個“安裝點”,因此需要找到“被安裝設備”/dev/sda1 根目錄節點的 dentry 和 inode。“win”的dentry中有d_sb(超級塊成員),d_sb中有“struct dentry *s_root;”,s_root就是指向“/dev/sda1”的dentry。
5、 然後由 /dev/sda1 根目錄節點的 inode 負責找到下一層節點 ‘dir1’ 的 dentry 和 inode
6、 由於 dir1 是個“安裝點”,因此需要藉助dir1的dentry->d_sb->s_root找到 /dev/sda2 的根目錄節點 dentry 和 inode
7、 最後由這個 inode 負責找到 ‘abc’ 的 dentry 和 inode
可以看到,整個尋找過程是一個遞歸的過程。
完成尋找後,內存中結構如下,其中紅色線條是尋找目標節點的路徑
文件系統是linux的一個十分基礎的知識,同時也是學習linux的必備知識。
本文將站在一個較高的視圖來了解linux的文件系統,主要包括了linux磁盤分區和目錄、掛載基本原理、文件存儲結構、軟鏈接硬鏈接、和常見目錄的介紹。相信有了這些知識對於深入的學習linux會有一定的幫助。文章例子主要是基於ubuntu發行版。
如有不對之處請大家多多指出。
1.Linux磁盤分區和目錄
Linux發行版本之間的差別很少,差別主要表現在系統管理的特色工具以及軟件包管理方式的不同。目錄結構基本上都是一樣的。Windows的文件結構是多個並列的樹狀結構,最頂部的是不同的磁盤(分區),如:C,D,E,F等。
Linux的文件結構是單個的樹狀結構.可以用tree進行展示。 在Ubuntu下安裝tree(sudo apt-get install tree),並可通過命令來查看。
每次安裝系統的時候我們都會進行分區,Linux下磁盤分區和目錄的關係如下:
– 任何一個分區都必須掛載到某個目錄上。
– 目錄是邏輯上的區分。分區是物理上的區分。
– 磁盤Linux分區都必須掛載到目錄樹中的某個具體的目錄上才能進行讀寫操作。
– 根目錄是所有Linux的文件和目錄所在的地方,需要掛載上一個磁盤分區。
以下是我們可能存在的一種目錄和分區關係:
圖1:目錄和分區關係
Q:如何查看分區和目錄及使用情況?
– fdisk查看硬盤分區表
– df:查看分區使用情況
– du: 查看文件佔用空間情況
Q: 爲什麼要分區,如何分區?
– 可以把不同資料,分別放入不同分區中管理,降低風險。
– 大硬盤搜索範圍大,效率低
– 磁盤配合只能對分區做設定
– /home /var /usr/local經常是單獨分區,因爲經常會操作,容易產生碎片
2.Mount掛載和NFS簡介
掛載的概念 :當要使用某個設備時,例如要讀取硬盤中的一個格式化好的分區、光盤或軟件等設備時,必須先把這些設備對應到某個目錄上,而這個目錄就稱爲“掛載點(mount point)”,這樣纔可以讀取這些設備,而這些對應的動作就是“掛載”。 將物理分區細節屏蔽掉。用戶只有統一的邏輯概念。所有的東西都是文件。Mount命令可以實現掛載:
mount [-fnrsvw] [-t vfstype] [-o options] device dir
Q:所有的磁盤分區都必須被掛載上才能使用,那麼我們機器上的硬盤分區是如何被掛載的?
A:這主要是它利用了/etc/fstab文件。每次內核加載它知道從這裏開始mount文件系統。每次系統啓動會根據該文件定義自動掛載。若沒有被自動掛載,分區將不能使用。 如下是我的/etc/fstab的定義,主要是根據裝機的分區來的:
# <file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
#/dev/sda1被自動掛載到 /
UUID=cb1934d0-4b72-4bbf-9fad-885d2a8eeeb1 / ext3 relatime,errors=remount-ro 0 1
# /dev/sda5 被自動掛載到分區/home
UUID=c40f813b-bb0e-463e-aa85-5092a17c9b94 /home ext3 relatime 0 2
#/dev/sda7 被自動掛載到/work
UUID=0f918e7e-721a-41c6-af82-f92352a568af /work ext3 relatime 0 2
#分區 /dev/sda6被自動掛載到swap
UUID=2f8bdd05-6f8e-4a6b-b166-12bb52591a1f none swap sw 0 0
Q:移動硬盤如何掛載?如何掛載一個新的分區?
移動硬盤有驅動模塊會自動掛載,如果有個新硬盤,要先進行分區,並通過mount命令掛載到某個文件夾。如果要自動掛載則可以修改/etc/fstab文件.
NFS簡介:NFS相信在很多地方都有廣泛使用,是一個非常好的文件共享方式。我們公司所使用的上傳服務就是把文件上傳到某臺網絡服務器上,中間就是通過NFS實現。
使用NFS客戶端可以透明的地訪問服務器端的文件。NFS也是通過mount來實現,底層是通過NFS通信協議實現。基本原理:
圖2:NFS基本原理
Ubuntu下面Ubuntu下的例子
服務端:
$apt-get install nfs-kernel-server
vi /etc/exports 添加nfs目錄: /personal/nfs_share
10.1.60.34(rw,sync,no_root_squash)
$sudo exportfs -r
$sudo /etc/init.d/portmap start
$sudo /etc/init.d/nfs-kernel-server start
客戶端:
$sudo apt-get install nfs-common
$sudo mount 10.19.34.76:/personal/nfs_share ~/nfsshare例子:
3.文件類型
Linux下面的文件類型主要有:
a) 普通文件:C語言元代碼、SHELL腳本、二進制的可執行文件等。分爲純文本和二進制。
b) 目錄文件:目錄,存儲文件的唯一地方。
c) 鏈接文件:指向同一個文件或目錄的的文件。
d) 特殊文件:與系統外設相關的,通常在/dev下面。分爲塊設備和字符設備。
可以通過ls –l, file, stat幾個命令來查看文件的類型等相關信息。
4.文件存儲結構
Linux正統的文件系統(如ext2、ext3)一個文件由目錄項、inode和數據塊組成。
目錄項:包括文件名和inode節點號。
Inode:又稱文件索引節點,是文件基本信息的存放地和數據塊指針存放地。
數據塊:文件的具體內容存放地。
Linux正統的文件系統(如ext2、3等)將硬盤分區時會劃分出目錄塊、inode Table區塊和data block數據區域。一個文件由一個目錄項、inode和數據區域塊組成。Inode包含文件的屬性(如讀寫屬性、owner等,以及指向數據塊的指針),數據區域塊則是文件內容。當查看某個文件時,會先從inode table中查出文件屬性及數據存放點,再從數據塊中讀取數據。
站在2w英尺視圖,文件存儲結構大概如下:
圖3:文件存儲結構2w英尺視圖
其中目錄項的結構如下(每個文件的目錄項存儲在改文件所屬目錄的文件內容裏):
圖4:目錄項結構
其中文件的inode結構如下(inode裏所包含的文件信息可以通過stat filename查看得到):
圖5:inode結構
以上只反映大體的結構,linux文件系統本身在不斷髮展。但是以上概念基本是不變的。且如ext2、ext3、ext4文件系統也存在很大差別,如果要了解可以查看專門的文件系統介紹。
5.軟連接、硬鏈接
軟鏈接和硬鏈接是我們常見的兩種概念:
硬連接:是給文件一個副本,同時建立兩者之間的連接關係。修改其中一個,與其連接的文件同時被修改。如果刪除其中[color=red]任意一個[/color]其餘的文件將不受影響。
軟連接:也叫符號連接,他只是對源文件在新的位置建立一個“快捷(借用一下wondows常用詞)”,所以,當源文件刪除時,符號連接的文件將成爲無源之水->僅僅剩下個文件名了,當然刪除這個連接,也不會影響到源文件,但對連接文件的使用、引用都是直接調用源文件的。
具體關係可以看下圖:
圖5:軟鏈接和硬鏈接
從圖上可以看出硬鏈接和軟鏈接的區別:
1:硬鏈接原文件和新文件的inode編號一致。而軟鏈接不一樣。
2:對原文件刪除,會導致軟鏈接不可用,而硬鏈接不受影響。
3:對原文件的修改,軟、硬鏈接文件內容也一樣的修改,因爲都是指向同一個文件內容的。
6.文件目錄管理命令
磁盤和文件空間
fdisk df du
文件目錄與管理
cd pwd mkdir rmdir ls cp rm mv
查看文件內容
cat:
cat [file]
查看文件的內容。全程式concatenate的意思,將文件內容連續輸出到屏幕上。第一行到最後一行顯示。
tac:
tac [file]
和cat剛好相反 是從最後一行到第一行的方式查看。
cat有個比較不好的地方時當文件比較大時候沒辦法看清楚,這個時候可以用more或者Less命令。
more:
more [file]
如果使用grep或者find等命令時,可以配合使用more一頁一頁的查看。如果看到一半想退出,則敲入’q’即可退出。
less:
less [file]
less比more更有彈性,可以上下翻頁。
如果只想讀取文件的頭幾行或者文件的末尾幾行,可以用head或tail.
head –n [file]:讀取文件的前n行。
tail –n [file]:讀取文件末尾n行。
以上命令都是用於查看字符文件,二進制文件出來的都是亂碼,要看二進制文件的內容,可以用od命令,如查看一個MP3文件裏面的內容:
od shijiemori.mp3
文件目錄與權限
chmod chown chgrp umask
文件查找
which:
which [filename]
該命令用於查詢通過PATH路徑到該路徑內查找可執行文件。
如:Which passwd:查找可執行文件passwd
whereis:
whereis [-bmsu] [keyword]
該命令用於把相關字的文件和目錄都列出來。(Linux 會將文件都記錄在一個文件數據庫裏面,該命令式從數據庫去查詢,所以速度比較快,Linux每天會更新該數據庫)
locate:
locate [filename]
該命令用於把相關字的文件和目錄都列出來。查找數據特別快,也是通過數據庫方式來查詢。但是數據庫一週更新一次,所以可能有些存在數據查不到。可以去修改配置文件。
find:
find [path] [參數] [keyword]
該命令用於在指定路徑下查找文件。不是通過數據來查詢,所以速度會比較慢。
7.常見目錄解釋
Linux各種發行版的目錄結構基本一致,各個目錄簡單介紹如下:
目錄 |
描述 |
/ |
根目錄 |
/bin |
做爲基礎系統所需要的最基礎的命令就是放在這裏。比如 ls、cp、mkdir等命令;功能和/usr/bin類似,這個目錄中的文件都是可執行的,普通用戶都可以使用的命令。 |
/boot |
Linux的內核及引導系統程序所需要的文件,比如 vmlinuz initrd.img 文件都位於這個目錄中。在一般情況下,GRUB或LILO系統引導管理器也位於這個目錄;啓動裝載文件存放位置,如kernels,initrd,grub。一般是一個獨立的分區。 |
/dev |
一些必要的設備,聲卡、磁盤等。還有如 /dev/null. /dev/console /dev/zero /dev/full 等。 |
/etc |
系統的配置文件存放地. 一些服務器的配置文件也在這裏;比如用戶帳號及密碼配置文件; /etc/opt:/opt對應的配置文件 /etc/X11:Xwindows系統配置文件 /etc/xml:XML配置文件 …… |
/home |
用戶工作目錄,和個人配置文件,如個人環境變量等,所有的賬號分配一個工作目錄。一般是一個獨立的分區。 |
/lib |
庫文件存放地。bin和sbin需要的庫文件。類似windows的DLL。 |
/media |
可拆卸的媒介掛載點,如CD-ROMs、移動硬盤、U盤,系統默認會掛載到這裏來。 |
/mnt |
臨時掛載文件系統。這個目錄一般是用於存放掛載儲存設備的掛載目錄的,比如有cdrom 等目錄。可以參看/etc/fstab的定義。 |
/opt |
可選的應用程序包。 |
/proc |
操作系統運行時,進程(正在運行中的程序)信息及內核信息(比如cpu、硬盤分區、內存信息等)存放在這裏。/proc目錄僞裝的文件系統proc的掛載目錄,proc並不是真正的文件系統,它的定義可以參見 /etc/fstab 。 |
/root |
Root用戶的工作目錄 |
/sbin |
和bin類似,是一些可執行文件,不過不是所有用戶都需要的,一般是系統管理所需要使用得到的。 |
/tmp |
系統的臨時文件,一般系統重啓不會被保存。 |
/usr |
包含了系統用戶工具和程序。 /usr/bin:非必須的普通用戶可執行命令 /usr/include:標準頭文件 /usr/lib:/usr/bin/ 和 /usr/sbin/的庫文件 /usr/sbin:非必須的可執行文件 /usr/src:內核源碼 /usr/X11R6:X Window System, Version 11, Release 6. |
/srv |
該目錄存放一些服務啓動之後需要提取的數據 |
一 、Linux文件結構
文件結構是文件存放在磁盤等存貯設備上的組織方法。主要體現在對文件和目錄的組織上。
目錄提供了管理文件的一個方便而有效的途徑。
Linux使用標準的目錄結構,在安裝的時候,安裝程序就已經爲用戶創建了文件系統和完整而固定的目錄組成形式,並指定了每個目錄的作用和其中的文件類型。
/根目錄
┃
┏━━┳━━━┳━━━┳━━━╋━━━┳━━━┳━━━┳━━━┓
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃
bin home dev etc lib sbin tmp usr var
┃ ┃
┏━┻━┓ ┏━━┳━━┳━━┳━┻━┳━━┓
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃
rc.d cron.d X11R6 src lib local man bin
┃
┏━━━┳━━┳━┻━┳━━━┓
┃ ┃ ┃ ┃ ┃
init.d rc0.d rc1.d rc2.d …… linux bin lib src
Linux採用的是樹型結構。最上層是根目錄,其他的所有目錄都是從根目錄出發而生成的。微軟的DOS和windows也是採用樹型結構,但是在DOS和 windows中這樣的樹型結構的根是磁盤分區的盤符,有幾個分區就有幾個樹型結構,他們之間的關係是並列的。但是在linux中,無論操作系統管理幾個磁盤分區,這樣的目錄樹只有一個。從結構上講,各個磁盤分區上的樹型目錄不一定是並列的。
如果這樣講不好理解的話,我來舉個例子:
有一塊硬盤,分成了4個分區,分別是/;/boot;/usr和windows下的fat
對於/和/boot或者/和/usr,它們是從屬關係;對於/boot和/usr,它們是並列關係。
如果我把windows下的fat分區掛載到/mnt/winc下,(掛載??哦,別急,呵呵,一會就講,一會就講。)那麼對於/mnt/winc和/usr或/mnt/winc和/boot來說,它們是從屬於目錄樹上沒有任何關係的兩個分支。
因爲linux是一個多用戶系統,制定一個固定的目錄規劃有助於對系統文件和不同的用戶文件進行統一管理。但就是這一點讓很多從windows轉到linux的初學者感到頭疼。下面列出了linux下一些主要目錄的功用。
/bin 二進制可執行命令
/dev 設備特殊文件
/etc 系統管理和配置文件
/etc/rc.d 啓動的配置文件和腳本
/home 用戶主目錄的基點,比如用戶user的主目錄就是/home/user,可以用~user表示
/lib 標準程序設計庫,又叫動態鏈接共享庫,作用類似windows裏的.dll文件
/sbin 系統管理命令,這裏存放的是系統管理員使用的管理程序
/tmp 公用的臨時文件存儲點
/root 系統管理員的主目錄(呵呵,特權階級)
/mnt 系統提供這個目錄是讓用戶臨時掛載其他的文件系統。
/lost+found 這個目錄平時是空的,系統非正常關機而留下“無家可歸”的文件(windows下叫什麼.chk)就在這裏
/proc 虛擬的目錄,是系統內存的映射。可直接訪問這個目錄來獲取系統信 息。
/var 某些大文件的溢出區,比方說各種服務的日誌文件
/usr 最龐大的目錄,要用到的應用程序和文件幾乎都在這個目錄。其中包 含:
/usr/X11R6 存放X window的目錄
/usr/bin 衆多的應用程序
/usr/sbin 超級用戶的一些管理程序
/usr/doc linux文檔
/usr/include linux下開發和編譯應用程序所需要的頭文件
/usr/lib 常用的動態鏈接庫和軟件包的配置文件
/usr/man 幫助文檔
/usr/src 源代碼,linux內核的源代碼就放在/usr/src/linux裏
/usr/local/bin 本地增加的命令
/usr/local/lib 本地增加的庫
二 、linux文件系統
文件系統指文件存在的物理空間,linux系統中每個分區都是一個文件系統,都有自己的目錄層次結構。linux會將這些分屬不同分區的、單獨的文件系統按一定的方式形成一個系統的總的目錄層次結構。一個操作系統的運行離不開對文件的操作,因此必然要擁有並維護自己的文件系統。
Llinux文件系統使用索引節點來記錄文件信息,作用像windows的文件分配表。
索引節點是一個結構,它包含了一個文件的長度、創建及修改時間、權限、所屬關係、磁盤中的位置等信息。一個文件系統維護了一個索引節點的數組,每個文件或目錄都與索引節點數組中的唯一一個元素對應。系統給每個索引節點分配了一個號碼,也就是該節點在數組中的索引號,稱爲索引節點號。
linux文件系統將文件索引節點號和文件名同時保存在目錄中。所以,目錄只是將文件的名稱和它的索引節點號結合在一起的一張表,目錄中每一對文件名稱和索引節點號稱爲一個連接。
對於一個文件來說有唯一的索引節點號與之對應,對於一個索引節點號,卻可以有多個文件名與之對應。因此,在磁盤上的同一個文件可以通過不同的路徑去訪問它。
可以用ln命令對一個已經存在的文件再建立一個新的連接,而不復制文件的內容。連接有軟連接和硬連接之分,軟連接又叫符號連接。它們各自的特點是:
硬連接:原文件名和連接文件名都指向相同的物理地址。
目錄不能有硬連接;硬連接不能跨越文件系統(不能跨越不同的分區)
文件在磁盤中只有一個拷貝,節省硬盤空間;
由於刪除文件要在同一個索引節點屬於唯一的連接時才能成功,因此可以防止不必要的誤刪除。
符號連接:用ln -s命令建立文件的符號連接符號連接是linux特殊文件的一種,作爲一個文件,它的數據是它所連接的文件的路徑名。類似windows下的快捷方式。
可以刪除原有的文件而保存連接文件,沒有防止誤刪除功能。
這一段的的內容過於抽象,又是節點又是數組的,我已經儘量通俗再通俗了,又不好加例子作演示。大家如果還是雲裏霧裏的話,我也沒有什麼辦法了,只有先記住,日後在實際應用中慢慢體會、理解了。這也是我學習的一個方法吧。
三 、掛載文件系統
由上一節知道,linux系統中每個分區都是一個文件系統,都有自己的目錄層次結構。linux會將這些分屬不同分區的、單獨的文件系統按一定的方式形成一個系統的總的目錄層次結構。這裏所說的“按一定方式”就是指的掛載。
將一個文件系統的頂層目錄掛到另一個文件系統的子目錄上,使它們成爲一個整體,稱爲掛載。把該子目錄稱爲掛載點。
舉個例子吧:
根分區:
/根目錄
┃
┏━━━━┳━━━━━┳━━━━━┳━━━━━╋━━━━━┳━━━━━┳━━━━━┳━━━━━┓
┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃
bin home dev etc lib sbin tmp usr var
┃
┏━┻━┓
┃ ┃
rc.d cron.d
┃
┏━━━┳━━━┳━┻━┳━━━━┓
┃ ┃ ┃ ┃ ┃
init.d rc0.d rc1.d rc2.d ……
/usr分區 :
usr
┃
┏━━━━┳━━━╋━━━┳━━━┳━━━┓
┃ ┃ ┃ ┃ ┃ ┃
X11R6 src lib local man bin
┃ ┃
┃ ┏━━━╋━━━┓
┃ ┃ ┃ ┃
linux bin lib src
掛載之後就形成了文章開始時的那個圖。像不像掛上去的?
注意:1、掛載點必須是一個目錄。
2、一個分區掛載在一個已存在的目錄上,這個目錄可以不爲空,但掛載後這個目錄下以前的內容將不可用。
對於其他操作系統建立的文件系統的掛載也是這樣。但是需要理解的是:光盤、軟盤、其他操作系統使用的文件系統的格式與linux使用的文件系統格式是不一樣的。光盤是ISO9660;軟盤是fat16或ext2;windows NT是fat16、NTFS;windows98是fat16、fat32;windows2000和windowsXP是fat16、fat32、 NTFS。掛載前要了解linux是否支持所要掛載的文件系統格式。
掛載時使用mount命令:
格式:mount [-參數] [設備名稱] [掛載點]
其中常用的參數有
-t 指定設備的文件系統類型,常見的有:
minix linux最早使用的文件系統
ext2 linux目前常用的文件系統
msdos MS-DOS的fat,就是fat16
vfat windows98常用的fat32
nfs 網絡文件系統
iso9660 CD-ROM光盤標準文件系統
ntfs windows NT 2000的文件系統
hpfs OS/2文件系統
auto 自動檢測文件系統
-o 指定掛載文件系統時的選項。有些也可用在/etc/fstab中。常用的 有
codepage=XXX 代碼頁
iocharset=XXX 字符集
ro 以只讀方式掛載
rw 以讀寫方式掛載
nouser 使一般用戶無法掛載
user 可以讓一般用戶掛載設備
提醒一下,mount命令沒有建立掛載點的功能,因此你應該確保執行mount命令時,掛載點已經存在。(不懂?說白了點就是你要把文件系統掛載到哪,首先要先建上個目錄。這樣OK?)
例子:windows98裝在hda1分區,同時計算機上還有軟盤和光盤需要掛載。
# mk /mnt/winc
# mk /mnt/floppy
# mk /mnt/cdrom
# mount -t vfat /dev/hda1 /mnt/winc
# mount -t msdos /dev/fd0 /mnt/floppy
# mount -t iso9660 /dev/cdrom /mnt/cdrom
現在就可以進入/mnt/winc等目錄讀寫這些文件系統了。
要保證最後兩行的命令不出錯,要確保軟驅和光驅裏有盤。(要是硬盤的磁盤片也可以經常隨時更換的話,我想就不會犯這樣的錯誤了 :-> )
如果你的windows98目錄裏有中文文件名,使用上面的命令掛載後,顯示的是一堆亂碼。這就要用到 -o 參數裏的codepage iocharset選項。codepage指定文件系統的代碼頁,簡體中文中文代碼是936;iocharset指定字符集,簡體中文一般用cp936或 gb2312。
當掛載的文件系統linux不支持時,mount一定報錯,如windows2000的ntfs文件系統。可以重新編譯linux內核以獲得對該文件系統的支持。關於重新編譯linux內核,就不在這裏說了。
四 、自動掛載
每次開機訪問windows分區都要運行mount命令顯然太煩瑣,爲什麼訪問其他的linux分區不用使用mount命令呢?
其實,每次開機時,linux自動將需要掛載的linux分區掛載上了。那麼我們是不是可以設定讓linux在啓動的時候也掛載我們希望掛載的分區,如windows分區,以實現文件系統的自動掛載呢?
這是完全可以的。在/etc目錄下有個fstab文件,它裏面列出了linux開機時自動掛載的文件系統的列表。我的/etc/fstab文件如下:
/dev/hda2 / ext3 defaults 1 1
/dev/hda1 /boot ext3 defaults 1 2
none /dev/pts devpts gid=5,mode=620 0 0
none /proc proc defaults 0 0
none /dev/shm tmpfs defaults 0 0
/dev/hda3 swap swap defaults 0 0
/dev/cdrom /mnt/cdrom iso9660 noauto,codepage=936,iocharset=gb2312 0 0
/dev/fd0 /mnt/floppy auto noauto,owner,kudzu 0 0
/dev/hdb1 /mnt/winc vfat defaults,codepage=936,iocharset=cp936 0 0
/dev/hda5 /mnt/wind vfat defaults,codepage=936,iocharset=cp936 0 0
在/etc/fstab文件裏,第一列是掛載的文件系統的設備名,第二列是掛載點,第三列是掛載的文件系統類型,第四列是掛載的選項,選項間用逗號分隔。第五六列不知道是什麼意思,還望高手指點。
在最後兩行是我手工添加的windows下的C;D盤,加了codepage=936和iocharset=cp936參數以支持中文文件名。參數defaults實際上包含了一組默認參數:
rw 以可讀寫模式掛載
suid 開啓用戶ID和羣組ID設置位
dev 可解讀文件系統上的字符或區塊設備
exec 可執行二進制文件
auto 自動掛載
nouser 使一般用戶無法掛載
async 以非同步方式執行文件系統的輸入輸出操作
大家可以看到在這個列表裏,光驅和軟驅是不自動掛載的,參數設置爲noauto。(如果你非要設成自動掛載,你要確保每次開機時你的光驅和軟驅裏都要有盤,呵呵。)
Hadoop分佈式文件系統:架構和設計要點
一、前提和設計目標
1、硬件錯誤是常態,而非異常情況,HDFS可能是有成百上千的server組成,任何一個組件都有可能一直失效,因此錯誤檢測和快速、自動的恢復是HDFS的核心架構目標。
2、跑在HDFS上的應用與一般的應用不同,它們主要是以流式讀爲主,做批量處理;比之關注數據訪問的低延遲問題,更關鍵的在於數據訪問的高吞吐量。
3、HDFS以支持大數據集合爲目標,一個存儲在上面的典型文件大小一般都在千兆至T字節,一個單一HDFS實例應該能支撐數以千萬計的文件。
4、 HDFS應用對文件要求的是write-one-read-many訪問模型。一個文件經過創建、寫,關閉之後就不需要改變。這一假設簡化了數據一致性問題,使高吞吐量的數據訪問成爲可能。典型的如MapReduce框架,或者一個web crawler應用都很適合這個模型。
5、移動計算的代價比之移動數據的代價低。一個應用請求的計算,離它操作的數據越近就越高效,這在數據達到海量級別的時候更是如此。將計算移動到數據附近,比之將數據移動到應用所在顯然更好,HDFS提供給應用這樣的接口。
6、在異構的軟硬件平臺間的可移植性。
二、Namenode和Datanode
HDFS採用master/slave架構。一個HDFS集羣是有一個Namenode和一定數目的Datanode組成。Namenode是一箇中心服務器,負責管理文件系統的namespace和客戶端對文件的訪問。Datanode在集羣中一般是一個節點一個,負責管理節點上它們附帶的存儲。在內部,一個文件其實分成一個或多個block,這些block存儲在Datanode集合裏。Namenode執行文件系統的namespace操作,例如打開、關閉、重命名文件和目錄,同時決定block到具體Datanode節點的映射。Datanode在Namenode的指揮下進行block的創建、刪除和複製。Namenode和Datanode都是設計成可以跑在普通的廉價的運行linux的機器上。HDFS採用java語言開發,因此可以部署在很大範圍的機器上。一個典型的部署場景是一臺機器跑一個單獨的Namenode節點,集羣中的其他機器各跑一個Datanode實例。這個架構並不排除一臺機器上跑多個Datanode,不過這比較少見。
單一節點的Namenode大大簡化了系統的架構。Namenode負責保管和管理所有的HDFS元數據,因而用戶數據就不需要通過Namenode(也就是說文件數據的讀寫是直接在Datanode上)。
三、文件系統的namespace
HDFS支持傳統的層次型文件組織,與大多數其他文件系統類似,用戶可以創建目錄,並在其間創建、刪除、移動和重命名文件。HDFS不支持user quotas和訪問權限,也不支持鏈接(link),不過當前的架構並不排除實現這些特性。Namenode維護文件系統的namespace,任何對文件系統namespace和文件屬性的修改都將被Namenode記錄下來。應用可以設置HDFS保存的文件的副本數目,文件副本的數目稱爲文件的 replication因子,這個信息也是由Namenode保存。
四、數據複製
HDFS被設計成在一個大集羣中可以跨機器地可靠地存儲海量的文件。它將每個文件存儲成block序列,除了最後一個block,所有的block都是同樣的大小。文件的所有block爲了容錯都會被複制。每個文件的block大小和replication因子都是可配置的。Replication因子可以在文件創建的時候配置,以後也可以改變。HDFS中的文件是write-one,並且嚴格要求在任何時候只有一個writer。Namenode全權管理block的複製,它週期性地從集羣中的每個Datanode接收心跳包和一個Blockreport。心跳包的接收表示該Datanode節點正常工作,而Blockreport包括了該Datanode上所有的block組成的列表。
1、副本的存放,副本的存放是HDFS可靠性和性能的關鍵。HDFS採用一種稱爲rack-aware的策略來改進數據的可靠性、有效性和網絡帶寬的利用。這個策略實現的短期目標是驗證在生產環境下的表現,觀察它的行爲,構建測試和研究的基礎,以便實現更先進的策略。龐大的HDFS實例一般運行在多個機架的計算機形成的集羣上,不同機架間的兩臺機器的通訊需要通過交換機,顯然通常情況下,同一個機架內的兩個節點間的帶寬會比不同機架間的兩臺機器的帶寬大。
通過一個稱爲Rack Awareness的過程,Namenode決定了每個Datanode所屬的rack id。一個簡單但沒有優化的策略就是將副本存放在單獨的機架上。這樣可以防止整個機架(非副本存放)失效的情況,並且允許讀數據的時候可以從多個機架讀取。這個簡單策略設置可以將副本分佈在集羣中,有利於組件失敗情況下的負載均衡。但是,這個簡單策略加大了寫的代價,因爲一個寫操作需要傳輸block到多個機架。
在大多數情況下,replication因子是3,HDFS的存放策略是將一個副本存放在本地機架上的節點,一個副本放在同一機架上的另一個節點,最後一個副本放在不同機架上的一個節點。機架的錯誤遠遠比節點的錯誤少,這個策略不會影響到數據的可靠性和有效性。三分之一的副本在一個節點上,三分之二在一個機架上,其他保存在剩下的機架中,這一策略改進了寫的性能。
2、副本的選擇,爲了降低整體的帶寬消耗和讀延時,HDFS會盡量讓reader讀最近的副本。如果在reader的同一個機架上有一個副本,那麼就讀該副本。如果一個HDFS集羣跨越多個數據中心,那麼reader也將首先嚐試讀本地數據中心的副本。
3、SafeMode
Namenode啓動後會進入一個稱爲SafeMode的特殊狀態,處在這個狀態的Namenode是不會進行數據塊的複製的。Namenode從所有的 Datanode接收心跳包和Blockreport。Blockreport包括了某個Datanode所有的數據塊列表。每個block都有指定的最小數目的副本。當Namenode檢測確認某個Datanode的數據塊副本的最小數目,那麼該Datanode就會被認爲是安全的;如果一定百分比(這個參數可配置)的數據塊檢測確認是安全的,那麼Namenode將退出SafeMode狀態,接下來它會確定還有哪些數據塊的副本沒有達到指定數目,並將這些block複製到其他Datanode。
五、文件系統元數據的持久化
Namenode存儲HDFS的元數據。對於任何對文件元數據產生修改的操作,Namenode都使用一個稱爲Editlog的事務日誌記錄下來。例如,在HDFS中創建一個文件,Namenode就會在Editlog中插入一條記錄來表示;同樣,修改文件的replication因子也將往 Editlog插入一條記錄。Namenode在本地OS的文件系統中存儲這個Editlog。整個文件系統的namespace,包括block到文件的映射、文件的屬性,都存儲在稱爲FsImage的文件中,這個文件也是放在Namenode所在系統的文件系統上。
Namenode在內存中保存着整個文件系統namespace和文件Blockmap的映像。這個關鍵的元數據設計得很緊湊,因而一個帶有4G內存的 Namenode足夠支撐海量的文件和目錄。當Namenode啓動時,它從硬盤中讀取Editlog和FsImage,將所有Editlog中的事務作用(apply)在內存中的FsImage ,並將這個新版本的FsImage從內存中flush到硬盤上,然後再truncate這個舊的Editlog,因爲這個舊的Editlog的事務都已經作用在FsImage上了。這個過程稱爲checkpoint。在當前實現中,checkpoint只發生在Namenode啓動時,在不久的將來我們將實現支持週期性的checkpoint。
Datanode並不知道關於文件的任何東西,除了將文件中的數據保存在本地的文件系統上。它把每個HDFS數據塊存儲在本地文件系統上隔離的文件中。 Datanode並不在同一個目錄創建所有的文件,相反,它用啓發式地方法來確定每個目錄的最佳文件數目,並且在適當的時候創建子目錄。在同一個目錄創建所有的文件不是最優的選擇,因爲本地文件系統可能無法高效地在單一目錄中支持大量的文件。當一個Datanode啓動時,它掃描本地文件系統,對這些本地文件產生相應的一個所有HDFS數據塊的列表,然後發送報告到Namenode,這個報告就是Blockreport。
六、通訊協議
所有的HDFS通訊協議都是構建在TCP/IP協議上。客戶端通過一個可配置的端口連接到Namenode,通過ClientProtocol與 Namenode交互。而Datanode是使用DatanodeProtocol與Namenode交互。從ClientProtocol和 Datanodeprotocol抽象出一個遠程調用(RPC),在設計上,Namenode不會主動發起RPC,而是是響應來自客戶端和 Datanode 的RPC請求。
七、健壯性
HDFS的主要目標就是實現在失敗情況下的數據存儲可靠性。常見的三種失敗:Namenode failures, Datanode failures和網絡分割(network partitions)。
1、硬盤數據錯誤、心跳檢測和重新複製
每個Datanode節點都向Namenode週期性地發送心跳包。網絡切割可能導致一部分Datanode跟Namenode失去聯繫。 Namenode通過心跳包的缺失檢測到這一情況,並將這些Datanode標記爲dead,不會將新的IO請求發給它們。寄存在dead Datanode上的任何數據將不再有效。Datanode的死亡可能引起一些block的副本數目低於指定值,Namenode不斷地跟蹤需要複製的 block,在任何需要的情況下啓動複製。在下列情況可能需要重新複製:某個Datanode節點失效,某個副本遭到損壞,Datanode上的硬盤錯誤,或者文件的replication因子增大。
2、集羣均衡
HDFS支持數據的均衡計劃,如果某個Datanode節點上的空閒空間低於特定的臨界點,那麼就會啓動一個計劃自動地將數據從一個Datanode搬移到空閒的Datanode。當對某個文件的請求突然增加,那麼也可能啓動一個計劃創建該文件新的副本,並分佈到集羣中以滿足應用的要求。這些均衡計劃目前還沒有實現。
3、數據完整性
從某個Datanode獲取的數據塊有可能是損壞的,這個損壞可能是由於Datanode的存儲設備錯誤、網絡錯誤或者軟件bug造成的。HDFS客戶端軟件實現了HDFS文件內容的校驗和。當某個客戶端創建一個新的HDFS文件,會計算這個文件每個block的校驗和,並作爲一個單獨的隱藏文件保存這些校驗和在同一個HDFS namespace下。當客戶端檢索文件內容,它會確認從Datanode獲取的數據跟相應的校驗和文件中的校驗和是否匹配,如果不匹配,客戶端可以選擇從其他Datanode獲取該block的副本。
4、元數據磁盤錯誤
FsImage和Editlog是HDFS的核心數據結構。這些文件如果損壞了,整個HDFS實例都將失效。因而,Namenode可以配置成支持維護多個FsImage和Editlog的拷貝。任何對FsImage或者Editlog的修改,都將同步到它們的副本上。這個同步操作可能會降低 Namenode每秒能支持處理的namespace事務。這個代價是可以接受的,因爲HDFS是數據密集的,而非元數據密集。當Namenode重啓的時候,它總是選取最近的一致的FsImage和Editlog使用。
Namenode在HDFS是單點存在,如果Namenode所在的機器錯誤,手工的干預是必須的。目前,在另一臺機器上重啓因故障而停止服務的Namenode這個功能還沒實現。
5、快照
快照支持某個時間的數據拷貝,當HDFS數據損壞的時候,可以恢復到過去一個已知正確的時間點。HDFS目前還不支持快照功能。
八、數據組織
1、數據塊
兼容HDFS的應用都是處理大數據集合的。這些應用都是寫數據一次,讀卻是一次到多次,並且讀的速度要滿足流式讀。HDFS支持文件的write- once-read-many語義。一個典型的block大小是64MB,因而,文件總是按照64M切分成chunk,每個chunk存儲於不同的 Datanode
2、步驟
某個客戶端創建文件的請求其實並沒有立即發給Namenode,事實上,HDFS客戶端會將文件數據緩存到本地的一個臨時文件。應用的寫被透明地重定向到這個臨時文件。當這個臨時文件累積的數據超過一個block的大小(默認64M),客戶端纔會聯繫Namenode。Namenode將文件名插入文件系統的層次結構中,並且分配一個數據塊給它,然後返回Datanode的標識符和目標數據塊給客戶端。客戶端將本地臨時文件flush到指定的 Datanode上。當文件關閉時,在臨時文件中剩餘的沒有flush的數據也會傳輸到指定的Datanode,然後客戶端告訴Namenode文件已經關閉。此時Namenode纔將文件創建操作提交到持久存儲。如果Namenode在文件關閉前掛了,該文件將丟失。
上述方法是對通過對HDFS上運行的目標應用認真考慮的結果。如果不採用客戶端緩存,由於網絡速度和網絡堵塞會對吞估量造成比較大的影響。
3、流水線複製
當某個客戶端向HDFS文件寫數據的時候,一開始是寫入本地臨時文件,假設該文件的replication因子設置爲3,那麼客戶端會從Namenode 獲取一張Datanode列表來存放副本。然後客戶端開始向第一個Datanode傳輸數據,第一個Datanode一小部分一小部分(4kb)地接收數據,將每個部分寫入本地倉庫,並且同時傳輸該部分到第二個Datanode節點。第二個Datanode也是這樣,邊收邊傳,一小部分一小部分地收,存儲在本地倉庫,同時傳給第三個Datanode,第三個Datanode就僅僅是接收並存儲了。這就是流水線式的複製。
九、可訪問性
HDFS給應用提供了多種訪問方式,可以通過DFSShell通過命令行與HDFS數據進行交互,可以通過java API調用,也可以通過C語言的封裝API訪問,並且提供了瀏覽器訪問的方式。正在開發通過WebDav協議訪問的方式。具體使用參考文檔。
十、空間的回收
1、文件的刪除和恢復
用戶或者應用刪除某個文件,這個文件並沒有立刻從HDFS中刪除。相反,HDFS將這個文件重命名,並轉移到/trash目錄。當文件還在/trash目錄時,該文件可以被迅速地恢復。文件在/trash中保存的時間是可配置的,當超過這個時間,Namenode就會將該文件從namespace中刪除。文件的刪除,也將釋放關聯該文件的數據塊。注意到,在文件被用戶刪除和HDFS空閒空間的增加之間會有一個等待時間延遲。
當被刪除的文件還保留在/trash目錄中的時候,如果用戶想恢復這個文件,可以檢索瀏覽/trash目錄並檢索該文件。/trash目錄僅僅保存被刪除文件的最近一次拷貝。/trash目錄與其他文件目錄沒有什麼不同,除了一點:HDFS在該目錄上應用了一個特殊的策略來自動刪除文件,目前的默認策略是刪除保留超過6小時的文件,這個策略以後會定義成可配置的接口。
2、Replication因子的減小
當某個文件的replication因子減小,Namenode會選擇要刪除的過剩的副本。下次心跳檢測就將該信息傳遞給Datanode, Datanode就會移除相應的block並釋放空間,同樣,在調用setReplication方法和集羣中的空閒空間增加之間會有一個時間延遲。