手机的Data分区被挂载为EXT4文件格式,由于开发阶段常会拔电源重启,经常遇到刚安装的程序重启后丢失以及设置壁纸重启后恢复等问题。 在网上搜了半天,ext4丢文件现象有很多人反映,不过多数是PC系统的问题。 看我自己手机的配置,发现有些参数不同。。于是研究了半天ext4挂载的参数,推荐看linux内核中的ext4文档,写的比网上文章详细多。
首先怀疑是data类型,有三种,分别为writeback、ordered和jounal
Data Mode ========= There are 3 different data modes:
* writeback mode In data=writeback mode, ext4 does not journal data at all. This mode provides a similar level of journaling as that of XFS, JFS, and ReiserFS in its default mode - metadata journaling. A crash+recovery can cause incorrect data to appear in files which were written shortly before the crash. This mode will typically provide the best ext4 performance.
* ordered mode In data=ordered mode, ext4 only officially journals metadata, but it logically groups metadata information related to data changes with the data blocks into a single unit called a transaction. When it's time to write the new metadata out to disk, the associated data blocks are written first. In general, this mode performs slightly slower than writeback but significantly faster than journal mode.
* journal mode data=journal mode provides full data and metadata journaling. All new data is written to the journal first, and then to its final location. In the event of a crash, the journal can be replayed, bringing both data and metadata into a consistent state. This mode is the slowest except when data needs to be read from and written to disk at the same time where it outperforms all others modes. Currently ext4 does not have delayed allocation support if this data journalling mode is selected.
将默认的ordered改为writeback,还是会丢,和此次参数无关。
接着怀疑没有commit参数
commit=nrsec(*)Ext4 can be told to sync all its data and metadata every 'nrsec' seconds. The default value is 5 seconds. This means that if you lose your power, you will lose as much as the latest 5 seconds of work (your filesystem will not be damaged though, thanks to the journaling). This default value (or any low value) will hurt performance, but it's good for data-safety. Setting it to 0 will have the same effect as leaving it at the default (5 seconds). Setting it to very large values will improve performance.
看过文档后发现commit默认为5,改大改小还是会丢文件。不过为了提升性能,CM系统的设置一般为15。
网上还有人提出noauto_da_alloc要打开,结果发现默认是打开的orz
auto_da_alloc(*)Many broken applications don't use fsync() when noauto_da_allocreplacing existing files via patterns such as fd = open("foo.new")/write(fd,..)/close(fd)/ rename("foo.new", "foo"), or worse yet, fd = open("foo", O_TRUNC)/write(fd,..)/close(fd). If auto_da_alloc is enabled, ext4 will detect the replace-via-rename and replace-via-truncate patterns and force that any delayed allocation blocks are allocated such that at the next journal commit, in the default data=ordered mode, the data blocks of the new file are forced to disk before the rename() operation is committed. This provides roughly the same level of guarantees as ext3, and avoids the "zero-length" problem that can happen when a system crashes before the delayed allocation blocks are forced to disk.
最后终于用zero size搜索到一篇有用的文章 How to Solve Zero Length File Problem in Linux’s Ext4 File System http://linux.bihlman.com/2010/05/09/how-to-solve-zero-length-file-problem-in-linuxs-ext4-file-system/
文中指出 Cause: The most possible cause for such behavior is the delayed allocation feature.What happens is when a file is closed after creation, the data blocks are allocated for the file after a minute or so. Because of this, the metadata of the modified file will show zero bytes as its size. The data allocation is done after the delayed allocation is over. Hence, in the case of a power surge the new file is considered as an empty file.
ext4的数据allocation竟然要等1分钟以上,这显然无法满足嵌入式的要求
解决方案是打开nodelalloc选项,尝试之,确有效! nodelallocDisable delayed allocation. Blocks are allocated when the data is copied from userspace to the page cache, either via the write(2) system call or when an mmap'ed page which was previously unallocated is written for the first time.
但是不知道对性能有没有影响。
BTW android的init.rc非常坑爹,mount命令和标准linux指令不同, 我一直怀疑只能解析一个参数,后来发现最后的参数不能用空格,需要用逗号隔开! mount ext4 /dev/block/mmcblk0p13 /data nosuid nodev barrier=1 noauto_da_alloc,commit=15,nodelalloc |