?? wbuf.c
字號:
list_del(&jeb->list); list_add(&jeb->list, &c->erase_pending_list); c->nr_erasing_blocks++; jffs2_erase_pending_trigger(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)); ACCT_SANITY_CHECK(c,new_jeb); D1(ACCT_PARANOIA_CHECK(new_jeb)); spin_unlock(&c->erase_completion_lock); D1(printk(KERN_DEBUG "wbuf recovery completed OK\n"));}/* 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*/static int __jffs2_flush_wbuf(struct jffs2_sb_info *c, int pad){ int ret; size_t retlen; /* Nothing to do if not NAND flash. In particular, we shouldn't del_timer() the timer we never initialised. */ if (jffs2_can_mark_obsolete(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 || !c->wbuf_len) return 0; /* 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); 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 { /* Pad with JFFS2_DIRTY_BITMASK */ memset(c->wbuf + c->wbuf_len, 0, c->wbuf_pagesize - c->wbuf_len); } } /* 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); ret = -EIO; } else #endif ret = c->mtd->write_ecc(c->mtd, c->wbuf_ofs, c->wbuf_pagesize, &retlen, c->wbuf, NULL, c->oobinfo); if (ret || retlen != c->wbuf_pagesize) { if (ret) printk(KERN_WARNING "jffs2_flush_wbuf(): Write failed with %d\n",ret); else { printk(KERN_WARNING "jffs2_flush_wbuf(): Write was short: %zd instead of %d\n", retlen, c->wbuf_pagesize); ret = -EIO; } jffs2_wbuf_recover(c); return ret; } spin_lock(&c->erase_completion_lock); /* Adjust free size of the block if we padded. */ if (pad) { struct jffs2_eraseblock *jeb; 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 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)) { 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); 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); } /* 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 */ c->wbuf_ofs += c->wbuf_pagesize; 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)); 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")); ret = __jffs2_flush_wbuf(c, 2); } 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); ret = __jffs2_flush_wbuf(c, 2); 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){ return __jffs2_flush_wbuf(c, 1);}#define PAGE_DIV(x) ( (x) & (~(c->wbuf_pagesize - 1)) )#define PAGE_MOD(x) ( (x) & (c->wbuf_pagesize - 1) )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; uint32_t outvec_to = to; /* If not NAND flash, don't bother */ if (!c->wbuf) return jffs2_flash_direct_writev(c, invecs, count, to, retlen); /* 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 ( (to & ~(c->sector_size-1)) != (c->wbuf_ofs & ~(c->sector_size-1)) ) { /* 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_pad(c); 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; return ret; } } /* 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(); } /* 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, 0); 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; return ret; } 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; } } /* 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; int ret; remainder = outvecs[splitvec].iov_len - split_ofs; outvecs[splitvec].iov_len = split_ofs; /* We did cross a page boundary, so we write some now */ ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo); if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) { /* At this point we have no problem, c->wbuf is empty. */ *retlen = donelen; return ret; } donelen += wbuf_retlen; c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); if (remainder) { outvecs[splitvec].iov_base += split_ofs; outvecs[splitvec].iov_len = remainder; } else { splitvec++; } } else { splitvec = 0; }
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -