JFFS2文件系統掛載過程優化的分析報告

一?問題描述

在上電啟動優化中發現Linux系統下掛載JFFS2文件系統耗時較長,以128M的NOR FLASH為例,用時接近20秒。后續單板的FLASH容量為256M,時間會更長。如此長的掛載時間,會大增加系統的上電啟動時間。希望能對mount功能或JFFS2文件系統做適當優化,將256M?FLASH的掛載時間降到3~5秒內,優化時需要同時保證文件系統的可靠性和讀寫速度,要保證兼容優化前的文件系統。

root@CMM:/$ time mount -t jffs2 /dev/mtdblock1 /FLASH0

real????0m 19.83s

user????0m 0.00s

sys?????0m 19.73s

二?問題分析

與磁盤文件系統不同,JFFS2文件系統不在FLASH設備上存儲文件系統結構信息,所有的信息都分散在各個數據實體節點之中,在掛載文件系統的時候,需掃描整個Flash設備,從中建立起文件系統在內存中的映像,系統在運行期間,就利用這些內存中的信息進行各種文件操作。這就造成了JFFS2文件系統掛載時間過長,尤其是FLASH比較大,文件比較多的情況下。

擦除塊小結(erase block summary)補丁可以提高JFFS2文件系統的掛載速度,它最基本的思想就是用空間來換時間。具體來說,就是將擦除塊每個節點的原數據信息寫在這個擦除塊最后的固定位置,當JFFS2掛載的時候,對每個擦除塊只需要讀取這個小結節點。同時該補丁具有一定的穩定性和兼容性。

●?????穩定性:

If the summary node is missing, maybe because of a system power-down before it could be written to flash, nothing bad happens - JFFS2 just falls back to scanning the whole block as it would have done before.

●?????兼容性:

The JFFS2 image produced by sumtool is also usable with previous kernel because the summary node is JFFS2_FEATURE_RWCOMPAT_DELETE.

(當不支持擦除塊小結特性的JFFS2文件系統發現了一個屬性是?JFFS2_FEATURE

_RWCOMPAT_DELETE的節點時,在垃圾回收的時候,該節點可以被刪除)

三?原理介紹

????在每個擦除塊的末尾,有一個8 byte長的jffs2_sum_marker節點,該sum_marker節點記錄summary node信息的存儲位置,summary node可以由文件系統在寫操作的過程中自動產生。在文件系統掛載的時候,jffs2_scan_eraseblock()會去讀取每個擦除塊的最后8byte,如果驗證是有效的sum_marker節點,就會更據sum_marker中的offset偏移量去讀取summary node,所有在掛載中需要的信息都存放在summary node節點中,因此就沒有必要掃描整個擦除塊。如果沒有找到有效的sum_marker則按正當的啟動方式去掃描整個擦除塊。

3.1?存放在flash上的節點

●?jffs2_raw_summary

struct jffs2_raw_summary

{

????jint16_t magic;??????/* A constant magic number. */

????jint16_t nodetype;???/* = JFFS2_NODETYPE_SUMMARY */

????jint32_t totlen;??????/* Total length of this node (inc data,etc) */

????jint32_t hdr_crc;????/* CRC checksum */

????jint32_t sum_num;???/* number of sum entries */

????jint32_t cln_mkr;????/* clean marker size, 0 = no cleanmarker */

????jint32_t padded;????/* sum of the size of padding nodes */

????jint32_t sum_crc;????/* summary information CRC */

????jint32_t node_crc;???/* node CRC */

????jint32_t sum[0];?????/* inode summary info */

};

●?jffs2_sum_inode_flash

struct jffs2_sum_inode_flash

{

????jint16_t nodetype;??/* == JFFS2_NODETYPE_INODE */

????jint32_t inode;?????/* inode number */

????jint32_t version;???/* inode version */

????jint32_t offset;????/* offset on jeb */

????jint32_t totlen;????/* record length */

};

該節點包含在掃描過程中所需的dnode節點必要信息。

●?jffs2_sum_dirent_flash

struct jffs2_sum_dirent_flash

{

????jint16_t nodetype;??/* == JFFS_NODETYPE_DIRENT */

????jint32_t totlen;????/* record length */

????jint32_t offset;????/* ofset on jeb */

????jint32_t pino;??????/* parent inode */

????jint32_t version;???/* dirent version */

????jint32_t ino;???????/* == zero for unlink */

????uint8_t nsize;??????/* dirent name size */

????uint8_t type;???????/* dirent type */

????uint8_t name[0];????/* dirent name */

};

該節點包含掃描過程所需的dirent節點的必要信息。

●?jffs2_sum_marker

struct jffs2_sum_marker

{

????jint32_t offset; /* Offset of the summary_node in the jeb */

????jint32_t magic; /* Magic number (identifies the sum_marker node)*/

};

通過offset偏移量可以找到summary node節點的存儲位置。

●?四種節點之間的關系

?

jffs2_sum_marker存放在擦除末尾固定的8byte里,通過該結構的offset讀取summary node,summary node的sum字段存放sum_inode和sum_dirent節點地址信息。

3.2?存放在內存中的節點

●?jffs2_sum_unknown_mem

struct jffs2_sum_unknown_mem

{

????union jffs2_sum_mem *next;??/* pointer to the next node */

????jint16_t nodetype;??????????/* node type */

};

是存放在內存中的summary node的公共頭部。

●?jffs2_sum_inode_mem

struct jffs2_sum_inode_mem

{

????union jffs2_sum_mem *next;??/* pointer to the next node */

????jint16_t nodetype;?????????/* == JFFS2_NODETYPE_INODE */

????jint32_t inode;????????????/* inode number */

????jint32_t version;??????????/* inode version */

????jint32_t offset;???????????/* offset on jeb */

????jint32_t totlen;???????????/* record length */

};

存放在flash上和memory中的jffs2_sum_inode節點版本號version的不同之處是,內存中節點的版本號要高些。

●?jffs2_sum_dirent_mem

struct jffs2_sum_dirent_mem

{

????union jffs2_sum_mem *next; /* pointer to the next node */

????jint16_t nodetype;?????????/* == JFFS_NODETYPE_DIRENT */

????jint32_t totlen;???????????/* record length */

????jint32_t offset;???????????/* ofset on jeb */

????jint32_t pino;?????????????/* parent inode */

????jint32_t version;??????????/* dirent version */

????jint32_t ino;??????????????/* == zero for unlink */

????uint8_t nsize;?????????????/* dirent name size */

????uint8_t type;??????????????/* dirent type */

????uint8_t name[0];???????????/* dirent name */

};

存放在flash上和memory中的jffs2_sum_drient節點版本號version的不同之處是,內存中節點的版本號要高些。

●?union jffs2_sum_mem

union jffs2_sum_mem

{

????struct jffs2_sum_unknown_mem u;

????struct jffs2_sum_inode_mem i;

????struct jffs2_sum_dirent_mem d;

};

該信息存放一個鏈表上,主要用來決定節點的類型。

●?jffs2_summary

struct jffs2_summary

{

????uint32_t sum_size;???????/* summary data size */

????uint32_t sum_num;?????????/* number of summary nodes */

????uint32_t sum_padded;???????/* padded size */

????union jffs2_sum_mem *sum_list_head; /* summary node list head*/

????union jffs2_sum_mem *sum_list_tail;??/* summary node list tail */

????jint32_t *sum_buf;??????????/* buffer for writing out summary */

};

jffs2_sb_info超級塊結構擴展了一個指針,指向jffs2 _summary結構。該結構存儲擦除塊小結(earse block summary)的必要信息。

●?五種節點之間的關系

?

3.3?掛載過程

????傳統的掛載方式和EBS掛載方式不同之處在于掃描方法,如果支持EBS,掛載的時候就去讀每個擦除塊末尾的8bytes找到jffs2_sum_marker從而獲取擦除塊小結節點信息,而不是掃描整個擦除塊。

?

● 擦除塊存在有效的jffs2_sum_marker

