aboutsummaryrefslogtreecommitdiffstats
path: root/fs/jffs2/wbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/jffs2/wbuf.c')
-rw-r--r--fs/jffs2/wbuf.c264
1 files changed, 97 insertions, 167 deletions
diff --git a/fs/jffs2/wbuf.c b/fs/jffs2/wbuf.c
index c7e3040240b2..916c87d3393b 100644
--- a/fs/jffs2/wbuf.c
+++ b/fs/jffs2/wbuf.c
@@ -613,20 +613,30 @@ int jffs2_flush_wbuf_pad(struct jffs2_sb_info *c)
613 613
614 return ret; 614 return ret;
615} 615}
616int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsigned long count, loff_t to, size_t *retlen, uint32_t ino) 616
617static size_t jffs2_fill_wbuf(struct jffs2_sb_info *c, const uint8_t *buf,
618 size_t len)
619{
620 if (len && !c->wbuf_len && (len >= c->wbuf_pagesize))
621 return 0;
622
623 if (len > (c->wbuf_pagesize - c->wbuf_len))
624 len = c->wbuf_pagesize - c->wbuf_len;
625 memcpy(c->wbuf + c->wbuf_len, buf, len);
626 c->wbuf_len += (uint32_t) len;
627 return len;
628}
629
630int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs,
631 unsigned long count, loff_t to, size_t *retlen,
632 uint32_t ino)
617{ 633{
618 struct kvec outvecs[3]; 634 struct jffs2_eraseblock *jeb;
619 uint32_t totlen = 0; 635 size_t wbuf_retlen, donelen = 0;
620 uint32_t split_ofs = 0;
621 uint32_t old_totlen;
622 int ret, splitvec = -1;
623 int invec, outvec;
624 size_t wbuf_retlen;
625 unsigned char *wbuf_ptr;
626 size_t donelen = 0;
627 uint32_t outvec_to = to; 636 uint32_t outvec_to = to;
637 int ret, invec;
628 638
629 /* If not NAND flash, don't bother */ 639 /* If not writebuffered flash, don't bother */
630 if (!jffs2_is_writebuffered(c)) 640 if (!jffs2_is_writebuffered(c))
631 return jffs2_flash_direct_writev(c, invecs, count, to, retlen); 641 return jffs2_flash_direct_writev(c, invecs, count, to, retlen);
632 642
@@ -639,23 +649,22 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
639 memset(c->wbuf,0xff,c->wbuf_pagesize); 649 memset(c->wbuf,0xff,c->wbuf_pagesize);
640 } 650 }
641 651
642 /* Sanity checks on target address. 652 /*
643 It's permitted to write at PAD(c->wbuf_len+c->wbuf_ofs), 653 * Sanity checks on target address. It's permitted to write
644 and it's permitted to write at the beginning of a new 654 * at PAD(c->wbuf_len+c->wbuf_ofs), and it's permitted to
645 erase block. Anything else, and you die. 655 * write at the beginning of a new erase block. Anything else,
646 New block starts at xxx000c (0-b = block header) 656 * and you die. New block starts at xxx000c (0-b = block
647 */ 657 * header)
658 */
648 if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) { 659 if (SECTOR_ADDR(to) != SECTOR_ADDR(c->wbuf_ofs)) {
649 /* It's a write to a new block */ 660 /* It's a write to a new block */
650 if (c->wbuf_len) { 661 if (c->wbuf_len) {
651 D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx causes flush of wbuf at 0x%08x\n", (unsigned long)to, c->wbuf_ofs)); 662 D1(printk(KERN_DEBUG "jffs2_flash_writev() to 0x%lx "
663 "causes flush of wbuf at 0x%08x\n",
664 (unsigned long)to, c->wbuf_ofs));
652 ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT); 665 ret = __jffs2_flush_wbuf(c, PAD_NOACCOUNT);
653 if (ret) { 666 if (ret)
654 /* the underlying layer has to check wbuf_len to do the cleanup */ 667 goto outerr;
655 D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
656 *retlen = 0;
657 goto exit;
658 }
659 } 668 }
660 /* set pointer to new block */ 669 /* set pointer to new block */
661 c->wbuf_ofs = PAGE_DIV(to); 670 c->wbuf_ofs = PAGE_DIV(to);
@@ -664,165 +673,70 @@ int jffs2_flash_writev(struct jffs2_sb_info *c, const struct kvec *invecs, unsig
664 673
665 if (to != PAD(c->wbuf_ofs + c->wbuf_len)) { 674 if (to != PAD(c->wbuf_ofs + c->wbuf_len)) {
666 /* We're not writing immediately after the writebuffer. Bad. */ 675 /* We're not writing immediately after the writebuffer. Bad. */
667 printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write to %08lx\n", (unsigned long)to); 676 printk(KERN_CRIT "jffs2_flash_writev(): Non-contiguous write "
677 "to %08lx\n", (unsigned long)to);
668 if (c->wbuf_len) 678 if (c->wbuf_len)
669 printk(KERN_CRIT "wbuf was previously %08x-%08x\n", 679 printk(KERN_CRIT "wbuf was previously %08x-%08x\n",
670 c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len); 680 c->wbuf_ofs, c->wbuf_ofs+c->wbuf_len);
671 BUG();
672 }
673
674 /* Note outvecs[3] above. We know count is never greater than 2 */
675 if (count > 2) {
676 printk(KERN_CRIT "jffs2_flash_writev(): count is %ld\n", count);
677 BUG(); 681 BUG();
678 } 682 }
679 683
680 invec = 0; 684 /* adjust alignment offset */
681 outvec = 0; 685 if (c->wbuf_len != PAGE_MOD(to)) {
682 686 c->wbuf_len = PAGE_MOD(to);
683 /* Fill writebuffer first, if already in use */ 687 /* take care of alignment to next page */
684 if (c->wbuf_len) { 688 if (!c->wbuf_len) {
685 uint32_t invec_ofs = 0; 689 c->wbuf_len = c->wbuf_pagesize;
686 690 ret = __jffs2_flush_wbuf(c, NOPAD);
687 /* adjust alignment offset */ 691 if (ret)
688 if (c->wbuf_len != PAGE_MOD(to)) { 692 goto outerr;
689 c->wbuf_len = PAGE_MOD(to);
690 /* take care of alignment to next page */
691 if (!c->wbuf_len)
692 c->wbuf_len = c->wbuf_pagesize;
693 }
694
695 while(c->wbuf_len < c->wbuf_pagesize) {
696 uint32_t thislen;
697
698 if (invec == count)
699 goto alldone;
700
701 thislen = c->wbuf_pagesize - c->wbuf_len;
702
703 if (thislen >= invecs[invec].iov_len)
704 thislen = invecs[invec].iov_len;
705
706 invec_ofs = thislen;
707
708 memcpy(c->wbuf + c->wbuf_len, invecs[invec].iov_base, thislen);
709 c->wbuf_len += thislen;
710 donelen += thislen;
711 /* Get next invec, if actual did not fill the buffer */
712 if (c->wbuf_len < c->wbuf_pagesize)
713 invec++;
714 }
715
716 /* write buffer is full, flush buffer */
717 ret = __jffs2_flush_wbuf(c, NOPAD);
718 if (ret) {
719 /* the underlying layer has to check wbuf_len to do the cleanup */
720 D1(printk(KERN_WARNING "jffs2_flush_wbuf() called from jffs2_flash_writev() failed %d\n", ret));
721 /* Retlen zero to make sure our caller doesn't mark the space dirty.
722 We've already done everything that's necessary */
723 *retlen = 0;
724 goto exit;
725 }
726 outvec_to += donelen;
727 c->wbuf_ofs = outvec_to;
728
729 /* All invecs done ? */
730 if (invec == count)
731 goto alldone;
732
733 /* Set up the first outvec, containing the remainder of the
734 invec we partially used */
735 if (invecs[invec].iov_len > invec_ofs) {
736 outvecs[0].iov_base = invecs[invec].iov_base+invec_ofs;
737 totlen = outvecs[0].iov_len = invecs[invec].iov_len-invec_ofs;
738 if (totlen > c->wbuf_pagesize) {
739 splitvec = outvec;
740 split_ofs = outvecs[0].iov_len - PAGE_MOD(totlen);
741 }
742 outvec++;
743 }
744 invec++;
745 }
746
747 /* OK, now we've flushed the wbuf and the start of the bits
748 we have been asked to write, now to write the rest.... */
749
750 /* totlen holds the amount of data still to be written */
751 old_totlen = totlen;
752 for ( ; invec < count; invec++,outvec++ ) {
753 outvecs[outvec].iov_base = invecs[invec].iov_base;
754 totlen += outvecs[outvec].iov_len = invecs[invec].iov_len;
755 if (PAGE_DIV(totlen) != PAGE_DIV(old_totlen)) {
756 splitvec = outvec;
757 split_ofs = outvecs[outvec].iov_len - PAGE_MOD(totlen);
758 old_totlen = totlen;
759 } 693 }
760 } 694 }
761 695
762 /* Now the outvecs array holds all the remaining data to write */ 696 for (invec = 0; invec < count; invec++) {
763 /* Up to splitvec,split_ofs is to be written immediately. The rest 697 int vlen = invecs[invec].iov_len;
764 goes into the (now-empty) wbuf */ 698 uint8_t *v = invecs[invec].iov_base;
765
766 if (splitvec != -1) {
767 uint32_t remainder;
768
769 remainder = outvecs[splitvec].iov_len - split_ofs;
770 outvecs[splitvec].iov_len = split_ofs;
771
772 /* We did cross a page boundary, so we write some now */
773 if (jffs2_cleanmarker_oob(c))
774 ret = c->mtd->writev_ecc(c->mtd, outvecs, splitvec+1, outvec_to, &wbuf_retlen, NULL, c->oobinfo);
775 else
776 ret = jffs2_flash_direct_writev(c, outvecs, splitvec+1, outvec_to, &wbuf_retlen);
777
778 if (ret < 0 || wbuf_retlen != PAGE_DIV(totlen)) {
779 /* At this point we have no problem,
780 c->wbuf is empty. However refile nextblock to avoid
781 writing again to same address.
782 */
783 struct jffs2_eraseblock *jeb;
784
785 spin_lock(&c->erase_completion_lock);
786 699
787 jeb = &c->blocks[outvec_to / c->sector_size]; 700 wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
788 jffs2_block_refile(c, jeb, REFILE_ANYWAY);
789 701
790 *retlen = 0; 702 if (c->wbuf_len == c->wbuf_pagesize) {
791 spin_unlock(&c->erase_completion_lock); 703 ret = __jffs2_flush_wbuf(c, NOPAD);
792 goto exit; 704 if (ret)
705 goto outerr;
793 } 706 }
794 707 vlen -= wbuf_retlen;
708 outvec_to += wbuf_retlen;
795 donelen += wbuf_retlen; 709 donelen += wbuf_retlen;
796 c->wbuf_ofs = PAGE_DIV(outvec_to) + PAGE_DIV(totlen); 710 v += wbuf_retlen;
797 711
798 if (remainder) { 712 if (vlen >= c->wbuf_pagesize) {
799 outvecs[splitvec].iov_base += split_ofs; 713 ret = c->mtd->write(c->mtd, outvec_to, PAGE_DIV(vlen),
800 outvecs[splitvec].iov_len = remainder; 714 &wbuf_retlen, v);
801 } else { 715 if (ret < 0 || wbuf_retlen != PAGE_DIV(vlen))
802 splitvec++; 716 goto outfile;
717
718 vlen -= wbuf_retlen;
719 outvec_to += wbuf_retlen;
720 c->wbuf_ofs = outvec_to;
721 donelen += wbuf_retlen;
722 v += wbuf_retlen;
803 } 723 }
804 724
805 } else { 725 wbuf_retlen = jffs2_fill_wbuf(c, v, vlen);
806 splitvec = 0; 726 if (c->wbuf_len == c->wbuf_pagesize) {
807 } 727 ret = __jffs2_flush_wbuf(c, NOPAD);
808 728 if (ret)
809 /* Now splitvec points to the start of the bits we have to copy 729 goto outerr;
810 into the wbuf */ 730 }
811 wbuf_ptr = c->wbuf;
812 731
813 for ( ; splitvec < outvec; splitvec++) { 732 outvec_to += wbuf_retlen;
814 /* Don't copy the wbuf into itself */ 733 donelen += wbuf_retlen;
815 if (outvecs[splitvec].iov_base == c->wbuf)
816 continue;
817 memcpy(wbuf_ptr, outvecs[splitvec].iov_base, outvecs[splitvec].iov_len);
818 wbuf_ptr += outvecs[splitvec].iov_len;
819 donelen += outvecs[splitvec].iov_len;
820 } 734 }
821 c->wbuf_len = wbuf_ptr - c->wbuf;
822 735
823 /* If there's a remainder in the wbuf and it's a non-GC write, 736 /*
824 remember that the wbuf affects this ino */ 737 * If there's a remainder in the wbuf and it's a non-GC write,
825alldone: 738 * remember that the wbuf affects this ino
739 */
826 *retlen = donelen; 740 *retlen = donelen;
827 741
828 if (jffs2_sum_active()) { 742 if (jffs2_sum_active()) {
@@ -835,8 +749,24 @@ alldone:
835 jffs2_wbuf_dirties_inode(c, ino); 749 jffs2_wbuf_dirties_inode(c, ino);
836 750
837 ret = 0; 751 ret = 0;
752 up_write(&c->wbuf_sem);
753 return ret;
838 754
839exit: 755outfile:
756 /*
757 * At this point we have no problem, c->wbuf is empty. However
758 * refile nextblock to avoid writing again to same address.
759 */
760
761 spin_lock(&c->erase_completion_lock);
762
763 jeb = &c->blocks[outvec_to / c->sector_size];
764 jffs2_block_refile(c, jeb, REFILE_ANYWAY);
765
766 spin_unlock(&c->erase_completion_lock);
767
768outerr:
769 *retlen = 0;
840 up_write(&c->wbuf_sem); 770 up_write(&c->wbuf_sem);
841 return ret; 771 return ret;
842} 772}