X-Git-Url: http://git.rot13.org/?a=blobdiff_plain;f=fs%2Fjffs2%2Fwbuf.c;h=76d4c361ef1f70f7dfb5c024f598a241b75074c0;hb=9223a456da8ed357bf7e0b128c853e2c8bd54614;hp=316133c626b7424fc68ccfce9043c5d92c6e359d;hpb=c7fb577e2a6cb04732541f2dc402bd46747f7558;p=powerpc.git diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c index 316133c626..76d4c361ef 100644 --- a/fs/jffs2/wbuf.c +++ b/fs/jffs2/wbuf.c @@ -9,7 +9,7 @@ * * For licensing information, see the file 'LICENCE' in this directory. * - * $Id: wbuf.c,v 1.92 2005/04/05 12:51:54 dedekind Exp $ + * $Id: wbuf.c,v 1.100 2005/09/30 13:59:13 dedekind Exp $ * */ @@ -30,12 +30,12 @@ static unsigned char *brokenbuf; #endif +#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) +#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) + /* max. erase failures before we mark a block bad */ #define MAX_ERASE_FAILURES 2 -/* two seconds timeout for timed wbuf-flushing */ -#define WBUF_FLUSH_TIMEOUT 2 * HZ - struct jffs2_inodirty { uint32_t ino; struct jffs2_inodirty *next; @@ -139,7 +139,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock { D1(printk("About to refile bad block at %08x\n", jeb->offset)); - D2(jffs2_dump_block_lists(c)); /* File the existing block on the bad_used_list.... */ if (c->nextblock == jeb) c->nextblock = NULL; @@ -156,7 +155,6 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock c->nr_erasing_blocks++; jffs2_erase_pending_trigger(c); } - D2(jffs2_dump_block_lists(c)); /* Adjust its size counts accordingly */ c->wasted_size += jeb->free_size; @@ -164,8 +162,9 @@ static void jffs2_block_refile(struct jffs2_sb_info *c, struct jffs2_eraseblock jeb->wasted_size += jeb->free_size; jeb->free_size = 0; - ACCT_SANITY_CHECK(c,jeb); - D1(ACCT_PARANOIA_CHECK(jeb)); + jffs2_dbg_dump_block_lists_nolock(c); + jffs2_dbg_acct_sanity_check_nolock(c,jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); } /* Recover from failure to write wbuf. Recover the nodes up to the @@ -189,7 +188,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) /* Find the first node to be recovered, by skipping over every node which ends before the wbuf starts, or which is obsolete. */ first_raw = &jeb->first_node; - while (*first_raw && + while (*first_raw && (ref_obsolete(*first_raw) || (ref_offset(*first_raw)+ref_totlen(c, jeb, *first_raw)) < c->wbuf_ofs)) { D1(printk(KERN_DEBUG "Skipping node at 0x%08x(%d)-0x%08x which is either before 0x%08x or obsolete\n", @@ -234,11 +233,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) } /* Do the read... */ - if (jffs2_cleanmarker_oob(c)) - ret = c->mtd->read_ecc(c->mtd, start, c->wbuf_ofs - start, &retlen, buf, NULL, c->oobinfo); - else - ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); - + ret = c->mtd->read(c->mtd, start, c->wbuf_ofs - start, &retlen, buf); + if (ret == -EBADMSG && retlen == c->wbuf_ofs - start) { /* ECC recovered */ ret = 0; @@ -266,39 +262,38 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) /* ... and get an allocation of space from a shiny new block instead */ - ret = jffs2_reserve_space_gc(c, end-start, &ofs, &len); + ret = jffs2_reserve_space_gc(c, end-start, &len, JFFS2_SUMMARY_NOSUM_SIZE); if (ret) { printk(KERN_WARNING "Failed to allocate space for wbuf recovery. Data loss ensues.\n"); kfree(buf); return; } + ofs = write_ofs(c); + if (end-start >= c->wbuf_pagesize) { /* Need to do another write immediately, but it's possible that this is just because the wbuf itself is completely - full, and there's nothing earlier read back from the - flash. Hence 'buf' isn't necessarily what we're writing + full, and there's nothing earlier read back from the + flash. Hence 'buf' isn't necessarily what we're writing from. */ unsigned char *rewrite_buf = buf?:c->wbuf; uint32_t towrite = (end-start) - ((end-start)%c->wbuf_pagesize); D1(printk(KERN_DEBUG "Write 0x%x bytes at 0x%08x in wbuf recover\n", towrite, ofs)); - + #ifdef BREAKMEHEADER static int breakme; if (breakme++ == 20) { printk(KERN_NOTICE "Faking write error at 0x%08x\n", ofs); breakme = 0; - c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, - brokenbuf, NULL, c->oobinfo); + c->mtd->write(c->mtd, ofs, towrite, &retlen, + brokenbuf); ret = -EIO; } else #endif - if (jffs2_cleanmarker_oob(c)) - ret = c->mtd->write_ecc(c->mtd, ofs, towrite, &retlen, - rewrite_buf, NULL, c->oobinfo); - else - ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, rewrite_buf); + ret = c->mtd->write(c->mtd, ofs, towrite, &retlen, + rewrite_buf); if (ret || retlen != towrite) { /* Argh. We tried. Really we did. */ @@ -313,11 +308,8 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) return; raw2->flash_offset = ofs | REF_OBSOLETE; - raw2->__totlen = ref_totlen(c, jeb, *first_raw); - raw2->next_phys = NULL; - raw2->next_in_ino = NULL; - jffs2_add_physical_node_ref(c, raw2); + jffs2_add_physical_node_ref(c, raw2, ref_totlen(c, jeb, *first_raw), NULL); } return; } @@ -327,8 +319,7 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *c) 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. */ - if (buf) - kfree(buf); + kfree(buf); } else { /* OK, now we're left with the dregs in whichever buffer we're using */ if (buf) { @@ -392,11 +383,11 @@ static void jffs2_wbuf_recover(struct jffs2_sb_info *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)); + jffs2_dbg_acct_sanity_check_nolock(c, jeb); + jffs2_dbg_acct_paranoia_check_nolock(c, jeb); - ACCT_SANITY_CHECK(c,new_jeb); - D1(ACCT_PARANOIA_CHECK(new_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); @@ -435,15 +426,15 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) 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. + enough remaining space for this. */ - if (pad && !jffs2_dataflash(c)) { + 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); @@ -454,21 +445,18 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) } /* 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); + c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, + brokenbuf); ret = -EIO; - } else + } else #endif - - if (jffs2_cleanmarker_oob(c)) - ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); - else + ret = c->mtd->write(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf); if (ret || retlen != c->wbuf_pagesize) { @@ -485,32 +473,43 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) return ret; } - spin_lock(&c->erase_completion_lock); - /* Adjust free size of the block if we padded. */ - if (pad && !jffs2_dataflash(c)) { + if (pad) { struct jffs2_eraseblock *jeb; + struct jffs2_raw_node_ref *ref; + uint32_t waste = c->wbuf_pagesize - c->wbuf_len; 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 + /* 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)) { + if (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, c->wbuf_pagesize-c->wbuf_len); + 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", 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); - } + ref = jffs2_alloc_raw_node_ref(); + if (!ref) + return -ENOMEM; + ref->flash_offset = c->wbuf_ofs + c->wbuf_len; + ref->flash_offset |= REF_OBSOLETE; + + spin_lock(&c->erase_completion_lock); + + jffs2_link_node_ref(c, jeb, ref, waste, NULL); + /* FIXME: that made it count as dirty. Convert to wasted */ + jeb->dirty_size -= waste; + c->dirty_size -= waste; + 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); @@ -524,9 +523,9 @@ static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad) return 0; } -/* Trigger garbage collection to flush the write-buffer. +/* 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 + 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) { @@ -606,243 +605,159 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c) return ret; } -#ifdef CONFIG_JFFS2_FS_WRITEBUFFER -#define PAGE_DIV(x) ( ((unsigned long)(x) / (unsigned long)(c->wbuf_pagesize)) * (unsigned long)(c->wbuf_pagesize) ) -#define PAGE_MOD(x) ( (unsigned long)(x) % (unsigned long)(c->wbuf_pagesize) ) -#else -#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) ) -#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) ) -#endif +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; -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) + 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 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; + struct jffs2_eraseblock *jeb; + size_t wbuf_retlen, donelen = 0; uint32_t outvec_to = to; + int ret, invec; - /* If not NAND flash, don't bother */ + /* 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); + c->wbuf_len = PAGE_MOD(to); memset(c->wbuf,0xff,c->wbuf_pagesize); } - /* Fixup the wbuf if we are moving to a new eraseblock. The checks below - fail for ECC'd NOR because cleanmarker == 16, so a block starts at - xxx0010. */ - if (jffs2_nor_ecc(c)) { - if (((c->wbuf_ofs % c->sector_size) == 0) && !c->wbuf_len) { - 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) - */ + /* + * 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)); + 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) { - /* 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; - goto exit; - } + if (ret) + goto outerr; } /* set pointer to new block */ c->wbuf_ofs = PAGE_DIV(to); - c->wbuf_len = PAGE_MOD(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); + 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); + 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, NOPAD); - 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; - goto exit; - } - 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; + /* 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; } } - /* 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; - - remainder = outvecs[splitvec].iov_len - split_ofs; - outvecs[splitvec].iov_len = split_ofs; - - /* We did cross a page boundary, so we write some now */ - if (jffs2_cleanmarker_oob(c)) - ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); - else - ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen); - - if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { - /* At this point we have no problem, - c->wbuf is empty. However refile nextblock to avoid - writing again to same address. - */ - struct jffs2_eraseblock *jeb; - - spin_lock(&c->erase_completion_lock); + for (invec = 0; invec < count; invec++) { + int vlen = invecs[invec].iov_len; + uint8_t *v = invecs[invec].iov_base; - jeb = &c->blocks[outvec_to / c->sector_size]; - jffs2_block_refile(c, jeb, REFILE_ANYWAY); + wbuf_retlen = jffs2_fill_wbuf(c, v, vlen); - *retlen = 0; - spin_unlock(&c->erase_completion_lock); - goto exit; + if (c->wbuf_len == c->wbuf_pagesize) { + ret = __jffs2_flush_wbuf(c, NOPAD); + if (ret) + goto outerr; } - + vlen -= wbuf_retlen; + outvec_to += wbuf_retlen; donelen += wbuf_retlen; - c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); + 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; + } - if (remainder) { - outvecs[splitvec].iov_base += split_ofs; - outvecs[splitvec].iov_len = remainder; - } else { - splitvec++; + 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; } - } else { - splitvec = 0; + outvec_to += wbuf_retlen; + donelen += wbuf_retlen; } - /* Now splitvec points to the start of the bits we have to copy - into the wbuf */ - 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 + */ + *retlen = donelen; - 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; + if (jffs2_sum_active()) { + int res = jffs2_sum_add_kvec(c, invecs, count, (uint32_t) to); + if (res) + return res; } - 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); ret = 0; - -exit: + 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; } @@ -856,7 +771,7 @@ int jffs2_flash_write(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *r struct kvec vecs[1]; if (!jffs2_is_writebuffered(c)) - return c->mtd->write(c->mtd, ofs, len, retlen, buf); + return jffs2_flash_direct_write(c, ofs, len, retlen, buf); vecs[0].iov_base = (unsigned char *) buf; vecs[0].iov_len = len; @@ -876,26 +791,23 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re /* Read flash */ down_read(&c->wbuf_sem); - if (jffs2_cleanmarker_oob(c)) - ret = c->mtd->read_ecc(c->mtd, ofs, len, retlen, buf, NULL, c->oobinfo); - else - ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); + ret = c->mtd->read(c->mtd, ofs, len, retlen, buf); 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 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 + * 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) @@ -910,16 +822,16 @@ int jffs2_flash_read(struct jffs2_sb_info *c, loff_t ofs, size_t len, size_t *re 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) + if (lwbf > len) lwbf = len; - } else { + } 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) + if (lwbf > c->wbuf_len) lwbf = c->wbuf_len; - } + } if (lwbf > 0) memcpy(buf+orbf,c->wbuf+owbf,lwbf); @@ -947,7 +859,7 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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 */ @@ -956,41 +868,41 @@ int jffs2_check_oob_empty( struct jffs2_sb_info *c, struct jffs2_eraseblock *jeb 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 && + 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; + buf[i], i, jeb->offset)); + ret = 1; goto out; } } - /* we know, we are aligned :) */ + /* 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; + ret = 1; goto out; } } out: - kfree(buf); - + kfree(buf); + return ret; } @@ -1072,7 +984,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc 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; @@ -1084,7 +996,7 @@ int jffs2_write_nand_cleanmarker(struct jffs2_sb_info *c, struct jffs2_erasebloc 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 @@ -1105,7 +1017,7 @@ int jffs2_write_nand_badblock(struct jffs2_sb_info *c, struct jffs2_eraseblock * 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; @@ -1129,7 +1041,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) /* 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; @@ -1155,7 +1067,7 @@ static int jffs2_nand_set_oobinfo(struct jffs2_sb_info *c) 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; @@ -1170,9 +1082,9 @@ int jffs2_nand_flash_setup(struct jffs2_sb_info *c) /* Initialise write buffer */ init_rwsem(&c->wbuf_sem); - c->wbuf_pagesize = c->mtd->oobblock; + c->wbuf_pagesize = c->mtd->writesize; c->wbuf_ofs = 0xFFFFFFFF; - + c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); if (!c->wbuf) return -ENOMEM; @@ -1198,17 +1110,41 @@ void jffs2_nand_flash_cleanup(struct jffs2_sb_info *c) 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->sector_size; - c->wbuf_ofs = 0xFFFFFFFF; + + 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 (%i)\n", c->wbuf_pagesize); + printk(KERN_INFO "JFFS2 write-buffering enabled buffer (%d) erasesize (%d)\n", c->wbuf_pagesize, c->sector_size); return 0; } @@ -1217,13 +1153,14 @@ void jffs2_dataflash_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); } -int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { - /* Cleanmarker is actually larger on the flashes */ - c->cleanmarker_size = 16; +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->eccsize; + c->wbuf_pagesize = c->mtd->writesize; c->wbuf_ofs = 0xFFFFFFFF; c->wbuf = kmalloc(c->wbuf_pagesize, GFP_KERNEL); @@ -1233,6 +1170,6 @@ int jffs2_nor_ecc_flash_setup(struct jffs2_sb_info *c) { return 0; } -void jffs2_nor_ecc_flash_cleanup(struct jffs2_sb_info *c) { +void jffs2_nor_wbuf_flash_cleanup(struct jffs2_sb_info *c) { kfree(c->wbuf); }