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 | } | ||