<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          文件系統(tǒng):隱匿在 Linux 背后的機制

          共 5384字,需瀏覽 11分鐘

           ·

          2020-09-05 04:12








          在 Linux 中,最直觀、最可見的部分就是 文件系統(tǒng)(file system)。下面我們就來一起探討一下關于 Linux 中國的文件系統(tǒng),系統(tǒng)調(diào)用以及文件系統(tǒng)實現(xiàn)背后的原理和思想。這些思想中有一些來源于 MULTICS,現(xiàn)在已經(jīng)被 Windows 等其他操作系統(tǒng)使用。Linux 的設計理念就是 小的就是好的(Small is Beautiful) 。雖然 Linux 只是使用了最簡單的機制和少量的系統(tǒng)調(diào)用,但是 Linux 卻提供了強大而優(yōu)雅的文件系統(tǒng)。

          Linux 文件系統(tǒng)基本概念

          Linux 在最初的設計是 MINIX1 文件系統(tǒng),它只支持 14 字節(jié)的文件名,它的最大文件只支持到 64 MB。在 MINIX 1 之后的文件系統(tǒng)是 ext 文件系統(tǒng)。ext 系統(tǒng)相較于 MINIX 1 來說,在支持字節(jié)大小和文件大小上均有很大提升,但是 ext 的速度仍沒有 MINIX 1 快,于是,ext 2 被開發(fā)出來,它能夠支持長文件名和大文件,而且具有比 MINIX 1 更好的性能。這使他成為 Linux 的主要文件系統(tǒng)。只不過 Linux 會使用 VFS 曾支持多種文件系統(tǒng)。在 Linux 鏈接時,用戶可以動態(tài)的將不同的文件系統(tǒng)掛載倒 VFS 上。

          Linux 中的文件是一個任意長度的字節(jié)序列,Linux 中的文件可以包含任意信息,比如 ASCII 碼、二進制文件和其他類型的文件是不加區(qū)分的。

          為了方便起見,文件可以被組織在一個目錄中,目錄存儲成文件的形式在很大程度上可以作為文件處理。目錄可以有子目錄,這樣形成有層次的文件系統(tǒng),Linux 系統(tǒng)下面的根目錄是 / ,它通常包含了多個子目錄。字符 / 還用于對目錄名進行區(qū)分,例如 /usr/cxuan 表示的就是根目錄下面的 usr 目錄,其中有一個叫做 cxuan 的子目錄。

          下面我們介紹一下 Linux 系統(tǒng)根目錄下面的目錄名

          • /bin,它是重要的二進制應用程序,包含二進制文件,系統(tǒng)的所有用戶使用的命令都在這里
          • /boot,啟動包含引導加載程序的相關文件
          • /dev,包含設備文件,終端文件,USB 或者連接到系統(tǒng)的任何設備
          • /etc,配置文件,啟動腳本等,包含所有程序所需要的配置文件,也包含了啟動/停止單個應用程序的啟動和關閉 shell 腳本
          • /home,本地主要路徑,所有用戶用 home 目錄存儲個人信息
          • /lib,系統(tǒng)庫文件,包含支持位于 /bin 和 /sbin 下的二進制庫文件
          • /lost+found,在根目錄下提供一個遺失+查找系統(tǒng),必須在 root 用戶下才能查看當前目錄下的內(nèi)容
          • /media,掛載可移動介質
          • /mnt,掛載文件系統(tǒng)
          • /opt,提供一個可選的應用程序安裝目錄
          • /proc,特殊的動態(tài)目錄,用于維護系統(tǒng)信息和狀態(tài),包括當前運行中進程信息
          • /root,root 用戶的主要目錄文件夾
          • /sbin,重要的二進制系統(tǒng)文件
          • /tmp, 系統(tǒng)和用戶創(chuàng)建的臨時文件,系統(tǒng)重啟時,這個目錄下的文件都會被刪除
          • /usr,包含絕大多數(shù)用戶都能訪問的應用程序和文件
          • /var,經(jīng)常變化的文件,諸如日志文件或數(shù)據(jù)庫等

          在 Linux 中,有兩種路徑,一種是 絕對路徑(absolute path) ,絕對路徑告訴你從根目錄下查找文件,絕對路徑的缺點是太長而且不太方便。還有一種是 相對路徑(relative path) ,相對路徑所在的目錄也叫做工作目錄(working directory)。

          如果 /usr/local/books 是工作目錄,那么 shell 命令

          cp?books?books-replica?

          就表示的是相對路徑,而

          cp?/usr/local/books/books?/usr/local/books/books-replica

          則表示的是絕對路徑。

          在 Linux 中經(jīng)常出現(xiàn)一個用戶使用另一個用戶的文件或者使用文件樹結構中的文件。兩個用戶共享同一個文件,這個文件位于某個用戶的目錄結構中,另一個用戶需要使用這個文件時,必須通過絕對路徑才能引用到他。如果絕對路徑很長,那么每次輸入起來會變的非常麻煩,所以 Linux 提供了一種 鏈接(link) 機制。

          舉個例子,下面是一個使用鏈接之前的圖

          以上所示,比如有兩個工作賬戶 jianshe 和 cxuan,jianshe 想要使用 cxuan 賬戶下的 A 目錄,那么它可能會輸入 /usr/cxuan/A ,這是一種未使用鏈接之后的圖。

          使用鏈接后的示意如下

          現(xiàn)在,jianshe 可以創(chuàng)建一個鏈接來使用 cxuan 下面的目錄了?!?/p>

          當一個目錄被創(chuàng)建出來后,有兩個目錄項也同時被創(chuàng)建出來,它們就是 ... ,前者代表工作目錄自身,后者代表該目錄的父目錄,也就是該目錄所在的目錄。這樣一來,在 /usr/jianshe 中訪問 cxuan 中的目錄就是 ../cxuan/xxx

          Linux 文件系統(tǒng)不區(qū)分磁盤的,這是什么意思呢?一般來說,一個磁盤中的文件系統(tǒng)相互之間保持獨立,如果一個文件系統(tǒng)目錄想要訪問另一個磁盤中的文件系統(tǒng),在 Windows 中你可以像下面這樣。

          兩個文件系統(tǒng)分別在不同的磁盤中,彼此保持獨立。

          而在 Linux 中,是支持掛載的,它允許一個磁盤掛在到另外一個磁盤上,那么上面的關系會變成下面這樣

          掛在之后,兩個文件系統(tǒng)就不再需要關心文件系統(tǒng)在哪個磁盤上了,兩個文件系統(tǒng)彼此可見。

          Linux 文件系統(tǒng)的另外一個特性是支持 加鎖(locking)。在一些應用中會出現(xiàn)兩個或者更多的進程同時使用同一個文件的情況,這樣很可能會導致競爭條件(race condition)。一種解決方法是對其進行加不同粒度的鎖,就是為了防止某一個進程只修改某一行記錄從而導致整個文件都不能使用的情況。

          POSIX 提供了一種靈活的、不同粒度級別的鎖機制,允許一個進程使用一個不可分割的操作對一個字節(jié)或者整個文件進行加鎖。加鎖機制要求嘗試加鎖的進程指定其 要加鎖的文件,開始位置以及要加鎖的字節(jié)

          Linux 系統(tǒng)提供了兩種鎖:共享鎖和互斥鎖。如果文件的一部分已經(jīng)加上了共享鎖,那么再加排他鎖是不會成功的;如果文件系統(tǒng)的一部分已經(jīng)被加了互斥鎖,那么在互斥鎖解除之前的任何加鎖都不會成功。為了成功加鎖、請求加鎖的部分的所有字節(jié)都必須是可用的。

          在加鎖階段,進程需要設計好加鎖失敗后的情況,也就是判斷加鎖失敗后是否選擇阻塞,如果選擇阻塞式,那么當已經(jīng)加鎖的進程中的鎖被刪除時,這個進程會解除阻塞并替換鎖。如果進程選擇非阻塞式的,那么就不會替換這個鎖,會立刻從系統(tǒng)調(diào)用中返回,標記狀態(tài)碼表示是否加鎖成功,然后進程會選擇下一個時間再次嘗試。

          加鎖區(qū)域是可以重疊的。下面我們演示了三種不同條件的加鎖區(qū)域。

          如上圖所示,A 的共享鎖在第四字節(jié)到第八字節(jié)進行加鎖

          如上圖所示,進程在 A 和 B 上同時加了共享鎖,其中 6 - 8 字節(jié)是重疊鎖

          如上圖所示,進程 A 和 B 和 C 同時加了共享鎖,那么第六字節(jié)和第七字節(jié)是共享鎖。

          如果此時一個進程嘗試在第 6 個字節(jié)處加鎖,此時會設置失敗并阻塞,由于該區(qū)域被 A B C 同時加鎖,那么只有等到 A B C 都釋放鎖后,進程才能加鎖成功。

          Linux 文件系統(tǒng)調(diào)用

          許多系統(tǒng)調(diào)用都會和文件與文件系統(tǒng)有關。我們首先先看一下對單個文件的系統(tǒng)調(diào)用,然后再來看一下對整個目錄和文件的系統(tǒng)調(diào)用。

          為了創(chuàng)建一個新的文件,會使用到 creat 方法,注意沒有 e。

          這里說一個小插曲,曾經(jīng)有人問 UNIX 創(chuàng)始人 Ken Thompson,如果有機會重新寫 UNIX ,你會怎么辦,他回答自己要把 creat 改成 create ,哈哈哈哈。

          這個系統(tǒng)調(diào)用的兩個參數(shù)是文件名和保護模式

          fd?=?creat("aaa",mode);

          這段命令會創(chuàng)建一個名為 aaa 的文件,并根據(jù) mode 設置文件的保護位。這些位決定了哪個用戶可能訪問文件、如何訪問。

          creat 系統(tǒng)調(diào)用不僅僅創(chuàng)建了一個名為 aaa 的文件,還會打開這個文件。為了允許后續(xù)的系統(tǒng)調(diào)用訪問這個文件,這個 creat 系統(tǒng)調(diào)用會返回一個 非負整數(shù), 這個就叫做 文件描述符(file descriptor),也就是上面的 fd。

          如果在已經(jīng)存在的文件上調(diào)用了 creat 系統(tǒng)調(diào)用,那么該文件中的內(nèi)容會被清除,從 0 開始。通過設置合適的參數(shù),open 系統(tǒng)調(diào)用也能夠創(chuàng)建文件。

          下面讓我們看一看主要的系統(tǒng)調(diào)用,如下表所示

          系統(tǒng)調(diào)用描述
          fd = creat(name,mode)一種創(chuàng)建一個新文件的方式
          fd = open(file, ...)打開文件讀、寫或者讀寫
          s = close(fd)關閉一個打開的文件
          n = read(fd, buffer, nbytes)從文件中向緩存中讀入數(shù)據(jù)
          n = write(fd, buffer, nbytes)從緩存中向文件中寫入數(shù)據(jù)
          position = lseek(fd, offset, whence)移動文件指針
          s = stat(name, &buf)獲取文件信息
          s = fstat(fd, &buf)獲取文件信息
          s = pipe(&fd[0])創(chuàng)建一個管道
          s = fcntl(fd,...)文件加鎖等其他操作

          為了對一個文件進行讀寫的前提是先需要打開文件,必須使用 creat 或者 open 打開,參數(shù)是打開文件的方式,是只讀、可讀寫還是只寫。open 系統(tǒng)調(diào)用也會返回文件描述符。打開文件后,需要使用 close 系統(tǒng)調(diào)用進行關閉。close 和 open 返回的 fd 總是未被使用的最小數(shù)量。

          什么是文件描述符?文件描述符就是一個數(shù)字,這個數(shù)字標示了計算機操作系統(tǒng)中打開的文件。它描述了數(shù)據(jù)資源,以及訪問資源的方式。

          當程序要求打開一個文件時,內(nèi)核會進行如下操作

          • 授予訪問權限
          • 全局文件表(global file table)中創(chuàng)建一個條目(entry)
          • 向軟件提供條目的位置

          文件描述符由唯一的非負整數(shù)組成,系統(tǒng)上每個打開的文件至少存在一個文件描述符。文件描述符最初在 Unix 中使用,并且被包括 Linux,macOS 和 BSD 在內(nèi)的現(xiàn)代操作系統(tǒng)所使用。

          當一個進程成功訪問一個打開的文件時,內(nèi)核會返回一個文件描述符,這個文件描述符指向全局文件表的 entry 項。這個文件表項包含文件的 inode 信息,字節(jié)位移,訪問限制等。例如下圖所示

          默認情況下,前三個文件描述符為 STDIN(標準輸入)、STDOUT(標準輸出)STDERR(標準錯誤)。

          標準輸入的文件描述符是 0 ,在終端中,默認為用戶的鍵盤輸入

          標準輸出的文件描述符是 1 ,在終端中,默認為用戶的屏幕

          與錯誤有關的默認數(shù)據(jù)流是 2,在終端中,默認為用戶的屏幕。

          在簡單聊了一下文件描述符后,我們繼續(xù)回到文件系統(tǒng)調(diào)用的探討。

          在文件系統(tǒng)調(diào)用中,開銷最大的就是 read 和 write 了。read 和 write 都有三個參數(shù)

          • 文件描述符:告訴需要對哪一個打開文件進行讀取和寫入
          • 緩沖區(qū)地址:告訴數(shù)據(jù)需要從哪里讀取和寫入哪里
          • 統(tǒng)計:告訴需要傳輸多少字節(jié)

          這就是所有的參數(shù)了,這個設計非常簡單輕巧。

          雖然幾乎所有程序都按順序讀取和寫入文件,但是某些程序需要能夠隨機訪問文件的任何部分。與每個文件相關聯(lián)的是一個指針,該指針指示文件中的當前位置。順序讀?。ɑ驅懭耄r,它通常指向要讀取(寫入)的下一個字節(jié)。如果指針在讀取 1024 個字節(jié)之前位于 4096 的位置,則它將在成功讀取系統(tǒng)調(diào)用后自動移至 5120 的位置。

          Lseek 系統(tǒng)調(diào)用會更改指針位置的值,以便后續(xù)對 read 或 write 的調(diào)用可以在文件中的任何位置開始,甚至可以超出文件末尾。

          lseek = Lseek ,段首大寫。

          lseek 避免叫做 seek 的原因就是 seek 已經(jīng)在之前 16 位的計算機上用于搜素功能了。

          Lseek 有三個參數(shù):第一個是文件的文件描述符,第二個是文件的位置;第三個告訴文件位置是相對于文件的開頭,當前位置還是文件的結尾

          lseek(int?fildes,?off_t?offset,?int?whence);

          lseek 的返回值是更改文件指針后文件中的絕對位置。lseek 是唯一從來不會造成真正磁盤查找的系統(tǒng)調(diào)用,它只是更新當前的文件位置,這個文件位置就是內(nèi)存中的數(shù)字。

          對于每個文件,Linux 都會跟蹤文件模式(常規(guī),目錄,特殊文件),大小,最后修改時間以及其他信息。程序能夠通過 stat 系統(tǒng)調(diào)用看到這些信息。第一個參數(shù)就是文件名,第二個是指向要放置請求信息結構的指針。這些結構的屬性如下圖所示。

          fstat 調(diào)用和 stat 相同,只有一點區(qū)別,fstat 可以對打開文件進行操作,而 stat 只能對路徑進行操作。

          pipe 文件系統(tǒng)調(diào)用被用來創(chuàng)建 shell 管道。它會創(chuàng)建一系列的偽文件,來緩沖和管道組件之間的數(shù)據(jù),并且返回讀取或者寫入緩沖區(qū)的文件描述符。在管道中,像是如下操作

          sort?

          sort 進程將會輸出到文件描述符1,也就是標準輸出,寫入管道中,而 head 進程將從管道中讀入。在這種方式中,sort 只是從文件描述符 0 中讀取并寫入到文件描述符 1 (管道)中,甚至不知道它們已經(jīng)被重定向了。如果沒有重定向的話,sort 會自動的從鍵盤讀入并輸出到屏幕中。

          最后一個系統(tǒng)調(diào)用是 fcntl,它用來鎖定和解鎖文件,應用共享鎖和互斥鎖,或者是執(zhí)行一些文件相關的其他操作。

          現(xiàn)在我們來關心一下和整體目錄和文件系統(tǒng)相關的系統(tǒng)調(diào)用,而不是把精力放在單個的文件上,下面列出了這些系統(tǒng)調(diào)用,我們一起來看一下。

          系統(tǒng)調(diào)用描述
          s = mkdir(path,mode)創(chuàng)建一個新的目錄
          s = rmdir(path)移除一個目錄
          s = link(oldpath,newpath)創(chuàng)建指向已有文件的鏈接
          s = unlink(path)取消文件的鏈接
          s = chdir(path)改變工作目錄
          dir = opendir(path)打開一個目錄讀取
          s = closedir(dir)關閉一個目錄
          dirent = readdir(dir)讀取一個目錄項
          rewinddir(dir)回轉目錄使其在此使用

          可以使用 mkdir 和 rmdir 創(chuàng)建和刪除目錄。但是需要注意,只有目錄為空時才可以刪除。

          創(chuàng)建一個指向已有文件的鏈接時會創(chuàng)建一個目錄項(directory entry)。系統(tǒng)調(diào)用 link 來創(chuàng)建鏈接,oldpath 代表已有的路徑,newpath 代表需要鏈接的路徑,使用 unlink 可以刪除目錄項。當文件的最后一個鏈接被刪除時,這個文件會被自動刪除。

          使用 chdir 系統(tǒng)調(diào)用可以改變工作目錄。

          最后四個系統(tǒng)調(diào)用是用于讀取目錄的。和普通文件類似,他們可以被打開、關閉和讀取。每次調(diào)用 readdir 都會以固定的格式返回一個目錄項。用戶不能對目錄執(zhí)行寫操作,但是可以使用 creat 或者 link 在文件夾中創(chuàng)建一個目錄,或使用 unlink 刪除一個目錄。用戶不能在目錄中查找某個特定文件,但是可以使用 rewindir 作用于一個打開的目錄,使他能在此從頭開始讀取。

          推薦閱讀:

          完全整理 | 365篇高質技術文章目錄整理

          算法之美 : 棧和隊列

          主宰這個世界的10大算法

          徹底理解cookie、session、token

          淺談什么是遞歸算法

          專注服務器后臺技術棧知識總結分享

          歡迎關注交流共同進步

          碼農(nóng)有道?coding


          碼農(nóng)有道,為您提供通俗易懂的技術文章,讓技術變的更簡單

          嘿,你在看嗎
          瀏覽 27
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  日本黄免费观看 | 狠狠躁日日躁夜夜躁A片视频小说 | 中文字幕在线看片 | 亲亲艺术一区二区 | 7777国产 |