jffs2文件系统——写操作 .

ramfs系统中write过程浅析中已经大致分析了vfs中写入的过程,jffs2大致跟这个过程差不多,略有差异的是 generic_file_buffered_write函数中的a_ops->prepare_write和a_ops->commit_writ,这两个函数各文件系统有差异。在jffs2文件系统中如此定义
  1. .readpage = jffs2_readpage,  
  2. .prepare_write =jffs2_prepare_write,  
  3. .commit_write = jffs2_commit_write  
.readpage =	jffs2_readpage,
.prepare_write =jffs2_prepare_write,
.commit_write =	jffs2_commit_write

jffs2_prepart_write这个函数主要是写入前准备。

commit_write这个函数才是真的数据写入。

  1. static int jffs2_prepare_write (struct file *filp, struct page *pg,  
  2.                 unsigned start, unsigned end)  
  3. {  
  4.     struct inode *inode = pg->mapping->host;  //对应的inode   
  5.     struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);   //得到这个inode信息   
  6.     uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT;  //页偏移量,在第几页*4k   
  7.   
  8.     if (pageofs > inode->i_size) {    //超过原来尺寸,有新数据写入   
  9.         ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,  
  10.                       ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);  //分配空间,并生成一个jffs2_raw_node_ref   
  11.   
  12.         //下面开始给inode赋值   
  13.         ……  
  14.         ri.data_crc = cpu_to_je32(0);  
  15.   
  16.         fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_NORMAL);   //写进去了,但是data是NULL的   
  17.   
  18.         if (IS_ERR(fn)) {  
  19.             ret = PTR_ERR(fn);  
  20.             jffs2_complete_reservation(c);  
  21.             up(&f->sem);  
  22.             return ret;  
  23.         }  
  24.         ret = jffs2_add_full_dnode_to_inode(c, f, fn);  //插入一个frag到f中,   
  25.         if (f->metadata) {   //将原来数据过期   
  26.             jffs2_mark_node_obsolete(c, f->metadata->raw);  
  27.             jffs2_free_full_dnode(f->metadata);  
  28.             f->metadata = NULL;  
  29.         }  
  30.         jffs2_complete_reservation(c);  
  31.         inode->i_size = pageofs;  
  32.     }  
  33.   
  34. }  
static int jffs2_prepare_write (struct file *filp, struct page *pg,
				unsigned start, unsigned end)
{
	struct inode *inode = pg->mapping->host;	//对应的inode
	struct jffs2_inode_info *f = JFFS2_INODE_INFO(inode);	//得到这个inode信息
	uint32_t pageofs = pg->index << PAGE_CACHE_SHIFT;	//页偏移量,在第几页*4k

	if (pageofs > inode->i_size) {	//超过原来尺寸,有新数据写入
		ret = jffs2_reserve_space(c, sizeof(ri), &alloc_len,
					  ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);	//分配空间,并生成一个jffs2_raw_node_ref

		//下面开始给inode赋值
		……
		ri.data_crc = cpu_to_je32(0);

		fn = jffs2_write_dnode(c, f, &ri, NULL, 0, ALLOC_NORMAL);	//写进去了,但是data是NULL的

		if (IS_ERR(fn)) {
			ret = PTR_ERR(fn);
			jffs2_complete_reservation(c);
			up(&f->sem);
			return ret;
		}
		ret = jffs2_add_full_dnode_to_inode(c, f, fn);	//插入一个frag到f中,
		if (f->metadata) {	//将原来数据过期
			jffs2_mark_node_obsolete(c, f->metadata->raw);
			jffs2_free_full_dnode(f->metadata);
			f->metadata = NULL;
		}
		jffs2_complete_reservation(c);
		inode->i_size = pageofs;
	}

}
一般情况下,如果写入的偏移(ofs)超过节点的大小(i_size),这个函数才会起作用,分配新的空间,且写入data为null的节点,生成fn并加到f->fragment的红黑树上。fn上有node的物理地址信息,数据的ofs和size。

  1. static int jffs2_commit_write (struct file *filp, struct page *pg,  
  2.                    unsigned start, unsigned end)  
  3. {  
  4.   
  5.     ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start,  
  6.                       (pg->index << PAGE_CACHE_SHIFT) + aligned_start,  
  7.                       end - aligned_start, &writtenlen);  
  8.     //入口参数:超级块,inode_info,ri,写入数据的位置,偏移,长度,返回值   
  9.     //这个偏移很关键,它跟物理地址没关系,就一个page内的偏移   
  10.     //将数据mapping(内存)上的数据写入flash   
  11.   
  12. }  
