在jffs2写入其实是一个页写入(不管是nand flash还是nor flash,无非norflash的页大小是1)。
当wbuf_len不足pagesize的时候,pagesize-wbuflen部分,写一个unknown_node,它有一个头,后面的数据是0,这部分的数据是waste的。
如下图:
具体代码:
static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad)
{
struct jffs2_eraseblock *wbuf_jeb;
int ret;
size_t retlen;
/* Nothing to do if not write-buffering the flash. In particular, we shouldn't
del_timer() the timer we never initialised. */
if (!jffs2_is_writebuffered(c))
return 0;
if (!down_trylock(&c->alloc_sem)) {
up(&c->alloc_sem);
printk(KERN_CRIT "jffs2_flush_wbuf() called with alloc_sem not locked!\n");
BUG();
}
if (!c->wbuf_len) /* already checked c->wbuf above */
return 0;
wbuf_jeb = &c->blocks[c->wbuf_ofs / c->sector_size]; //擦除块
if (jffs2_prealloc_raw_node_refs(c, wbuf_jeb, c->nextblock->allocated_refs + 1))
//alloc出jffs2_raw_node_ref
return -ENOMEM;
/* claim remaining space on the page
this happens, if we have a change to a new block,
or if fsync forces us to flush the writebuffer.
if we have a switch to next page, we will not have
enough remaining space for this.
*/
if (pad ) {
c->wbuf_len = PAD(c->wbuf_len); //四字节对齐
/* Pad with JFFS2_DIRTY_BITMASK initially. this helps out ECC'd NOR
with 8 byte page size */
memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); //多余部分是0
if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {
//如果len还不致于超过一页,则生成一个unkown的node
//这个node 紧挨着数据,表示后面空白数据的node
//这个node是浪费掉的
struct jffs2_unknown_node *padnode = (void *)(c->wbuf + c->wbuf_len);
padnode->magic = cpu_to_je16(JFFS2_MAGIC_BITMASK);
padnode->nodetype = cpu_to_je16(JFFS2_NODETYPE_PADDING);
padnode->totlen = cpu_to_je32(c->wbuf_pagesize - c->wbuf_len);
padnode->hdr_crc = cpu_to_je32(crc32(0, padnode, sizeof(*padnode)-4));
}
}
/* else jffs2_flash_writev has actually filled in the rest of the
buffer for us, and will deal with the node refs etc. later. */
#ifdef BREAKME
static int breakme;
if (breakme++ == 20) {
printk(KERN_NOTICE "Faking write error at 0x%08x\n", c->wbuf_ofs);
breakme = 0;
c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen,
brokenbuf);
ret = -EIO;
} else
#endif
//调用mtd函数,写入至物理层
ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);
if (ret || retlen != c->wbuf_pagesize) {
if (ret)
printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret);
else {
printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",
retlen, c->wbuf_pagesize);
ret = -EIO;
}
jffs2_wbuf_recover(c);
return ret;
}
/* Adjust free size of the block if we padded. */
if (pad) {
uint32_t waste = c->wbuf_pagesize - c->wbuf_len; //浪费的空间数
D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",
(wbuf_jeb==c->nextblock)?"next":"", wbuf_jeb->offset));
/* wbuf_pagesize - wbuf_len is the amount of space that's to be
padded. If there is less free space in the block than that,
something screwed up */
if (wbuf_jeb->free_size < waste) { //如果原来空闲的小于本次浪费的,这个是错误的
printk(KERN_CRIT "jffs2_flush_wbuf(): Accounting error. wbuf at 0x%08x has 0x%03x bytes, 0x%03x left.\n",
c->wbuf_ofs, c->wbuf_len, waste);
printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",
wbuf_jeb->offset, wbuf_jeb->free_size);
BUG();
}
spin_lock(&c->erase_completion_lock);
jffs2_link_node_ref(c, wbuf_jeb, (c->wbuf_ofs + c->wbuf_len) | REF_OBSOLETE, waste, NULL);
/* FIXME: that made it count as dirty. Convert to wasted */
wbuf_jeb->dirty_size -= waste; //这个数据是浪费掉的,不是脏的
//jffs2_link_node_ref中将这块区域标识成脏了
c->dirty_size -= waste;
wbuf_jeb->wasted_size += waste;
c->wasted_size += waste;
} else
spin_lock(&c->erase_completion_lock);
/* Stick any now-obsoleted blocks on the erase_pending_list */
jffs2_refile_wbuf_blocks(c);
jffs2_clear_wbuf_ino_list(c);
spin_unlock(&c->erase_completion_lock);
memset(c->wbuf,0xff,c->wbuf_pagesize);
/* adjust write buffer offset, else we get a non contiguous write bug */
c->wbuf_ofs += c->wbuf_pagesize;
c->wbuf_len = 0;
return 0;
}