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

📄 wbuf.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		outvec_to += wbuf_retlen;		donelen += wbuf_retlen;		v += wbuf_retlen;		if (vlen >= c->wbuf_pagesize) {			ret = c->mtd->write(c->mtd, outvec_to, PAGE_DIV(vlen),					    &wbuf_retlen, v);			if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen))				goto outfile;			vlen -= wbuf_retlen;			outvec_to += wbuf_retlen;			c->wbuf_ofs = outvec_to;			donelen += wbuf_retlen;			v += wbuf_retlen;		}		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;		}		outvec_to += wbuf_retlen;		donelen += wbuf_retlen;	}	/*	 * If there's a remainder in the wbuf and it's a non-GC write,	 * remember that the wbuf affects this ino	 */	*retlen = donelen;	if (jffs2_sum_active()) {		int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to);		if (res)			return res;	}	if (c->wbuf_len && ino)		jffs2_wbuf_dirties_inode(c, ino);	ret = 0;	up_write(&c->wbuf_sem);	return ret;outfile:	/*	 * At this point we have no problem, c->wbuf is empty. However	 * refile nextblock to avoid writing again to same address.	 */	spin_lock(&c->erase_completion_lock);	jeb = &c->blocks[outvec_to / c->sector_size];	jffs2_block_refile(c, jeb, REFILE_ANYWAY);	spin_unlock(&c->erase_completion_lock);outerr:	*retlen = 0;	up_write(&c->wbuf_sem);	return ret;}/* *	This is the entry for flash write. *	Check, if we work on NAND FLASH, if so build an kvec and write it via vritev*/int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len,		      size_t *retlen, const u_char *buf){	struct kvec vecs[1];	if (!jffs2_is_writebuffered(c))		return jffs2_flash_direct_write(c, ofs, len, retlen, buf);	vecs[0].iov_base = (unsigned char *) buf;	vecs[0].iov_len = len;	return jffs2_flash_writev(c, vecs, 1, ofs, retlen, 0);}/*	Handle readback from writebuffer and ECC failure return*/int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *retlen, u_char *buf){	loff_t	orbf = 0, owbf = 0, lwbf = 0;	int	ret;	if (!jffs2_is_writebuffered(c))		return c->mtd->read(c->mtd, ofs, len, retlen, buf);	/* Read flash */	down_read(&c->wbuf_sem);	ret = c->mtd->read(c->mtd, ofs, len, retlen, buf);	if ( (ret == -EBADMSG || ret == -EUCLEAN) && (*retlen == len) ) {		if (ret == -EBADMSG)			printk(KERN_WARNING "mtd->read(0x%zx bytes from 0x%llx)"			       " returned ECC error\n", len, ofs);		/*		 * We have the raw data without ECC correction in the buffer,		 * maybe we are lucky and all data or parts are correct. We		 * check the node.  If data are corrupted node check will sort		 * it out.  We keep this block, it will fail on write or erase		 * and the we mark it bad. Or should we do that now? But we		 * should give him a chance.  Maybe we had a system crash or		 * power loss before the ecc write or a erase was completed.		 * So we return success. :)		 */		ret = 0;	}	/* if no writebuffer available or write buffer empty, return */	if (!c->wbuf_pagesize || !c->wbuf_len)		goto exit;	/* if we read in a different block, return */	if (SECTOR_ADDR(ofs) != SECTOR_ADDR(c->wbuf_ofs))		goto exit;	if (ofs >= c->wbuf_ofs) {		owbf = (ofs - c->wbuf_ofs);	/* offset in write buffer */		if (owbf > c->wbuf_len)		/* is read beyond write buffer ? */			goto exit;		lwbf = c->wbuf_len - owbf;	/* number of bytes to copy */		if (lwbf > len)			lwbf = len;	} else {		orbf = (c->wbuf_ofs - ofs);	/* offset in read buffer */		if (orbf > len)			/* is write beyond write buffer ? */			goto exit;		lwbf = len - orbf;		/* number of bytes to copy */		if (lwbf > c->wbuf_len)			lwbf = c->wbuf_len;	}	if (lwbf > 0)		memcpy(buf+orbf,c->wbuf+owbf,lwbf);exit:	up_read(&c->wbuf_sem);	return ret;}#define NR_OOB_SCAN_PAGES 4/* For historical reasons we use only 8 bytes for OOB clean marker */#define OOB_CM_SIZE 8static const struct jffs2_unknown_node oob_cleanmarker ={	.magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK),	.nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER),	.totlen = constant_cpu_to_je32(8)};/* * Check, if the out of band area is empty. This function knows about the clean * marker and if it is present in OOB, treats the OOB as empty anyway. */int jffs2_check_oob_empty(struct jffs2_sb_info *c,			  struct jffs2_eraseblock *jeb, int mode){	int i, ret;	int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);	struct mtd_oob_ops ops;	ops.mode = MTD_OOB_AUTO;	ops.ooblen = NR_OOB_SCAN_PAGES * c->oobavail;	ops.oobbuf = c->oobbuf;	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;	ops.datbuf = NULL;	ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);	if (ret || ops.oobretlen != ops.ooblen) {		printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"				" bytes, read %zd bytes, error %d\n",				jeb->offset, ops.ooblen, ops.oobretlen, ret);		if (!ret)			ret = -EIO;		return ret;	}	for(i = 0; i < ops.ooblen; i++) {		if (mode && i < cmlen)			/* Yeah, we know about the cleanmarker */			continue;		if (ops.oobbuf[i] != 0xFF) {			D2(printk(KERN_DEBUG "Found %02x at %x in OOB for "				  "%08x\n", ops.oobbuf[i], i, jeb->offset));			return 1;		}	}	return 0;}/* * Check for a valid cleanmarker. * Returns: 0 if a valid cleanmarker was found *	    1 if no cleanmarker was found *	    negative error code if an error occurred */int jffs2_check_nand_cleanmarker(struct jffs2_sb_info *c,				 struct jffs2_eraseblock *jeb){	struct mtd_oob_ops ops;	int ret, cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);	ops.mode = MTD_OOB_AUTO;	ops.ooblen = cmlen;	ops.oobbuf = c->oobbuf;	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;	ops.datbuf = NULL;	ret = c->mtd->read_oob(c->mtd, jeb->offset, &ops);	if (ret || ops.oobretlen != ops.ooblen) {		printk(KERN_ERR "cannot read OOB for EB at %08x, requested %zd"				" bytes, read %zd bytes, error %d\n",				jeb->offset, ops.ooblen, ops.oobretlen, ret);		if (!ret)			ret = -EIO;		return ret;	}	return !!memcmp(&oob_cleanmarker, c->oobbuf, cmlen);}int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c,				 struct jffs2_eraseblock *jeb){	int ret;	struct mtd_oob_ops ops;	int cmlen = min_t(int, c->oobavail, OOB_CM_SIZE);	ops.mode = MTD_OOB_AUTO;	ops.ooblen = cmlen;	ops.oobbuf = (uint8_t *)&oob_cleanmarker;	ops.len = ops.ooboffs = ops.retlen = ops.oobretlen = 0;	ops.datbuf = NULL;	ret = c->mtd->write_oob(c->mtd, jeb->offset, &ops);	if (ret || ops.oobretlen != ops.ooblen) {		printk(KERN_ERR "cannot write OOB for EB at %08x, requested %zd"				" bytes, read %zd bytes, error %d\n",				jeb->offset, ops.ooblen, ops.oobretlen, ret);		if (!ret)			ret = -EIO;		return ret;	}	return 0;}/* * On NAND we try to mark this block bad. If the block was erased more * than MAX_ERASE_FAILURES we mark it finaly bad. * Don't care about failures. This block remains on the erase-pending * or badblock list as long as nobody manipulates the flash with * a bootloader or something like that. */int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, uint32_t bad_offset){	int 	ret;	/* if the count is < max, we try to write the counter to the 2nd page oob area */	if( ++jeb->bad_count < MAX_ERASE_FAILURES)		return 0;	if (!c->mtd->block_markbad)		return 1; // What else can we do?	printk(KERN_WARNING "JFFS2: marking eraseblock at %08x\n as bad", bad_offset);	ret = c->mtd->block_markbad(c->mtd, bad_offset);	if (ret) {		D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Write failed for block at %08x: error %d\n", jeb->offset, ret));		return ret;	}	return 1;}int jffs2_nand_flash_setup(struct jffs2_sb_info *c){	struct nand_ecclayout *oinfo = c->mtd->ecclayout;	if (!c->mtd->oobsize)		return 0;	/* Cleanmarker is out-of-band, so inline size zero */	c->cleanmarker_size = 0;	if (!oinfo || oinfo->oobavail == 0) {		printk(KERN_ERR "inconsistent device description\n");		return -EINVAL;	}	D1(printk(KERN_DEBUG "JFFS2 using OOB on NAND\n"));	c->oobavail = oinfo->oobavail;	/* Initialise write buffer */	init_rwsem(&c->wbuf_sem);	c->wbuf_pagesize = c->mtd->writesize;	c->wbuf_ofs = 0xFFFFFFFF;	c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);	if (!c->wbuf)		return -ENOMEM;	c->oobbuf = kmalloc(NR_OOB_SCAN_PAGES * c->oobavail, GFP_KERNEL);	if (!c->oobbuf) {		kfree(c->wbuf);		return -ENOMEM;	}#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY	c->wbuf_verify = kmalloc(c->wbuf_pagesize, GFP_KERNEL);	if (!c->wbuf_verify) {		kfree(c->oobbuf);		kfree(c->wbuf);		return -ENOMEM;	}#endif	return 0;}void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c){#ifdef CONFIG_JFFS2_FS_WBUF_VERIFY	kfree(c->wbuf_verify);#endif	kfree(c->wbuf);	kfree(c->oobbuf);}int jffs2_dataflash_setup(struct jffs2_sb_info *c) {	c->cleanmarker_size = 0;		/* No cleanmarkers needed */	/* Initialize write buffer */	init_rwsem(&c->wbuf_sem);	c->wbuf_pagesize =  c->mtd->erasesize;	/* Find a suitable c->sector_size	 * - Not too much sectors	 * - Sectors have to be at least 4 K + some bytes	 * - All known dataflashes have erase sizes of 528 or 1056	 * - we take at least 8 eraseblocks and want to have at least 8K size	 * - The concatenation should be a power of 2	*/	c->sector_size = 8 * c->mtd->erasesize;	while (c->sector_size < 8192) {		c->sector_size *= 2;	}	/* It may be necessary to adjust the flash size */	c->flash_size = c->mtd->size;	if ((c->flash_size % c->sector_size) != 0) {		c->flash_size = (c->flash_size / c->sector_size) * c->sector_size;		printk(KERN_WARNING "JFFS2 flash size adjusted to %dKiB\n", c->flash_size);	};	c->wbuf_ofs = 0xFFFFFFFF;	c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);	if (!c->wbuf)		return -ENOMEM;	printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);	return 0;}void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) {	kfree(c->wbuf);}int jffs2_nor_wbuf_flash_setup(struct jffs2_sb_info *c) {	/* Cleanmarker currently occupies whole programming regions,	 * either one or 2 for 8Byte STMicro flashes. */	c->cleanmarker_size = max(16u, c->mtd->writesize);	/* Initialize write buffer */	init_rwsem(&c->wbuf_sem);	c->wbuf_pagesize = c->mtd->writesize;	c->wbuf_ofs = 0xFFFFFFFF;	c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);	if (!c->wbuf)		return -ENOMEM;	return 0;}void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) {	kfree(c->wbuf);}int jffs2_ubivol_setup(struct jffs2_sb_info *c) {	c->cleanmarker_size = 0;	if (c->mtd->writesize == 1)		/* We do not need write-buffer */		return 0;	init_rwsem(&c->wbuf_sem);	c->wbuf_pagesize =  c->mtd->writesize;	c->wbuf_ofs = 0xFFFFFFFF;	c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL);	if (!c->wbuf)		return -ENOMEM;	printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size);	return 0;}void jffs2_ubivol_cleanup(struct jffs2_sb_info *c) {	kfree(c->wbuf);}

⌨️ 快捷键说明

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