📄 wbuf.c
字号:
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 + -