diff options
| author | Evgeniy Dushistov <dushistov@mail.ru> | 2006-06-25 08:47:23 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-25 13:01:02 -0400 |
| commit | 3e41f597b1595479e4a1b2e6b17b3542120ef165 (patch) | |
| tree | a4adfd190f25b6b896ae04e9d4cbd6c4d94c872c /fs/ufs | |
| parent | 9695ef16ed4e00b59303f39f9a4a422a2c6a3b89 (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>
Diffstat (limited to 'fs/ufs')
| -rw-r--r-- | fs/ufs/balloc.c | 132 | ||||
| -rw-r--r-- | fs/ufs/util.h | 26 |
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 | ||
| 729 | static unsigned ufs_bitmap_search (struct super_block * sb, | 729 | static 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 | */ | ||
| 764 | static 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) | ||
| 518 | static 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 | } | ||
