1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        FUSE文件系統(tǒng)

        共 3990字,需瀏覽 8分鐘

         ·

        2020-11-08 01:29

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



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



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


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


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



        二、?Fuse實(shí)現(xiàn)細(xì)節(jié)



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



        1.?fuse用戶空間流程


        (1)?fuse mount



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


        (2)?fuse thread



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


        fuse_session_loop_mt在libfuse中實(shí)現(xiàn)了一個(gè)多線程模式來(lái)讀取請(qǐng)求,相比單線程,在請(qǐng)求處理上效率更高。


        (3)?libfuse


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



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



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

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




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


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

        ?

        fuse在內(nèi)核中維護(hù)了五個(gè)隊(duì)列,分別為:Backgroud、Pending、Processing、Interrupts、Forgets。一個(gè)請(qǐng)求在任何時(shí)候只會(huì)存在于一個(gè)隊(duì)列中。



        a) Backgroud:background 隊(duì)列用于暫存異步請(qǐng)求。在默認(rèn)情況下,只有讀請(qǐng)求進(jìn)入 background 隊(duì)列;當(dāng)writeback cache啟用時(shí),寫(xiě)請(qǐng)求也會(huì)進(jìn)入 background 隊(duì)列。當(dāng)開(kāi)啟writeback cache時(shí),來(lái)自用戶進(jìn)程的寫(xiě)請(qǐng)求會(huì)先在頁(yè)緩存中累積,然后當(dāng)bdflush 線程被喚醒時(shí)會(huì)下刷臟頁(yè)。在下刷臟頁(yè)時(shí),F(xiàn)USE會(huì)構(gòu)造異步請(qǐng)求,并將它們放入 background 隊(duì)列中。

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

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

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

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



        ?

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


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



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



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

        ?

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


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

        ?

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



        三、?總結(jié)



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

        ?


        參考文獻(xiàn):

        [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語(yǔ)言


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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            久久国产综合精品swag蓝导航 | 成欢阁网站 | 欧美色色色色色 | 《梦莹和刘老头的情乱》 | hezyo北岛玲办公室av在线 | 免费超级乱淫视频播放 | 女人添男人囗交做爰视频 | 翔田千里一区二区三区 | 特黄一级富婆毛片 | www.操逼com |