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