日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > windows >内容正文

windows

(2021) 24 [持久化] 文件系统API

發(fā)布時間:2025/3/8 windows 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 (2021) 24 [持久化] 文件系统API 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

(2021) 24 [持久化] 文件系統API

南京大學操作系統課蔣炎巖老師網絡課程筆記。

視頻:https://www.bilibili.com/video/BV1HN41197Ko?p=24
講義:http://jyywiki.cn/OS/2021/slides/14.slides#/

背景

回顧

硬件視角:持久化的“層層抽象”

  • 物理層1-bit存儲
  • 設備層I/O設備(寄存器)
  • 驅動層(可讀可寫可控制的對象)

用戶(應用程序)視角:對象 + API

  • C:\Program Files\…
  • /etc/apt/souces.list
  • /bin/bash

中間的部分:文件系統

本次課的內容和目標

理解 “文件系統” 的設計

  • “文件系統” 的需求分析
    • 需要什么對象
    • 提供什么 API

文件系統概述

為什么需要文件系統?

存點什么

計算機:輔助人類更好地完成物理世界中的任務開機以后,必須得有點 “代表物理世界” 的東西。

“開機” 后操作系統中應該有的對象

  • 各類數據
    • 《操作系統》點名冊/成績單/Online Judge 結果/…
    • 處理這些數據的程序
      • wc, grep, vim, LibreOffice, …
      • libc, X11, gnome-settings-manager, …
  • 這些 “對象” 應該被持久地保存在介質上

別亂套

沒問題!我們已經講過 1-bit 的存儲了,但讓應用程序直接通過驅動訪問存儲設備 (1950s)?不合適!這樣就亂套了。

今天的系統中有不止一個程序

  • 每個程序還需要考慮各種訪問權限、并發(fā)控制……
  • 程序出 bug 了,不小心弄壞了整塊磁盤

文件系統:設計目標

  • 提供合理的 API 使多個應用程序能共享數據
  • 提供一定的隔離,使惡意/出錯程序的傷害不能任意擴大
    • 這就是文件系統
      • 你會怎么辦?
  • 文件系統:存儲設備的虛擬化

    磁盤 (I/O 設備) = 一個可以讀/寫的字節(jié)序列 —> 虛擬磁盤 (文件) = 一個可以讀/寫/的動態(tài)字節(jié)序列

    結合我們操作系統課前面所學,可以類比:

    • 進程抽象:一個 CPU → 切分時間片,在時間上共享
    • 虛擬存儲:一份內存 → 劃分給多個虛擬地址空間
    • 文件系統:一個物理磁盤 → 多個虛擬磁盤

    文件系統 API: 虛擬磁盤管理

    • 需要解決的問題
      • 虛擬磁盤的命名、查找、權限
      • 虛擬磁盤的操作 (讀寫)

    虛擬磁盤:命名管理

    接下來我們就來看看,兩個最主流的文件系統是如何實現磁盤到虛擬磁盤的虛擬化的。

    文件系統 = “虛擬磁盤名” 到 “虛擬磁盤對象” 的映射

    我們的系統中可能會有上百萬個文件,這時候,局部性就發(fā)揮很大作用了。

    目錄:文件/目錄的集合 (形成一棵樹),邏輯相關的數據存放在相近的目錄

    . └── 學習資料├── .學習資料(隱藏)├── 問題求解1├── 問題求解2├── 問題求解3└── 問題求解4

    Windows文件系統

    樹總得有個根結點

    Windows: 每個驅動器是一棵樹

    • C:\:“C 盤根目錄”
      • C:\Program Files\, C:\Windows, C:\Users, …
    • D:\: “D 盤根目錄”
      • D:\學習資料\
    • 優(yōu)盤分配給新的盤符
    • 為什么沒有 A:\, B:\? A、B盤歷史上是為軟驅預留的

    Linux、UNIX文件系統

    UNIX/Linux只有一個根/,其他沒有了,那第二個設備呢?優(yōu)盤呢???該怎么辦

    文件系統的掛載

    掛載設備

    UNIX 允許任何一個目錄都可以 “掛載” 一個設備代表的目錄樹

    非常靈活的設計;充分利用了目錄的局部性。

    比如 128G 優(yōu)盤分成了兩個 64G 分區(qū) (Linux/和 exFAT)

    可以直接使用mount命令 “掛載” 到一個目錄上

    • 目錄里原先的內容會暫時消失 (但不會丟失),改換為你掛載的設備的內容。

    • /, /home, /var 可以是獨立的磁盤

    如何 mount 一個文件?
    • disk-img.tar.gz的掛載:創(chuàng)建一個 “l(fā)oopback” 設備(lsblk 可以看到),實際上loopback相當于是將一個文件(虛擬磁盤設備)反虛擬化為一個設備。
    • 然后就變成掛載設備了,可以 strace 一下,看看操作系統提供了哪些 API。

    Filesystem Hierarchy Standard (FHS)

    Linux的文件樹標準。

    掛載機制的好處

    掛載機制非常靈活,比如說,你有兩塊磁盤,那你可以將你的/根目錄和/home主目錄分別掛載在兩塊磁盤上,在/根目錄下創(chuàng)建一個空的主目錄即可。這樣的好處是對根目錄和主目錄的訪問帶寬就分開了,你可以同時讀寫這兩個目錄下的內容。

    目錄API(系統調用)

    目錄管理:創(chuàng)建、刪除、遍歷

    這個簡單

    • mkdir

      • 創(chuàng)建一個目錄
      • 可以設置訪問權限
    • rmdir

      • 刪除一個空目錄
      • 沒有 “遞歸刪除” 的系統調用
        • (應用層能實現的,就不要在操作系統層實現)
        • rm -rf 會遍歷目錄,逐個刪除 (試試 strace)
    • getdents

      • 返回count個目錄項 (ls, find, tree 都使用這個),以點開頭的目錄會被系統調用返回,只是 ls 沒有顯示。

        ls不顯示以.所有開頭的文件的文件,這時為了隱藏當前目錄.和上一級目錄..,但是在實現上所有以.開頭的文件或目錄都不會被顯示。這使得我們可以通過在文件或目錄前面加.來對其做簡單的隱藏。使用ls -a可以顯示全部。

    小啟示:我們遇到Linux系統中的問題時通常會上Stack Overflow來查找別人解決問題的方法,這當然是很好的,Stack Overflow有許多有用的技巧。但實際上,Linux系統是self-contain的,即就算沒有互聯網,我們也可以通過man page配合strace等工具來找到我們想要的一切說明,并且,man page是最權威的。當然,Stack Overflow上的一些別人的巧妙的方法也是互聯網搜索的優(yōu)勢。

    硬(hard)鏈接

    UNIX文件指針

    在UNIX中,文件和目錄完全不是同一個概念,雖然我們平時看著它們仿佛并列地躺在某個文件夾下。但實際上,目錄是樹狀結構組織的,而文件,卻是每個目錄指向某個文件的指針。并且,每個文件都有一個編號,可能會有多個目錄下的多個指針都指向同一個編號的文件。它們雖然存在于不同的目錄下,甚至名稱也不同,但是同一個編號的文件是完全相同的,修改也是同步的。如下圖所示:

    我們可以做這樣的測試:

    創(chuàng)建測試目錄并在其中的a.txt寫入Hello World!

    mkdir test && cd test && touch a.txt vim a.txt # 寫入 Hello World!

    創(chuàng)建a.txt的硬鏈接b.txt:

    ln a.txt b.txt

    我們查看兩個文件的內容,輸出顯示都是同樣的Hello World:

    cat *.txt # 輸出: # Hello World! # Hello World!

    這時,我們修改b.txt的內容為Hello World! Changed~,再查看兩個文件的內容:

    vim b.txt # 更改為 Hello World! Changed~ cat *.txt # 輸出: # Hello World! Changed~ # Hello World! Changed~

    結果兩個文件都被修改了,這就是硬鏈接,我們可以通過-i參數查看文件的編號:

    ls -i # 輸出: # 8593746 a.txt 8593746 b.txt

    可以看到,兩個文件其實是同一個編號的文件的不同鏈接。即硬鏈接的圖示如下:

    硬鏈接

    注意

    • 目錄中僅存儲指向文件數據的指針
    • 允許一個文件被多個目錄引用
    • 不能鏈接目錄 ?
    • 不能跨文件系統 ?

    小知識:其實所有的文件都是硬連接 (ls -i 查看)

    • 刪除的系統調用稱為 “unlink” (引用計數)

    應用場景

    可以給文件起別名,同步,省空間。

    需求:系統中可能有同一個運行庫的多個版本

    • libc-2.27.so, libc-2.26.so, …
    • 還需要一個 “當前版本的 libc”
      • 程序需要鏈接 “l(fā)ibc.so.6”
      • 能否避免文件的一份拷貝?

    軟(symbolic)鏈接

    軟鏈接:在文件里存儲一個 “跳轉提示”,相當于”快捷方式“。

    • 軟鏈接也是一個文件
      • 當引用這個文件時,去找另一個文件
      • 另一個文件的絕對/相對路徑以文本形式存儲在文件里
      • 可以跨文件系統、可以鏈接目錄、……好處多多
      • 甚至,符號鏈接可以指向一個暫時不存在的文件或目錄,只要這個不存在文件或目錄將來某天存在了,這個符號鏈接就會生效

    ln -s 創(chuàng)建軟鏈接,用的是symlink 系統調用。現在系統中/lib下的共享庫,通常都是軟鏈接。

    我們接著上面硬鏈接的例子來看一下二者的區(qū)別:

    再在測試目錄下創(chuàng)建a.txt的軟鏈接c.txt:

    ln -s a.txt c.txt

    我們用-li參數查看測試目錄中的三個文件:

    ls -li # 輸出 # 8593746 -rw-rw-r-- 2 ps ps 22 10月 1 22:14 a.txt # 8593746 -rw-rw-r-- 2 ps ps 22 10月 1 22:14 b.txt # 8593742 lrwxrwxrwx 1 ps ps 5 10月 1 22:35 c.txt -> a.txt

    在這里,b,c分別是a的硬、軟鏈接。可以看到,a和c的文件編號是不一樣的,因為它們是軟鏈接。但是,它們的修改仍然是同步的,因為我們在試圖修改c的時候,系統會順著上面輸出的軟鏈接箭頭去尋找,直到找到一個真實的文件或者目錄。我們還是來試一下:

    vim c.txt # 修改為Hello World! Changed~ Soft~ cat *.txt # 輸出: # Hello World! Changed~ Soft~ # Hello World! Changed~ Soft~ # Hello World! Changed~ Soft~

    與預期一致。此時測試目錄下的鏈接關系應該如下圖所示:

    軟鏈接可能帶來的麻煩

    軟鏈接可以隨意創(chuàng)建 (當前可能不合法;但未來可能合法),操作系統在處理軟鏈接時會執(zhí)行路徑解析,,允許多次間接鏈接,會有意想不到的復雜性 ,a → b → c (遞歸解析)。可以創(chuàng)建軟連接的硬鏈接 (因為軟鏈接也是文件),通過ls -i 可以看到。

    符號鏈接成環(huán)?ln -s . a。所有處理符號鏈接的程序 (tree, find, …) 都要考慮遞歸的情況。它們默認遇到軟鏈接就跳過,如果加上-L參數強制使它們考慮軟鏈接的話,它們也會很小心的檢測成環(huán)和遞歸的情況并適時退出。

    進程的 “當前目錄”

    working/current directory

    • pwd 命令或 $PWD 環(huán)境變量可以查看
    • 用chdir系統調用修改
      • 對應 shell 中的 cd
      • 注意 cd 是 shell 的內部命令,不存在 /bin/cd。不能被strace

    問題:線程是共享 working directory, 還是各自獨立持有一個?

    文件API(系統調用)

    復習:文件和文件描述符

    文件:虛擬的磁盤

    • 磁盤是一個“字節(jié)序列”
    • 支持讀/寫操作

    文件描述符:進程訪問文件(操作系統對象)的 “指針”

    • 通過open / pipe獲得
    • 通過close釋放
    • 通過dup / dup2復制
    • fork時繼承

    復習:mmap

    將一整個文件映射到進程的地址空間。

    使用 open 打開一個文件后

    • 用 MAP_SHARED 將文件映射到地址空間中
    • 用 MAP_PRIVATE 創(chuàng)建一個 copy-on-write 的副本
    void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset); // 映射 fd 的 offset 開始的 length 字節(jié) int munmap(void *addr, size_t length); int msync(void *addr, size_t length, int flags);

    小問題:

    • 映射的長度超過文件大小會發(fā)生什么?
      • (RTFM, “Errors” section): SIGBUS…
        • bus error 的常見來源 (M5)
        • ftruncate 可以改變文件大小

    文件系統的游標(偏移量)

    文件系統的游標(偏移量)介紹

    文件的讀寫時,文件描述符自帶 “游標”,這樣就不用每次都指定文件讀/寫到哪里了,方便了程序員順序訪問文件

    例子

    • read(fd, buf, 512); - 第一個 512 字節(jié)
    • read(fd, buf, 512); - 第二個 512 字節(jié)
    • lseek(fd, -1, SEEK_END);- 最后一個字節(jié)

    偏移量管理的問題 1

    mmap, lseek, ftruncate 互相交互的情況

    • 初始時文件大小為 0
    • mmap (length = 2 MiB)
    • lseek to 3 MiB (SEEK_SET)
    • ftruncate to 1 MiB

    在任何時刻,寫入數據的行為是什么?

    • blog posts 不會告訴你全部
    • RTFM & 做實驗!

    偏移量管理的問題 2

    我們知道,文件描述符在 fork 時會被子進程繼承。那父子進程應該共用偏移量,還是應該各自持有偏移量?

    • 這決定了 offset 存儲在哪里

    考慮應用場景

    • 父子進程同時寫入文件
      • 各自持有偏移量 → 父子進程需要協調偏移量的競爭
        • (race condition)
      • 共享偏移量 → 操作系統管理偏移量
        • 雖然仍然共享,但操作系統保證 write 的原子性 ?

    偏移量管理:行為

    操作系統的每一個 API 都可能和其他 API 有交互

  • open 時,獲得一個獨立的 offset
  • dup 時,兩個文件描述符共享 offset
  • fork 時,父子進程共享 offset
  • execve 時文件描述符不變
  • O_APPEND 方式打開的文件,偏移量永遠在最后 (無論是否 fork)
    • modification of the file offset and the write operation are performed as a single atomic step
  • 這也是 fork 被批評的一個原因,(在當時) 好的設計可能成為系統演化過程中的包袱,今天的 fork 可謂是 “補丁滿滿”。

    總結

    本次課內容與目標

    • 理解 “文件系統” 的設計
      • 設備、文件和目錄
      • mount, chdir, mkdir, rmdir, link, unlink, symlink, open, mmap, read, write, lseek, ftruncate, …

    Takeaway messages

    • 一個經典的設計:簡潔、通用、富有遠見
    • 但無論多么有遠見,在時間面前都會千瘡百孔

    總結

    以上是生活随笔為你收集整理的(2021) 24 [持久化] 文件系统API的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。