<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>

          FUSE文件系統(tǒng)

          共 3990字,需瀏覽 8分鐘

           ·

          2020-11-08 01:29

          Fuse(filesystem in userspace),是一個用戶空間的文件系統(tǒng)。通過fuse內(nèi)核模塊的支持,開發(fā)者只需要根據(jù)fuse提供的接口實現(xiàn)具體的文件操作就可以實現(xiàn)一個文件系統(tǒng)。由于其主要實現(xiàn)代碼位于用戶空間中,而不需要重新編譯內(nèi)核,這給開發(fā)者帶來了眾多便利。Google在Android 11上,為了實現(xiàn)scoped storage,也引入了fuse。下面我們從Fuse的架構(gòu)設(shè)計以及具體的實現(xiàn)細節(jié)來談一談fuse文件系統(tǒng)。



          一、?Fuse架構(gòu)設(shè)計



          圖片摘自《To FUSE or Not to FUSE: Performance of User-Space File Systems》


          Fuse包含一個內(nèi)核模塊和一個用戶空間守護進程(下文稱fuse daemon)。內(nèi)核模塊加載時被注冊成 Linux 虛擬文件系統(tǒng)的一個 fuse 文件系統(tǒng)驅(qū)動。此外,還注冊了一個/dev/fuse的塊設(shè)備。該塊設(shè)備作為fuse daemon與內(nèi)核通信的橋梁,fuse daemon通過/dev/fuse讀取fuse request,處理后將reply寫入/dev/fuse。


          上圖詳細展示了fuse的構(gòu)架。當application掛在fuse文件系統(tǒng)上,并且執(zhí)行一些系統(tǒng)調(diào)用時,VFS會將這些操作路由至fuse driver,fuse driver創(chuàng)建了一個fuse request結(jié)構(gòu)體,并把request保存在請求隊列中。此時,執(zhí)行操作的進程會被阻塞,同時fuse daemon通過讀取/dev/fuse將request從內(nèi)核隊列中取出,并且提交操作到底層文件系統(tǒng)中(例如 EXT4 或 F2FS)。當處理完請求后,fuse daemon會將reply寫回/dev/fuse,fuse driver此時把requset標記為completed,最終喚醒用戶進程。



          二、?Fuse實現(xiàn)細節(jié)



          下面我們基于Android 11 AOSP 以及 kernel4.19的開源代碼,討論一些fuse的實現(xiàn)細節(jié),包括:fuse 用戶空間流程、內(nèi)核隊列、/dev/fuse的讀寫流程等。



          1.?fuse用戶空間流程


          (1)?fuse mount



          Fuse的掛載通過mount函數(shù),將指定的fuse_path掛載到/dev/fuse設(shè)備上。之后對于fuse_path下的文件操作,都會通過fuse文件系統(tǒng),并通過/dev/fuse被fuse daemon讀取處理。


          (2)?fuse thread



          Fuse ?daemon還會創(chuàng)建一個服務(wù)線程,基于libfuse庫來處理文件操作請求。這里主要關(guān)注fuse_session_new和fuse_session_loop_mt。通過fuse_session_new在libfuse中注冊了fuse daemon實現(xiàn)的fuse_lowlevel_ops,之后通過fuse的所有的文件操作,都會通過libfuse回調(diào)到fuse daemon進行處理。


          fuse_session_loop_mt在libfuse中實現(xiàn)了一個多線程模式來讀取請求,相比單線程,在請求處理上效率更高。


          (3)?libfuse


          fuse_session_loop_mt在libfuse中的調(diào)用流程如下:



          這里我們關(guān)注兩點:



          a) splice實現(xiàn)內(nèi)存零拷貝。在默認情況下,fuse daemon必須通過read()從/dev/fuse讀取請求,通過write()將請求回復(fù)寫入/dev/fuse。每次讀寫系統(tǒng)調(diào)用都需要進行一次內(nèi)核-用戶空間的內(nèi)存拷貝。這樣對讀寫的性能損耗十分嚴重,因為一次內(nèi)存拷貝需要處理大量數(shù)據(jù)。為了緩解這個問題,fuse支持了Linux內(nèi)核提供的 splice 功能。splice 允許用戶空間在兩個內(nèi)核內(nèi)存緩沖區(qū)之間傳輸數(shù)據(jù),而無需將數(shù)據(jù)復(fù)制給用戶空間。如果fuse daemon實現(xiàn)了write_buf()方法,則 FUSE 從/dev/fuse讀取數(shù)據(jù),并以包含文件描述符的緩沖區(qū)的形式將數(shù)據(jù)直接傳遞給此方法處理,從而省去了一次內(nèi)存申請與拷貝。

          b)?多線程模式。在多線程模式下,fuse ?daemon以一個線程開始,如果內(nèi)核隊列中有兩個以上的request,則會自動生成其他線程。默認最大支持10個線程同時處理請求。




          2.?fuse內(nèi)核隊列


          圖片摘自《To FUSE or Not to FUSE: Performance of User-Space File Systems》

          ?

          fuse在內(nèi)核中維護了五個隊列,分別為:Backgroud、Pending、Processing、Interrupts、Forgets。一個請求在任何時候只會存在于一個隊列中。



          a) Backgroud:background 隊列用于暫存異步請求。在默認情況下,只有讀請求進入 background 隊列;當writeback cache啟用時,寫請求也會進入 background 隊列。當開啟writeback cache時,來自用戶進程的寫請求會先在頁緩存中累積,然后當bdflush 線程被喚醒時會下刷臟頁。在下刷臟頁時,F(xiàn)USE會構(gòu)造異步請求,并將它們放入 background 隊列中。

          b) Pending:同步請求(例如,元數(shù)據(jù))放在 pending 隊列中,并且pending隊列會周期性接收來自background 的請求。但是pending隊列中異步請求的個數(shù)最大為max_background(最大為12),當pending隊列的異步請求未達到12時,background隊列的請求將被移動到pending隊列中。這樣做的目的是為了控制pending隊列中異步請求的個數(shù),防止在突發(fā)大量異步請求的情況下,阻塞了同步請求。

          c) Processing:當pending隊列中的請求被轉(zhuǎn)發(fā)到fuse daemon的同時,也被移動到processing隊列。所以processing隊列中的請求,表示正在被處理fuse daemon處理的請求。當fuse daemon真正處理完請求,通過/dev/fuse下發(fā)reply時,該請求將從processing隊列中刪除。

          d) Interrupts:用于存放中斷請求,比如當發(fā)送的請求被用戶取消時,內(nèi)核會發(fā)送一個Interrupts請求,來取消已被發(fā)送的請求。中斷請求的優(yōu)先級最高,Interrupts中的請求會最先得到處理。

          e) Forgets:forget請求用于刪除dcache中緩存的inode。



          ?

          3.?/dev/fuse 讀寫調(diào)用流程


          Fuse driver加載過程中注冊了對/dev/fuse的操作接口fuse_dev_operations。fuse_dev_do_read/fuse_dev_do_write分別對應(yīng)fuse daemon從內(nèi)核讀取請求,以及處理完請求后寫回reply的函數(shù)調(diào)用。我們分別看下具體的代碼片段



          pending 、interrups、forgets隊列都沒有請求時,讀進程進入休眠。一旦有請求到達,這個等待隊列上的進程將被喚醒。Interrups 和 forgets的請求優(yōu)先級高于pending隊列。當請求的數(shù)據(jù)內(nèi)容被拷貝至用戶空間后,該請求會被移至processing隊列,并且req->flags會保存當前請求的狀態(tài)。



          fuse daemon處理完請求后,會將結(jié)果寫回到/dev/fuse。寫數(shù)據(jù)保存在struct ?fuse_copy_state中,并且會根據(jù)unique id在fc(fuse_conn)中找到對應(yīng)的req,并將寫回的參數(shù)從fuse_copy_state拷貝至req->out。

          ?

          最后我們以unlink為例,看下fuse整體是如何工作的:


          圖片摘自fuse內(nèi)核官方文檔

          ?

          首先,fuse daemon會阻塞在讀/dev/fuse,當app進程在fuse掛載點下面有新的文件操作(unlink),這時系統(tǒng)調(diào)用會調(diào)用fuse內(nèi)核接口,并生成request,同時喚醒阻塞的fuse daemon。fuse daemon讀到request后,在libfuse中進行解析,根據(jù)request的opcode來執(zhí)行對應(yīng)的ops,完成后會把處理結(jié)果返回給/dev/fuse。此時vfs調(diào)用阻塞的行為將被喚醒,最后返回vfs調(diào)用。



          三、?總結(jié)



          雖然Fuse簡化了文件系統(tǒng)的實現(xiàn),給開發(fā)者帶來了便利。但是其額外的內(nèi)核態(tài)/用戶態(tài)切換帶來的性能開銷不能被忽視,所以fuse性能問題,一直是業(yè)界繞不開的話題。前面說到的splice、多線程、writeback cache都是為了改善其性能問題。后續(xù),我們再具體談?wù)刦use性能改善。

          ?


          參考文獻:

          [1]?Bharath Kumar Reddy Vangoor, Vasily Tarasov, Erez Zadok.To FUSE or Not to FUSE: Performance of User-Space File Systems. in Proceedings of the 15th USENIX Conference on File and Storage Technologies (FAST ’17), 2017 ? Santa Clara, CA, USA



          ? ? 推薦閱讀:
          ? ??專輯|Linux文章匯總
          ? ??專輯|程序人生
          ? ??專輯|C語言


          嵌入式Linux
          微信掃描二維碼,關(guān)注我的公眾號?
          瀏覽 139
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

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

          手機掃一掃分享

          分享
          舉報
          <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片免费下载 | 豆花视频在线观看一区二区三区 |