如何介绍网站模板下载,哈尔滨关键词优化推广,手机网站开发合同范本,wordpress文字博客主题一 问题描述
在上电启动优化中发现Linux系统下挂载JFFS2文件系统耗时较长#xff0c;以128M的NOR FLASH为例#xff0c;用时接近20秒。后续单板的FLASH容量为256M#xff0c;时间会更长。如此长的挂载时间#xff0c;会大增加系统的上电启动时间。希望能对mount功能或JFFS…一 问题描述
在上电启动优化中发现Linux系统下挂载JFFS2文件系统耗时较长以128M的NOR FLASH为例用时接近20秒。后续单板的FLASH容量为256M时间会更长。如此长的挂载时间会大增加系统的上电启动时间。希望能对mount功能或JFFS2文件系统做适当优化将256M FLASH的挂载时间降到3~5秒内优化时需要同时保证文件系统的可靠性和读写速度要保证兼容优化前的文件系统。 rootCMM:/$ 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 nodesummary 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 nodes 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