?? wbuf.c
字號(hào):
/* Now splitvec points to the start of the bits we have to copy into the wbuf */ wbuf_ptr = c->wbuf; for ( ; splitvec < outvec; splitvec++) { /* Don't copy the wbuf into itself */ if (outvecs[splitvec].iov_base == c->wbuf) continue; memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len); wbuf_ptr += outvecs[splitvec].iov_len; donelen += outvecs[splitvec].iov_len; } c->wbuf_len = wbuf_ptr - c->wbuf; /* If there's a remainder in the wbuf and it's a non-GC write, remember that the wbuf affects this ino */alldone: *retlen = donelen; if (c->wbuf_len && ino) jffs2_wbuf_dirties_inode(c, ino); return 0;}/* * 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_can_mark_obsolete(c)) return c->mtd->write(c->mtd, 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; /* Read flash */ if (!jffs2_can_mark_obsolete(c)) { ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); if ( (ret == -EBADMSG) && (*retlen == len) ) { 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; } } else return c->mtd->read(c->mtd, ofs, len, retlen, buf); /* if no writebuffer available or write buffer empty, return */ if (!c->wbuf_pagesize || !c->wbuf_len) return ret; /* if we read in a different block, return */ if ( (ofs & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) return ret; if (ofs >= c->wbuf_ofs) { owbf = (ofs - c->wbuf_ofs); /* offset in write buffer */ if (owbf > c->wbuf_len) /* is read beyond write buffer ? */ return ret; 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 ? */ return ret; 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); return ret;}/* * Check, if the out of band area is empty */int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb, int mode){ unsigned char *buf; int ret = 0; int i,len,page; size_t retlen; int oob_size; /* allocate a buffer for all oob data in this sector */ oob_size = c->mtd->oobsize; len = 4 * oob_size; buf = kmalloc(len, GFP_KERNEL); if (!buf) { printk(KERN_NOTICE "jffs2_check_oob_empty(): allocation of temporary data buffer for oob check failed\n"); return -ENOMEM; } /* * if mode = 0, we scan for a total empty oob area, else we have * to take care of the cleanmarker in the first page of the block */ ret = jffs2_flash_read_oob(c, jeb->offset, len , &retlen, buf); if (ret) { D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); goto out; } if (retlen < len) { D1(printk(KERN_WARNING "jffs2_check_oob_empty(): Read OOB return short read " "(%zd bytes not %d) for block at %08x\n", retlen, len, jeb->offset)); ret = -EIO; goto out; } /* Special check for first page */ for(i = 0; i < oob_size ; i++) { /* Yeah, we know about the cleanmarker. */ if (mode && i >= c->fsdata_pos && i < c->fsdata_pos + c->fsdata_len) continue; if (buf[i] != 0xFF) { D2(printk(KERN_DEBUG "Found %02x at %x in OOB for %08x\n", buf[page+i], page+i, jeb->offset)); ret = 1; goto out; } } /* we know, we are aligned :) */ for (page = oob_size; page < len; page += sizeof(long)) { unsigned long dat = *(unsigned long *)(&buf[page]); if(dat != -1) { ret = 1; goto out; } }out: kfree(buf); return ret;}/** Scan for a valid cleanmarker and for bad blocks* For virtual blocks (concatenated physical blocks) check the cleanmarker* only in the first page of the first physical block, but scan for bad blocks in all* physical blocks*/int jffs2_check_nand_cleanmarker (struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb){ struct jffs2_unknown_node n; unsigned char buf[2 * NAND_MAX_OOBSIZE]; unsigned char *p; int ret, i, cnt, retval = 0; size_t retlen, offset; int oob_size; offset = jeb->offset; oob_size = c->mtd->oobsize; /* Loop through the physical blocks */ for (cnt = 0; cnt < (c->sector_size / c->mtd->erasesize); cnt++) { /* Check first if the block is bad. */ if (c->mtd->block_isbad (c->mtd, offset)) { D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Bad block at %08x\n", jeb->offset)); return 2; } /* * We read oob data from page 0 and 1 of the block. * page 0 contains cleanmarker and badblock info * page 1 contains failure count of this block */ ret = c->mtd->read_oob (c->mtd, offset, oob_size << 1, &retlen, buf); if (ret) { D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB failed %d for block at %08x\n", ret, jeb->offset)); return ret; } if (retlen < (oob_size << 1)) { D1 (printk (KERN_WARNING "jffs2_check_nand_cleanmarker(): Read OOB return short read (%zd bytes not %d) for block at %08x\n", retlen, oob_size << 1, jeb->offset)); return -EIO; } /* Check cleanmarker only on the first physical block */ if (!cnt) { n.magic = cpu_to_je16 (JFFS2_MAGIC_BITMASK); n.nodetype = cpu_to_je16 (JFFS2_NODETYPE_CLEANMARKER); n.totlen = cpu_to_je32 (8); p = (unsigned char *) &n; for (i = 0; i < c->fsdata_len; i++) { if (buf[c->fsdata_pos + i] != p[i]) { retval = 1; } } D1(if (retval == 1) { printk(KERN_WARNING "jffs2_check_nand_cleanmarker(): Cleanmarker node not detected in block at %08x\n", jeb->offset); printk(KERN_WARNING "OOB at %08x was ", offset); for (i=0; i < oob_size; i++) { printk("%02x ", buf[i]); } printk("\n"); }) } offset += c->mtd->erasesize; } return retval;}int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb){ struct jffs2_unknown_node n; int ret; size_t retlen; n.magic = cpu_to_je16(JFFS2_MAGIC_BITMASK); n.nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER); n.totlen = cpu_to_je32(8); ret = jffs2_flash_write_oob(c, jeb->offset + c->fsdata_pos, c->fsdata_len, &retlen, (unsigned char *)&n); if (ret) { D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Write failed for block at %08x: error %d\n", jeb->offset, ret)); return ret; } if (retlen != c->fsdata_len) { D1(printk(KERN_WARNING "jffs2_write_nand_cleanmarker(): Short write for block at %08x: %zd not %d\n", jeb->offset, retlen, c->fsdata_len)); 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? D1(printk(KERN_WARNING "jffs2_write_nand_badblock(): Marking bad block at %08x\n", 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;}#define NAND_JFFS2_OOB16_FSDALEN 8static struct nand_oobinfo jffs2_oobinfo_docecc = { .useecc = MTD_NANDECC_PLACE, .eccbytes = 6, .eccpos = {0,1,2,3,4,5}};int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c){ struct nand_oobinfo *oinfo = &c->mtd->oobinfo; /* Do this only, if we have an oob buffer */ if (!c->mtd->oobsize) return 0; /* Cleanmarker is out-of-band, so inline size zero */ c->cleanmarker_size = 0; /* Should we use autoplacement ? */ if (oinfo && oinfo->useecc == MTD_NANDECC_AUTOPLACE) { D1(printk(KERN_DEBUG "JFFS2 using autoplace on NAND\n")); /* Get the position of the free bytes */ if (!oinfo->oobfree[0][1]) { printk (KERN_WARNING "jffs2_nand_set_oobinfo(): Eeep. Autoplacement selected and no empty space in oob\n"); return -ENOSPC; } c->fsdata_pos = oinfo->oobfree[0][0]; c->fsdata_len = oinfo->oobfree[0][1]; if (c->fsdata_len > 8) c->fsdata_len = 8; } else { /* This is just a legacy fallback and should go away soon */ switch(c->mtd->ecctype) { case MTD_ECC_RS_DiskOnChip: printk(KERN_WARNING "JFFS2 using DiskOnChip hardware ECC without autoplacement. Fix it!\n"); c->oobinfo = &jffs2_oobinfo_docecc; c->fsdata_pos = 6; c->fsdata_len = NAND_JFFS2_OOB16_FSDALEN; c->badblock_pos = 15; break; default: D1(printk(KERN_DEBUG "JFFS2 on NAND. No autoplacment info found\n")); return -EINVAL; } } return 0;}int jffs2_nand_flash_setup(struct jffs2_sb_info *c){ int res; /* Initialise write buffer */ c->wbuf_pagesize = c->mtd->oobblock; c->wbuf_ofs = 0xFFFFFFFF; c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; res = jffs2_nand_set_oobinfo(c);#ifdef BREAKME if (!brokenbuf) brokenbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!brokenbuf) { kfree(c->wbuf); return -ENOMEM; } memset(brokenbuf, 0xdb, c->wbuf_pagesize);#endif return res;}void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c){ kfree(c->wbuf);}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -