⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 wbuf.c

📁 jffs2源代码基于2。6内核
💻 C
📖 第 1 页 / 共 3 页
字号:
		list_del(&jeb->list);		list_add(&jeb->list, &c->erase_pending_list);		c->nr_erasing_blocks++;		jffs2_erase_pending_trigger(c);	}	else		jeb->last_node = container_of(first_raw, struct jffs2_raw_node_ref, next_phys);	ACCT_SANITY_CHECK(c,jeb);        D1(ACCT_PARANOIA_CHECK(jeb));	ACCT_SANITY_CHECK(c,new_jeb);        D1(ACCT_PARANOIA_CHECK(new_jeb));	spin_unlock(&c->erase_completion_lock);	D1(printk(KERN_DEBUG "wbuf recovery completed OK\n"));}/* Meaning of pad argument:   0: Do not pad. Probably pointless - we only ever use this when we can't pad anyway.   1: Pad, do not adjust nextblock free_size   2: Pad, adjust nextblock free_size*/static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad){	int ret;	size_t retlen;	/* Nothing to do if not NAND flash. In particular, we shouldn't	   del_timer() the timer we never initialised. */	if (jffs2_can_mark_obsolete(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 || !c->wbuf_len)		return 0;	/* 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);				if ( c->wbuf_len + sizeof(struct jffs2_unknown_node) < c->wbuf_pagesize) {			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 {			/* Pad with JFFS2_DIRTY_BITMASK */			memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len);		}	}	/* 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_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize,					&retlen, brokenbuf, NULL, c->oobinfo);		ret = -EIO;	} else #endif	ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo);	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; 	}	spin_lock(&c->erase_completion_lock);	/* Adjust free size of the block if we padded. */	if (pad) {		struct jffs2_eraseblock *jeb;		jeb = &c->blocks[c->wbuf_ofs / c->sector_size];		D1(printk(KERN_DEBUG "jffs2_flush_wbuf() adjusting free_size of %sblock at %08x\n",			  (jeb==c->nextblock)?"next":"", 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 (jeb->free_size < (c->wbuf_pagesize - c->wbuf_len)) {			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, c->wbuf_pagesize-c->wbuf_len);			printk(KERN_CRIT "jffs2_flush_wbuf(): But free_size for block at 0x%08x is only 0x%08x\n",			       jeb->offset, jeb->free_size);			BUG();		}		jeb->free_size -= (c->wbuf_pagesize - c->wbuf_len);		c->free_size -= (c->wbuf_pagesize - c->wbuf_len);		jeb->wasted_size += (c->wbuf_pagesize - c->wbuf_len);		c->wasted_size += (c->wbuf_pagesize - c->wbuf_len);	}	/* 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;}/* Trigger garbage collection to flush the write-buffer.    If ino arg is zero, do it if _any_ real (i.e. not GC) writes are   outstanding. If ino arg non-zero, do it only if a write for the    given inode is outstanding. */int jffs2_flush_wbuf_gc(struct jffs2_sb_info *c, uint32_t ino){	uint32_t old_wbuf_ofs;	uint32_t old_wbuf_len;	int ret = 0;	D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() called for ino #%u...\n", ino));	down(&c->alloc_sem);	if (!jffs2_wbuf_pending_for_ino(c, ino)) {		D1(printk(KERN_DEBUG "Ino #%d not pending in wbuf. Returning\n", ino));		up(&c->alloc_sem);		return 0;	}	old_wbuf_ofs = c->wbuf_ofs;	old_wbuf_len = c->wbuf_len;	if (c->unchecked_size) {		/* GC won't make any progress for a while */		D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() padding. Not finished checking\n"));		ret = __jffs2_flush_wbuf(c, 2);	} else while (old_wbuf_len &&		      old_wbuf_ofs == c->wbuf_ofs) {		up(&c->alloc_sem);		D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() calls gc pass\n"));		ret = jffs2_garbage_collect_pass(c);		if (ret) {			/* GC failed. Flush it with padding instead */			down(&c->alloc_sem);			ret = __jffs2_flush_wbuf(c, 2);			break;		}		down(&c->alloc_sem);	}	D1(printk(KERN_DEBUG "jffs2_flush_wbuf_gc() ends...\n"));	up(&c->alloc_sem);	return ret;}/* Pad write-buffer to end and write it, wasting space. */int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c){	return __jffs2_flush_wbuf(c, 1);}#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino){	struct kvec outvecs[3];	uint32_t totlen = 0;	uint32_t split_ofs = 0;	uint32_t old_totlen;	int ret, splitvec = -1;	int invec, outvec;	size_t wbuf_retlen;	unsigned char *wbuf_ptr;	size_t donelen = 0;	uint32_t outvec_to = to;	/* If not NAND flash, don't bother */	if (!c->wbuf)		return jffs2_flash_direct_writev(c, invecs, count, to, retlen);		/* If wbuf_ofs is not initialized, set it to target address */	if (c->wbuf_ofs == 0xFFFFFFFF) {		c->wbuf_ofs = PAGE_DIV(to);		c->wbuf_len = PAGE_MOD(to);					memset(c->wbuf,0xff,c->wbuf_pagesize);	}	/* Sanity checks on target address. 	   It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), 	   and it's permitted to write at the beginning of a new 	   erase block. Anything else, and you die.	   New block starts at xxx000c (0-b = block header)	*/	if ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) {		/* It's a write to a new block */		if (c->wbuf_len) {			D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs));			ret = jffs2_flush_wbuf_pad(c);			if (ret) {				/* the underlying layer has to check wbuf_len to do the cleanup */				D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));				*retlen = 0;				return ret;			}		}		/* set pointer to new block */		c->wbuf_ofs = PAGE_DIV(to);		c->wbuf_len = PAGE_MOD(to);				} 	if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {		/* We're not writing immediately after the writebuffer. Bad. */		printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to);		if (c->wbuf_len)			printk(KERN_CRIT "wbuf was previously %08x-%08x\n",					  c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);		BUG();	}	/* Note outvecs[3] above. We know count is never greater than 2 */	if (count > 2) {		printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count);		BUG();	}	invec = 0;	outvec = 0;	/* Fill writebuffer first, if already in use */		if (c->wbuf_len) {		uint32_t invec_ofs = 0;		/* adjust alignment offset */ 		if (c->wbuf_len != PAGE_MOD(to)) {			c->wbuf_len = PAGE_MOD(to);			/* take care of alignment to next page */			if (!c->wbuf_len)				c->wbuf_len = c->wbuf_pagesize;		}				while(c->wbuf_len < c->wbuf_pagesize) {			uint32_t thislen;						if (invec == count)				goto alldone;			thislen = c->wbuf_pagesize - c->wbuf_len;			if (thislen >= invecs[invec].iov_len)				thislen = invecs[invec].iov_len;				invec_ofs = thislen;			memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);			c->wbuf_len += thislen;			donelen += thislen;			/* Get next invec, if actual did not fill the buffer */			if (c->wbuf_len < c->wbuf_pagesize) 				invec++;		}							/* write buffer is full, flush buffer */		ret = __jffs2_flush_wbuf(c, 0);		if (ret) {			/* the underlying layer has to check wbuf_len to do the cleanup */			D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));			/* Retlen zero to make sure our caller doesn't mark the space dirty.			   We've already done everything that's necessary */			*retlen = 0;			return ret;		}		outvec_to += donelen;		c->wbuf_ofs = outvec_to;		/* All invecs done ? */		if (invec == count)			goto alldone;		/* Set up the first outvec, containing the remainder of the		   invec we partially used */		if (invecs[invec].iov_len > invec_ofs) {			outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs;			totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs;			if (totlen > c->wbuf_pagesize) {				splitvec = outvec;				split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen);			}			outvec++;		}		invec++;	}	/* OK, now we've flushed the wbuf and the start of the bits	   we have been asked to write, now to write the rest.... */	/* totlen holds the amount of data still to be written */	old_totlen = totlen;	for ( ; invec < count; invec++,outvec++ ) {		outvecs[outvec].iov_base = invecs[invec].iov_base;		totlen += outvecs[outvec].iov_len = invecs[invec].iov_len;		if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) {			splitvec = outvec;			split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen);			old_totlen = totlen;		}	}	/* Now the outvecs array holds all the remaining data to write */	/* Up to splitvec,split_ofs is to be written immediately. The rest	   goes into the (now-empty) wbuf */	if (splitvec != -1) {		uint32_t remainder;		int ret;		remainder = outvecs[splitvec].iov_len - split_ofs;		outvecs[splitvec].iov_len = split_ofs;		/* We did cross a page boundary, so we write some now */		ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); 		if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {			/* At this point we have no problem,			   c->wbuf is empty. 			*/			*retlen = donelen;			return ret;		}				donelen += wbuf_retlen;		c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen);		if (remainder) {			outvecs[splitvec].iov_base += split_ofs;			outvecs[splitvec].iov_len = remainder;		} else {			splitvec++;		}	} else {		splitvec = 0;	}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -