第二章 从文件创建到flash固化存储
在第一章中我们讲述了jffs2文件系统如何通过文件ino信息找到flash中对应文件的数据实体,本章将解析如何将文件固化到flash中存储。
一、文件系统操作实例
jffs2文件系统将写文件方法绑定到全局量变中,对外提供一个写对象,隐藏具体的实现细节。从中我们可以看出对文件的操作分为三个阶段,可以简单看作读文件、写文件预处理、实际写文件。
const struct address_space_operations jffs2_file_address_operations =
{
.read_folio = jffs2_read_folio,
.write_begin = jffs2_write_begin,
.write_end = jffs2_write_end,
};
1.1 读文件
下面我们来看下前处理jffs2_read_folio的代码逻辑。前处理中主要是通jffs2_read_inode_range函数,从flash上读取文件的一个页框中[offset, offset + len]区域的内容到页高速缓存中。对于已经压缩的数据还需要执行解压操作。
static int jffs2_read_folio(struct file *file, struct folio *folio)
{
...
ret = __jffs2_read_folio(file, folio);
...
}
int __jffs2_read_folio(struct file *file, struct folio *folio)
{
int ret = jffs2_do_readpage_nolock(folio->mapping->host, &folio->page);
folio_unlock(folio);
return ret;
}
static int jffs2_do_readpage_nolock (struct inode *inode, struct page *pg)
{
...
ret = jffs2_read_inode_range(c, f, pg_buf, pg->index << PAGE_SHIFT,
PAGE_SIZE);
...
}
int jffs2_read_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
unsigned char *buf, uint32_t offset, uint32_t len)
{
/* 从flash中读出数据(已压缩数据还需解压jffs2_decompress) */
ret = jffs2_read_dnode(c, f, frag->node, buf, fragofs + frag->ofs - frag->node->ofs, readlen);
}
1.2 写文件预处理
剔除部分无效数据,我们可以看到,预处理阶段,将文件的数据实体之间的空洞先写0。
static int jffs2_write_begin(struct file *filp, struct address_space *mapping,
loff_t pos, unsigned len,
struct page **pagep, void **fsdata)
{
...
fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_NORMAL);
...
}
1.3 实际写文件处理
我们可以看出,主要通过jffs2_write_dnode将压缩过的数据分段写入flash中。因此,我们实际在操作文件写时,可以在应用层也可执行小力度的文件数据写入,进而在busy状态快速终止写文件操作。
static int jffs2_write_end(struct file *filp, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *pg, void *fsdata)
{
...
ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start,
(pg->index << PAGE_SHIFT) + aligned_start,
end - aligned_start, &writtenlen);
...
}
int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,
struct jffs2_raw_inode *ri, unsigned char *buf,
uint32_t offset, uint32_t writelen, uint32_t *retlen)
{
/* 分段写入数据 */
datalen = min_t(uint32_t, writelen, PAGE_SIZE - (offset & (PAGE_SIZE-1)));
cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);
...
/* 压缩文件数据 */
comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);
...
/* 将文件数据写入flash */
fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, ALLOC_NORETRY);
...
}