????擦除塊存在有效的jffs2_sum_marker節點,表示整個擦除塊已經寫滿。jffs2_sum_marker節點有一個offset字段,代表從該擦除塊開始的地址偏移的地方存放著擦除塊小結的信息。EBS會分配c->sector_size - offset?(size of summary info)大小的內存,把flash上該擦除塊小結的信息讀到內存中,通過校驗節點和數據的有效性之后,會根據該擦除塊小結信息,像傳統方式一樣構建jffs2_raw_node_refs,?jffs2_full_dirents?和jffs2_inode_caches,而不用掃描整個擦除塊。

●?擦除塊不存在有效的jffs2_sum_marker

????擦除塊不存在有效的jffs2_sum_marker,表示該擦除塊沒有寫滿,應該像傳統的方式一樣掃描整個擦除塊同時收集擦除塊小結信息。下面是收集擦除塊小結信息的過程:

①?JFFS2_NODETYPE_INODE,為該類型的節點分配jffs2_sum_inode_mem結構,同時拷貝必要的節點信息到jffs2_sum_inode_mem,并且增加到sum_list_tail鏈表中,同時統計sum_size?和sum_num大小。

②?JFFS2_NODETYPE_DIRENT,為該類型的節點分配jffs2_sum_dirent_mem結構,同時拷貝必要的節點信息到jffs2_sum_dirent_mem,并且增加到sum_list_tail鏈表中,同時統計sum_size?和sum_num大小。

③?JFFS2_NODETYPE_CLEANMARKER,不做任何處理,在summary node中有個cln_mkr統計cleankarker大小。

④?JFFS2_NODETYPE_PADDING,增加sum_padded的值。

3.4?文件操作

