aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEvgeniy Dushistov <dushistov@mail.ru>2006-06-25 08:47:23 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-06-25 13:01:02 -0400
commit3e41f597b1595479e4a1b2e6b17b3542120ef165 (patch)
treea4adfd190f25b6b896ae04e9d4cbd6c4d94c872c
parent9695ef16ed4e00b59303f39f9a4a422a2c6a3b89 (diff)
[PATCH] ufs: not usual amounts of fragments per block
The writing to UFS file system with block/fragment!=8 may cause bogus behaviour. The problem in "ufs_bitmap_search" function, which doesn't work correctly in "block/fragment!=8" case. The idea is stolen from BSD code. Signed-off-by: Evgeniy Dushistov <dushistov@mail.ru> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r--fs/ufs/balloc.c132
-rw-r--r--fs/ufs/util.h26
2 files changed, 87 insertions, 71 deletions
diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c
index 68de1312e4b6..343eaf4542f8 100644
--- a/fs/ufs/balloc.c
+++ b/fs/ufs/balloc.c
@@ -726,18 +726,63 @@ gotit:
726 return result; 726 return result;
727} 727}
728 728
729static unsigned ufs_bitmap_search (struct super_block * sb, 729static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
730 struct ufs_cg_private_info * ucpi, unsigned goal, unsigned count) 730 struct ufs_buffer_head *ubh,
731 unsigned begin, unsigned size,
732 unsigned char *table, unsigned char mask)
731{ 733{
732 struct ufs_sb_private_info * uspi; 734 unsigned rest, offset;
733 struct ufs_super_block_first * usb1; 735 unsigned char *cp;
734 struct ufs_cylinder_group * ucg; 736
735 unsigned start, length, location, result; 737
736 unsigned possition, fragsize, blockmap, mask; 738 offset = begin & ~uspi->s_fmask;
737 739 begin >>= uspi->s_fshift;
738 UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count)) 740 for (;;) {
741 if ((offset + size) < uspi->s_fsize)
742 rest = size;
743 else
744 rest = uspi->s_fsize - offset;
745 size -= rest;
746 cp = ubh->bh[begin]->b_data + offset;
747 while ((table[*cp++] & mask) == 0 && --rest)
748 ;
749 if (rest || !size)
750 break;
751 begin++;
752 offset = 0;
753 }
754 return (size + rest);
755}
756
757/*
758 * Find a block of the specified size in the specified cylinder group.
759 * @sp: pointer to super block
760 * @ucpi: pointer to cylinder group info
761 * @goal: near which block we want find new one
762 * @count: specified size
763 */
764static unsigned ufs_bitmap_search(struct super_block *sb,
765 struct ufs_cg_private_info *ucpi,
766 unsigned goal, unsigned count)
767{
768 /*
769 * Bit patterns for identifying fragments in the block map
770 * used as ((map & mask_arr) == want_arr)
771 */
772 static const int mask_arr[9] = {
773 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
774 };
775 static const int want_arr[9] = {
776 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
777 };
778 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
779 struct ufs_super_block_first *usb1;
780 struct ufs_cylinder_group *ucg;
781 unsigned start, length, loc, result;
782 unsigned pos, want, blockmap, mask, end;
783
784 UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count));
739 785
740 uspi = UFS_SB(sb)->s_uspi;
741 usb1 = ubh_get_usb_first (uspi); 786 usb1 = ubh_get_usb_first (uspi);
742 ucg = ubh_get_ucg(UCPI_UBH(ucpi)); 787 ucg = ubh_get_ucg(UCPI_UBH(ucpi));
743 788
@@ -747,53 +792,50 @@ static unsigned ufs_bitmap_search (struct super_block * sb,
747 start = ucpi->c_frotor >> 3; 792 start = ucpi->c_frotor >> 3;
748 793
749 length = ((uspi->s_fpg + 7) >> 3) - start; 794 length = ((uspi->s_fpg + 7) >> 3) - start;
750 location = ubh_scanc(UCPI_UBH(ucpi), ucpi->c_freeoff + start, length, 795 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
751 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other, 796 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
752 1 << (count - 1 + (uspi->s_fpb & 7))); 797 1 << (count - 1 + (uspi->s_fpb & 7)));
753 if (location == 0) { 798 if (loc == 0) {
754 length = start + 1; 799 length = start + 1;
755 location = ubh_scanc(UCPI_UBH(ucpi), ucpi->c_freeoff, length, 800 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
756 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other, 801 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
757 1 << (count - 1 + (uspi->s_fpb & 7))); 802 ufs_fragtable_other,
758 if (location == 0) { 803 1 << (count - 1 + (uspi->s_fpb & 7)));
759 ufs_error (sb, "ufs_bitmap_search", 804 if (loc == 0) {
760 "bitmap corrupted on cg %u, start %u, length %u, count %u, freeoff %u\n", 805 ufs_error(sb, "ufs_bitmap_search",
761 ucpi->c_cgx, start, length, count, ucpi->c_freeoff); 806 "bitmap corrupted on cg %u, start %u,"
807 " length %u, count %u, freeoff %u\n",
808 ucpi->c_cgx, start, length, count,
809 ucpi->c_freeoff);
762 return (unsigned)-1; 810 return (unsigned)-1;
763 } 811 }
764 start = 0; 812 start = 0;
765 } 813 }
766 result = (start + length - location) << 3; 814 result = (start + length - loc) << 3;
767 ucpi->c_frotor = result; 815 ucpi->c_frotor = result;
768 816
769 /* 817 /*
770 * found the byte in the map 818 * found the byte in the map
771 */ 819 */
772 blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result); 820
773 fragsize = 0; 821 for (end = result + 8; result < end; result += uspi->s_fpb) {
774 for (possition = 0, mask = 1; possition < 8; possition++, mask <<= 1) { 822 blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
775 if (blockmap & mask) { 823 blockmap <<= 1;
776 if (!(possition & uspi->s_fpbmask)) 824 mask = mask_arr[count];
777 fragsize = 1; 825 want = want_arr[count];
778 else 826 for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
779 fragsize++; 827 if ((blockmap & mask) == want) {
780 } 828 UFSD(("EXIT, result %u\n", result));
781 else { 829 return result + pos;
782 if (fragsize == count) { 830 }
783 result += possition - count; 831 mask <<= 1;
784 UFSD(("EXIT, result %u\n", result)) 832 want <<= 1;
785 return result; 833 }
786 } 834 }
787 fragsize = 0; 835
788 } 836 ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
789 } 837 ucpi->c_cgx);
790 if (fragsize == count) { 838 UFSD(("EXIT (FAILED)\n"));
791 result += possition - count;
792 UFSD(("EXIT, result %u\n", result))
793 return result;
794 }
795 ufs_error (sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx);
796 UFSD(("EXIT (FAILED)\n"))
797 return (unsigned)-1; 839 return (unsigned)-1;
798} 840}
799 841
diff --git a/fs/ufs/util.h b/fs/ufs/util.h
index 6a0b48cf9cef..e95d1c46461f 100644
--- a/fs/ufs/util.h
+++ b/fs/ufs/util.h
@@ -513,29 +513,3 @@ static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap,
513 if (fragsize > 0 && fragsize < uspi->s_fpb) 513 if (fragsize > 0 && fragsize < uspi->s_fpb)
514 fs32_add(sb, &fraglist[fragsize], cnt); 514 fs32_add(sb, &fraglist[fragsize], cnt);
515} 515}
516
517#define ubh_scanc(ubh,begin,size,table,mask) _ubh_scanc_(uspi,ubh,begin,size,table,mask)
518static inline unsigned _ubh_scanc_(struct ufs_sb_private_info * uspi, struct ufs_buffer_head * ubh,
519 unsigned begin, unsigned size, unsigned char * table, unsigned char mask)
520{
521 unsigned rest, offset;
522 unsigned char * cp;
523
524
525 offset = begin & ~uspi->s_fmask;
526 begin >>= uspi->s_fshift;
527 for (;;) {
528 if ((offset + size) < uspi->s_fsize)
529 rest = size;
530 else
531 rest = uspi->s_fsize - offset;
532 size -= rest;
533 cp = ubh->bh[begin]->b_data + offset;
534 while ((table[*cp++] & mask) == 0 && --rest);
535 if (rest || !size)
536 break;
537 begin++;
538 offset = 0;
539 }
540 return (size + rest);
541}