static int jffs2_commit_write (struct file *filp, struct page *pg,
			       unsigned start, unsigned end)
{

	ret = jffs2_write_inode_range(c, f, ri, page_address(pg) + aligned_start,
				      (pg->index << PAGE_CACHE_SHIFT) + aligned_start,
				      end - aligned_start, &writtenlen);
	//入口参数:超级块,inode_info,ri,写入数据的位置,偏移,长度,返回值
	//这个偏移很关键,它跟物理地址没关系,就一个page内的偏移
	//将数据mapping(内存)上的数据写入flash

}
其他校验的代码去掉后,剩下本人觉得最重要的代码jffs2_write_inode_range
  1. /* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that 
  2.    we don't have to go digging in struct inode or its equivalent. It should set: 
  3.    mode, uid, gid, (starting)isize, atime, ctime, mtime */  
  4. int jffs2_write_inode_range(struct jffs2_sb_info *c, struct jffs2_inode_info *f,  
  5.                 struct jffs2_raw_inode *ri, unsigned char *buf,  
  6.                 uint32_t offset, uint32_t writelen, uint32_t *retlen)  
  7. {  
  8.   
  9.     while(writelen) {   //按照长度写完   
  10.     retry:  
  11.         ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN,  
  12.                     &alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);  
  13.         datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));//存在超出一页的情况   
  14.         cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);//跨区   
  15.   
  16.         comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);  //压缩数据   
  17.         //写进去的数据是压缩过的   
  18.   
  19.         ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));  
  20.   
  21.         fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, ALLOC_NORETRY);  
  22.         //入口参数:sb_info,inode_info,ri,data,datalen,mode;返回full_dnode   
  23.         //fn->size=dsize   
  24.         //fn->raw是节点信息,里面有物理地址信息   
  25.         //fn->ofs=ri.offset   
  26.   
  27.         jffs2_free_comprbuf(comprbuf, buf); //释放压缩后的数据   
  28.   
  29.         ret = jffs2_add_full_dnode_to_inode(c, f, fn);  
  30.         if (f->metadata) {//将原来的数据过期掉   
  31.             jffs2_mark_node_obsolete(c, f->metadata->raw);  
  32.             jffs2_free_full_dnode(f->metadata);  
  33.             f->metadata = NULL;  
  34.         }  
  35.         jffs2_complete_reservation(c);  
  36.     }  
  37. }  
/* The OS-specific code fills in the metadata in the jffs2_raw_inode for us, so that
   we don't have to go digging in struct inode or its equivalent. It should set:
   mode, uid, gid, (starting)isize, atime, ctime, mtime */
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)
{

	while(writelen) {	//按照长度写完
	retry:
		ret = jffs2_reserve_space(c, sizeof(*ri) + JFFS2_MIN_DATA_LEN,
					&alloclen, ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE);
		datalen = min_t(uint32_t, writelen, PAGE_CACHE_SIZE - (offset & (PAGE_CACHE_SIZE-1)));//存在超出一页的情况
		cdatalen = min_t(uint32_t, alloclen - sizeof(*ri), datalen);//跨区

		comprtype = jffs2_compress(c, f, buf, &comprbuf, &datalen, &cdatalen);	//压缩数据
		//写进去的数据是压缩过的

		ri->data_crc = cpu_to_je32(crc32(0, comprbuf, cdatalen));

		fn = jffs2_write_dnode(c, f, ri, comprbuf, cdatalen, ALLOC_NORETRY);
		//入口参数:sb_info,inode_info,ri,data,datalen,mode;返回full_dnode
		//fn->size=dsize
		//fn->raw是节点信息,里面有物理地址信息
		//fn->ofs=ri.offset

		jffs2_free_comprbuf(comprbuf, buf);	//释放压缩后的数据

		ret = jffs2_add_full_dnode_to_inode(c, f, fn);
		if (f->metadata) {//将原来的数据过期掉
			jffs2_mark_node_obsolete(c, f->metadata->raw);
			jffs2_free_full_dnode(f->metadata);
			f->metadata = NULL;
		}
		jffs2_complete_reservation(c);
	}
}

这个函数是将需要写入的数据压缩,后写到通过jffs2_write_dnode将数据写到flash中。并将写入的node信息fn,挂到f->fragment树上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值