???在為一個新的節點分配空間時,EBS會檢查c->nextblock是否有足夠的空間分配給該節點以及它的summary。如果有空間就會從目前可以使用的空間(jeb->free_size?- (collected summary info) - (new node's summary size))中分配。如果沒有足夠的空間分配,就會為該擦除塊產生summary node信息,并寫到預留的flash空間中。

四?方案驗證

4.1?驗證步驟

● 配置新的內核,支持EBS。

File systems --->

Miscellaneous filesystems??--->

?<*> Journalling Flash File System v2 (JFFS2) support

?(0)???FFS2 debugging verbosity (0 = quiet, 2 = noisy)

?[*]???JFFS2 write-buffering support

?[ ]????Verify JFFS2 write-buffer reads

?[*]???JFFS2 summary support (EXPERIMENTAL)

?[ ]???JFFS2 XATTR support (EXPERIMENTAL)

?[ ]???Advanced compression options for JFFS2

● 制作JFFS2鏡像文件

mkfs.jffs2 -e 0x20000 -p 0x20000 -d rootdir -o rootdir.jffs2

-d is the directory to use for input files, -o is the output file,-e means the earseblock

size for this flash, -p option means pad the last block to the eraseblock size.

● 為JFFS2鏡像文件增加小結信息

sumtool -e 0x20000 -p -i rootdir.jffs2 -o rootdir-sum.jffs2

具體的參數要根據實際情況修改。

● 寫文件到FLASH

可以嘗試使用nandwrite或flashcp,前者是往NAND FLASH寫數據,后者是往NOR FLASH寫數據。這些命令可以在mtd-utils-1.1.0中找到,下載地址:

ftp://ftp.infradead.org/pub/mtd-utils/mtd-utils-1.1.0.tar.bz2

4.2?驗證結果

?

No summary

With summary

real

?0m 19.83s

0m?0.47s

user

0m?0.00s

0m?0.01s

sys

?0m 19.73s

0m?0.46s

從驗證結果來看,掛載速度有顯著提高。

五?參考文獻

1、JFFS2 full summary support??http://www.infradead.org/pipermail/linux-mtd/2004-November/010887.html

2、Great jffs2 speedup?????????http://www.infradead.org/pipermail/linux-mtd/2005-September/013857.html

3、JFFS2 mount time????http://mhonarc.axis.se/jffs-dev/msg01763.html

4、Reducing JFFS2 mount time?http://www.embedded-linux.co.uk/tutorial/jffs2-summary

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/383430.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/383430.shtml
英文地址,請注明出處:http://en.pswp.cn/news/383430.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

右移函數(字符串,數組)

右移函數 以上是數組右移&#xff0c;將int換成char 把數組內容改成字符串就行。

關于jffs2文件系統如何掉電保護

JFFS2 是將節點信息保存在內存中 Flash上日志型文件系統的資料&#xff0c;了解到傳統的基于閃存轉換層&#xff08;FLT&#xff09;的文件系統存在的主要問題&#xff1a; 1. 效率低。因為每次都要把要修改的數據所在擦寫塊放入內存&#xff0c;產生了許多不必要的讀操作&…

c中指針簡介

c中指針簡介 首先我們來看一下指針的一些基本概念 ![在這里插入圖片描述](https://img 而對于指針的應用&#xff0c;平常有一些形式&#xff0c;總結了一下大概有這幾種用法 對于以上的幾種用法&#xff0c;我依次給出詳盡的解釋 //這是一個普通的整型變量 1 //首先從P 處開…

判斷一個字符串是否另一個字符串的右移后的

首先我們把需要判斷的字符串傳進來&#xff0c;開辟一塊大小為兩個字符串的長度總和加1的動態的空間&#xff0c;然后后字符串拷貝函數將一個字符串拷貝到開辟空降中&#xff0c;再將這個字符串再次連接到這塊動態的空間中&#xff0c;等于就是將一個字符串拷貝了兩遍。然后比較…

登陸后保持環境變量導出

在嵌入式開發中&#xff0c;要保證在系統登錄后&#xff0c;導出的環境變量依然有效&#xff0c;需要修改如下文件&#xff1a; /etc/profile export PATH/bin:/sbin:/usr/bin:/usr/sbin export PATH/system/bin:$PATH export LD_LIBRARY_PATH/system/lib export LD_LIBRARY_P…

fasync驅動異步通知機制

fasync簡介 編輯異步通知fasync應用于系統調用signal和sigaction函數&#xff0c;簡單的說&#xff0c;signal函數就是讓一個信號與與一個函數對應&#xff0c;每當接收到這個信號就會調用相應的函數。[1]那么什么是異步通知&#xff1f;異步通知類似于中斷的機制&#xff0c;當…

Linux中最常見命令總結

Linux中最常見命令總結 基礎命令 命令使用格式 命令名【選項參數】 【操作對象】Ls -a workspace目錄命令 Ls 默認顯示瀏覽當前文件目錄 -a 顯示所有文件&#xff0c;不忽略以點開頭的文件 Linux下以.開頭的文件是隱藏文件 每個目錄下文件的兩個特殊目錄 . 表示目錄自身…

不帶頭結點的鏈表基礎操作(初始化,增刪改查)

鏈表是什么&#xff1f; **鏈表是一種物理存儲單元上非連續、非順序的存儲結構&#xff0c;數據元素的邏輯順序是通過鏈表中的指針鏈接次序實現的。鏈表由一系列結點&#xff08;鏈表中每一個元素稱為結點&#xff09;組成&#xff0c;結點可以在運行時動態生成。每個結點包括…

fcntl的使用

功能描述&#xff1a;根據文件描述詞來操作文件的特性。 #include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct flock *lock); [描述] fcntl()針對(文件)描述符提供控…

鏈表面試題1:反轉單鏈表,不帶頭結點。

三個指針p1,p2,p3&#xff0c;p1指向頭結點的前一個結點&#xff0c;也就時指空&#xff0c;p2指向頭結點&#xff0c;p3指向頭結點下一個結點。 p3指向p2的下一個&#xff0c;讓p2指針域指向p1&#xff0c;讓p1挪到p2上&#xff0c;再讓p2指向p3.

dup/dup2函數的用法

系統調用dup和dup2能夠復制文件描述符。dup返回新的文件文件描述符&#xff08;沒有用的文件描述符最小的編號&#xff09;。dup2可以讓用戶指定返回的文件描述符的值&#xff0c;如果需要&#xff0c;則首先接近newfd的值&#xff0c;他通常用來重新打開或者重定向一個文件描述…

鏈表面試題2:編寫代碼,以給定值x為基準將鏈表分割成兩部分,所有小于x的結點排在大于或等于x的結點之前

我們可以&#xff0c;用兩個新鏈表&#xff0c;一個存比基準值大的&#xff0c;另一個存比基準值小的。然后再拼接在一起。 用尾插的方法&#xff0c;首先說小的&#xff0c;創建兩個指針&#xff0c;一個頭&#xff0c;一個尾&#xff0c;再創建個指針跑鏈表&#xff0c;掃描…

文件系統緩存dirty_ratio與dirty_background_ratio兩個參數區別

這兩天在調優數據庫性能的過程中需要降低操作系統文件Cache對數據庫性能的影響&#xff0c;故調研了一些降低文件系統緩存大小的方法&#xff0c;其中一種是通過修改/proc/sys/vm/dirty_background_ration以及/proc/sys/vm/dirty_ratio兩個參數的大小來實現。看了不少相關博文的…

棧和隊列的基本操作(棧和隊列的區別)

數據結構中的棧與內存中的棧的不同 一、數據結構中的堆棧 在數據結構中的堆棧&#xff0c;實際上堆棧是兩種數據結構&#xff1a;堆和棧。堆和棧都是一種數據項按序排列的數據結構。 1.棧就像裝數據的桶或箱子 我們先從大家比較熟悉的棧說起吧&#xff0c;它是一種具有后進先…

Linux I/O 調度方法

操作系統的調度有 CPU調度 CPU scheduler IO調度 IO scheduler IO調度器的總體目標是希望讓磁頭能夠總是往一個方向移動,移動到底了再往反方向走,這恰恰就是現實生活中的電梯模型,所以IO調 度器也被叫做電梯. (elevator)而相應的算法也就被叫做電梯算法. 而Linux中I…

編譯libcurl

1.下載源碼后&#xff0c;執行./buidconf產生configure配置文件 2.通過build.sh來設定configure 配置的參數 #!/bin/sh # export CFLAGS-O3 -w -isystem /home/xuxuequan/Ingenicwork/toolchain/mips-gcc472-glibc216-32bit/mips-linux-gnu/libc/usr/include export CPPFLAGS…

鏈表面試題3:將兩個有序鏈表合并為一個新的有序鏈表并返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成 的。

鏈表面試題3&#xff1a;將兩個有序鏈表合并為一個新的有序鏈表并返回。新鏈表是通過拼接給定的兩個鏈表的所有節點組成 的。 首先我們的思想是將得一個鏈表和第二個鏈表的每個結點進行比較&#xff0c;誰小誰就插入到新鏈表的最后。 首先我們要判段鏈表是否為空&#xff0c;…

gcc編譯參數-fPIC的一些問題

ppc_85xx-gcc -shared -fPIC liberr.c -o liberr.so-fPIC 作用于編譯階段&#xff0c;告訴編譯器產生與位置無關代碼(Position-Independent Code)&#xff0c;則產生的代碼中&#xff0c;沒有絕對地址&#xff0c;全部使用相對地址&#xff0c;故而代碼可以被加載器加載到內存的…

雙向鏈表的操作(創建,插入,刪除)

雙向鏈表的代碼看似復雜&#xff0c;其實很簡單&#xff0c;只要畫圖便可明白&#xff0c; 刪除 假如要刪除的結點叫pos. pos->prev->nextpos->next; pos->next->prevpos->prev; free(pos);

我使用過的Linux命令之hwclock - 查詢和設置硬件時鐘

我使用過的Linux命令之hwclock - 查詢和設置硬件時鐘 本文鏈接&#xff1a;http://codingstandards.iteye.com/blog/804830 &#xff08;轉載請注明出處&#xff09; 用途說明 hwclock命令&#xff0c;與clock命令是同一個命令&#xff0c;主要用來查詢和設置硬件時鐘&#x…