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

📄 wbuf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
			return;		}		printk(KERN_NOTICE "Recovery of wbuf succeeded to %08x\n", ofs);		c->wbuf_len = (end - start) - towrite;		c->wbuf_ofs = ofs + towrite;		memmove(c->wbuf, rewrite_buf + towrite, c->wbuf_len);		/* Don't muck about with c->wbuf_inodes. False positives are harmless. */	} else {		/* OK, now we're left with the dregs in whichever buffer we're using */		if (buf) {			memcpy(c->wbuf, buf, end-start);		} else {			memmove(c->wbuf, c->wbuf + (start - c->wbuf_ofs), end - start);		}		c->wbuf_ofs = ofs;		c->wbuf_len = end - start;	}	/* Now sort out the jffs2_raw_node_refs, moving them from the old to the next block */	new_jeb = &c->blocks[ofs / c->sector_size];	spin_lock(&c->erase_completion_lock);	for (raw = first_raw; raw != jeb->last_node; raw = ref_next(raw)) {		uint32_t rawlen = ref_totlen(c, jeb, raw);		struct jffs2_inode_cache *ic;		struct jffs2_raw_node_ref *new_ref;		struct jffs2_raw_node_ref **adjust_ref = NULL;		struct jffs2_inode_info *f = NULL;		D1(printk(KERN_DEBUG "Refiling block of %08x at %08x(%d) to %08x\n",			  rawlen, ref_offset(raw), ref_flags(raw), ofs));		ic = jffs2_raw_ref_to_ic(raw);		/* Ick. This XATTR mess should be fixed shortly... */		if (ic && ic->class == RAWNODE_CLASS_XATTR_DATUM) {			struct jffs2_xattr_datum *xd = (void *)ic;			BUG_ON(xd->node != raw);			adjust_ref = &xd->node;			raw->next_in_ino = NULL;			ic = NULL;		} else if (ic && ic->class == RAWNODE_CLASS_XATTR_REF) {			struct jffs2_xattr_datum *xr = (void *)ic;			BUG_ON(xr->node != raw);			adjust_ref = &xr->node;			raw->next_in_ino = NULL;			ic = NULL;		} else if (ic && ic->class == RAWNODE_CLASS_INODE_CACHE) {			struct jffs2_raw_node_ref **p = &ic->nodes;			/* Remove the old node from the per-inode list */			while (*p && *p != (void *)ic) {				if (*p == raw) {					(*p) = (raw->next_in_ino);					raw->next_in_ino = NULL;					break;				}				p = &((*p)->next_in_ino);			}			if (ic->state == INO_STATE_PRESENT && !ref_obsolete(raw)) {				/* If it's an in-core inode, then we have to adjust any				   full_dirent or full_dnode structure to point to the				   new version instead of the old */				f = jffs2_gc_fetch_inode(c, ic->ino, ic->nlink);				if (IS_ERR(f)) {					/* Should never happen; it _must_ be present */					JFFS2_ERROR("Failed to iget() ino #%u, err %ld\n",						    ic->ino, PTR_ERR(f));					BUG();				}				/* We don't lock f->sem. There's a number of ways we could				   end up in here with it already being locked, and nobody's				   going to modify it on us anyway because we hold the				   alloc_sem. We're only changing one ->raw pointer too,				   which we can get away with without upsetting readers. */				adjust_ref = jffs2_incore_replace_raw(c, f, raw,								      (void *)(buf?:c->wbuf) + (ref_offset(raw) - start));			} else if (unlikely(ic->state != INO_STATE_PRESENT &&					    ic->state != INO_STATE_CHECKEDABSENT &&					    ic->state != INO_STATE_GC)) {				JFFS2_ERROR("Inode #%u is in strange state %d!\n", ic->ino, ic->state);				BUG();			}		}		new_ref = jffs2_link_node_ref(c, new_jeb, ofs | ref_flags(raw), rawlen, ic);		if (adjust_ref) {			BUG_ON(*adjust_ref != raw);			*adjust_ref = new_ref;		}		if (f)			jffs2_gc_release_inode(c, f);		if (!ref_obsolete(raw)) {			jeb->dirty_size += rawlen;			jeb->used_size  -= rawlen;			c->dirty_size += rawlen;			c->used_size -= rawlen;			raw->flash_offset = ref_offset(raw) | REF_OBSOLETE;			BUG_ON(raw->next_in_ino);		}		ofs += rawlen;	}	kfree(buf);	/* Fix up the original jeb now it's on the bad_list */	if (first_raw == jeb->first_node) {		D1(printk(KERN_DEBUG "Failing block at %08x is now empty. Moving to erase_pending_list\n", jeb->offset));		list_move(&jeb->list, &c->erase_pending_list);		c->nr_erasing_blocks++;		jffs2_erase_pending_trigger(c);	}	jffs2_dbg_acct_sanity_check_nolock(c, jeb);	jffs2_dbg_acct_paranoia_check_nolock(c, jeb);	jffs2_dbg_acct_sanity_check_nolock(c, new_jeb);	jffs2_dbg_acct_paranoia_check_nolock(c, new_jeb);	spin_unlock(&c->erase_completion_lock);	D1(printk(KERN_DEBUG "wbuf recovery completed OK. wbuf_ofs 0x%08x, len 0x%x\n", c->wbuf_ofs, c->wbuf_len));}/* 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*/#define NOPAD		0#define PAD_NOACCOUNT	1#define PAD_ACCOUNTING	2static 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))		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);		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 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		ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf);	if (ret) {		printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n", ret);		goto wfail;	} else if (retlen != c->wbuf_pagesize) {		printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n",		       retlen, c->wbuf_pagesize);		ret = -EIO;		goto wfail;	} else if ((ret = jffs2_verify_write(c, c->wbuf, c->wbuf_ofs))) {	wfail:		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;		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 */	if (SECTOR_ADDR(c->wbuf_ofs) == SECTOR_ADDR(c->wbuf_ofs+c->wbuf_pagesize))		c->wbuf_ofs += c->wbuf_pagesize;	else		c->wbuf_ofs = 0xffffffff;	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));	if (!c->wbuf)		return 0;	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"));		down_write(&c->wbuf_sem);		ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);		/* retry flushing wbuf in case jffs2_wbuf_recover		   left some data in the wbuf */		if (ret)			ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);		up_write(&c->wbuf_sem);	} 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);			down_write(&c->wbuf_sem);			ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);			/* retry flushing wbuf in case jffs2_wbuf_recover			   left some data in the wbuf */			if (ret)				ret = __jffs2_flush_wbuf(c, PAD_ACCOUNTING);			up_write(&c->wbuf_sem);			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){	int ret;	if (!c->wbuf)		return 0;	down_write(&c->wbuf_sem);	ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);	/* retry - maybe wbuf recover left some data in wbuf. */	if (ret)		ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);	up_write(&c->wbuf_sem);	return ret;}static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf,			      size_t len){	if (len && !c->wbuf_len && (len >= c->wbuf_pagesize))		return 0;	if (len > (c->wbuf_pagesize - c->wbuf_len))		len = c->wbuf_pagesize - c->wbuf_len;	memcpy(c->wbuf + c->wbuf_len, buf, len);	c->wbuf_len += (uint32_t) len;	return len;}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 jffs2_eraseblock *jeb;	size_t wbuf_retlen, donelen = 0;	uint32_t outvec_to = to;	int ret, invec;	/* If not writebuffered flash, don't bother */	if (!jffs2_is_writebuffered(c))		return jffs2_flash_direct_writev(c, invecs, count, to, retlen);	down_write(&c->wbuf_sem);	/* 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 (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {		/* 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(c, PAD_NOACCOUNT);			if (ret)				goto outerr;		}		/* 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();	}	/* 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;			ret = __jffs2_flush_wbuf(c, NOPAD);			if (ret)				goto outerr;		}	}	for (invec = 0; invec < count; invec++) {		int vlen = invecs[invec].iov_len;		uint8_t *v = invecs[invec].iov_base;		wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);		if (c->wbuf_len == c->wbuf_pagesize) {			ret = __jffs2_flush_wbuf(c, NOPAD);			if (ret)				goto outerr;		}		vlen -= wbuf_retlen;

⌨️ 快捷键说明

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