Workaround for mballoc BUG on powerpc. From: Aneesh Kumar K.V This patch adds some of the code removed. The changes fixes the BUG on powerpc with mballoc. Untill we fix the problem this should enable us to run the patch queue on powerpc. Signed-off-by: Aneesh Kumar K.V --- fs/ext4/mballoc.c | 126 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 86 insertions(+), 40 deletions(-) Index: linux-2.6.23/fs/ext4/mballoc.c =================================================================== --- linux-2.6.23.orig/fs/ext4/mballoc.c 2007-10-23 15:42:37.000000000 -0700 +++ linux-2.6.23/fs/ext4/mballoc.c 2007-10-23 15:42:40.000000000 -0700 @@ -501,7 +501,53 @@ static ext4_fsblk_t ext4_grp_offs_to_blo return block; } -static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max) +#if BITS_PER_LONG == 64 +#define mb_correct_addr_and_bit(bit, addr) \ +{ \ + bit += ((unsigned long) addr & 7UL) << 3; \ + addr = (void *) ((unsigned long) addr & ~7UL); \ +} +#elif BITS_PER_LONG == 32 +#define mb_correct_addr_and_bit(bit, addr) \ +{ \ + bit += ((unsigned long) addr & 3UL) << 3; \ + addr = (void *) ((unsigned long) addr & ~3UL); \ +} +#else +#error "how many bits you are?!" +#endif + +static inline int mb_test_bit(int bit, void *addr) +{ + mb_correct_addr_and_bit(bit, addr); + return ext4_test_bit(bit, addr); +} + +static inline void mb_set_bit(int bit, void *addr) +{ + mb_correct_addr_and_bit(bit, addr); + ext4_set_bit(bit, addr); +} + +static inline void mb_set_bit_atomic(int bit, void *addr) +{ + mb_correct_addr_and_bit(bit, addr); + ext4_set_bit_atomic(NULL, bit, addr); +} + +static inline void mb_clear_bit(int bit, void *addr) +{ + mb_correct_addr_and_bit(bit, addr); + ext4_clear_bit(bit, addr); +} + +static inline void mb_clear_bit_atomic(int bit, void *addr) +{ + mb_correct_addr_and_bit(bit, addr); + ext4_clear_bit_atomic(NULL, bit, addr); +} + +static inline void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max) { char *bb; @@ -536,7 +582,7 @@ static void mb_free_blocks_double(struct return; BUG_ON(!ext4_is_group_locked(sb, e4b->bd_group)); for (i = 0; i < count; i++) { - if (!ext4_test_bit(first + i, e4b->bd_info->bb_bitmap)) { + if (!mb_test_bit(first + i, e4b->bd_info->bb_bitmap)) { unsigned long blocknr; blocknr = e4b->bd_group * EXT4_BLOCKS_PER_GROUP(sb); blocknr += first + i; @@ -548,7 +594,7 @@ static void mb_free_blocks_double(struct inode ? inode->i_ino : 0, blocknr, first + i, e4b->bd_group); } - ext4_clear_bit(first + i, e4b->bd_info->bb_bitmap); + mb_clear_bit(first + i, e4b->bd_info->bb_bitmap); } } @@ -560,8 +606,8 @@ static void mb_mark_used_double(struct e return; BUG_ON(!ext4_is_group_locked(e4b->bd_sb, e4b->bd_group)); for (i = 0; i < count; i++) { - BUG_ON(ext4_test_bit(first + i, e4b->bd_info->bb_bitmap)); - ext4_set_bit(first + i, e4b->bd_info->bb_bitmap); + BUG_ON(mb_test_bit(first + i, e4b->bd_info->bb_bitmap)); + mb_set_bit(first + i, e4b->bd_info->bb_bitmap); } } @@ -639,26 +685,26 @@ static int __mb_check_buddy(struct ext4_ count = 0; for (i = 0; i < max; i++) { - if (ext4_test_bit(i, buddy)) { + if (mb_test_bit(i, buddy)) { /* only single bit in buddy2 may be 1 */ - if (!ext4_test_bit(i << 1, buddy2)) { + if (!mb_test_bit(i << 1, buddy2)) { MB_CHECK_ASSERT( - ext4_test_bit((i<<1)+1, buddy2)); - } else if (!ext4_test_bit((i << 1) + 1, buddy2)) { + mb_test_bit((i<<1)+1, buddy2)); + } else if (!mb_test_bit((i << 1) + 1, buddy2)) { MB_CHECK_ASSERT( - ext4_test_bit(i << 1, buddy2)); + mb_test_bit(i << 1, buddy2)); } continue; } /* both bits in buddy2 must be 0 */ - MB_CHECK_ASSERT(ext4_test_bit(i << 1, buddy2)); - MB_CHECK_ASSERT(ext4_test_bit((i << 1) + 1, buddy2)); + MB_CHECK_ASSERT(mb_test_bit(i << 1, buddy2)); + MB_CHECK_ASSERT(mb_test_bit((i << 1) + 1, buddy2)); for (j = 0; j < (1 << order); j++) { k = (i * (1 << order)) + j; MB_CHECK_ASSERT( - !ext4_test_bit(k, EXT4_MB_BITMAP(e4b))); + !mb_test_bit(k, EXT4_MB_BITMAP(e4b))); } count++; } @@ -669,7 +715,7 @@ static int __mb_check_buddy(struct ext4_ fstart = -1; buddy = mb_find_buddy(e4b, 0, &max); for (i = 0; i < max; i++) { - if (!ext4_test_bit(i, buddy)) { + if (!mb_test_bit(i, buddy)) { MB_CHECK_ASSERT(i >= e4b->bd_info->bb_first_free); if (fstart == -1) { fragments++; @@ -683,7 +729,7 @@ static int __mb_check_buddy(struct ext4_ buddy2 = mb_find_buddy(e4b, j, &max2); k = i >> j; MB_CHECK_ASSERT(k < max2); - MB_CHECK_ASSERT(ext4_test_bit(k, buddy2)); + MB_CHECK_ASSERT(mb_test_bit(k, buddy2)); } } MB_CHECK_ASSERT(!EXT4_MB_GRP_NEED_INIT(e4b->bd_info)); @@ -698,7 +744,7 @@ static int __mb_check_buddy(struct ext4_ ext4_get_group_no_and_offset(sb, pa->pstart, &groupnr, &k); MB_CHECK_ASSERT(groupnr == e4b->bd_group); for (i = 0; i < pa->len; i++) - MB_CHECK_ASSERT(ext4_test_bit(k + i, buddy)); + MB_CHECK_ASSERT(mb_test_bit(k + i, buddy)); } return 0; } @@ -757,7 +803,7 @@ static void ext4_mb_mark_free_simple(str /* mark multiblock chunks only */ grp->bb_counters[min]++; if (min > 0) - ext4_clear_bit(first >> min, + mb_clear_bit(first >> min, buddy + sbi->s_mb_offsets[min]); len -= chunk; @@ -1095,7 +1141,7 @@ static int mb_find_order_for_block(struc bb = EXT4_MB_BUDDY(e4b); while (order <= e4b->bd_blkbits + 1) { block = block >> 1; - if (!ext4_test_bit(block, bb)) { + if (!mb_test_bit(block, bb)) { /* this block is part of buddy of order 'order' */ return order; } @@ -1118,7 +1164,7 @@ static void mb_clear_bits(void *bm, int cur += 32; continue; } - ext4_clear_bit_atomic(NULL, cur, bm); + mb_clear_bit_atomic(cur, bm); cur++; } } @@ -1136,7 +1182,7 @@ static void mb_set_bits(void *bm, int cu cur += 32; continue; } - ext4_set_bit_atomic(NULL, cur, bm); + mb_set_bit_atomic(cur, bm); cur++; } } @@ -1162,9 +1208,9 @@ static int mb_free_blocks(struct inode * /* let's maintain fragments counter */ if (first != 0) - block = !ext4_test_bit(first - 1, EXT4_MB_BITMAP(e4b)); + block = !mb_test_bit(first - 1, EXT4_MB_BITMAP(e4b)); if (first + count < EXT4_SB(sb)->s_mb_maxs[0]) - max = !ext4_test_bit(first + count, EXT4_MB_BITMAP(e4b)); + max = !mb_test_bit(first + count, EXT4_MB_BITMAP(e4b)); if (block && max) e4b->bd_info->bb_fragments--; else if (!block && !max) @@ -1175,7 +1221,7 @@ static int mb_free_blocks(struct inode * block = first++; order = 0; - if (!ext4_test_bit(block, EXT4_MB_BITMAP(e4b))) { + if (!mb_test_bit(block, EXT4_MB_BITMAP(e4b))) { unsigned long blocknr; blocknr = e4b->bd_group * EXT4_BLOCKS_PER_GROUP(sb); blocknr += block; @@ -1187,7 +1233,7 @@ static int mb_free_blocks(struct inode * inode ? inode->i_ino : 0, blocknr, block, e4b->bd_group); } - ext4_clear_bit(block, EXT4_MB_BITMAP(e4b)); + mb_clear_bit(block, EXT4_MB_BITMAP(e4b)); e4b->bd_info->bb_counters[order]++; /* start of the buddy */ @@ -1195,8 +1241,8 @@ static int mb_free_blocks(struct inode * do { block &= ~1UL; - if (ext4_test_bit(block, buddy) || - ext4_test_bit(block + 1, buddy)) + if (mb_test_bit(block, buddy) || + mb_test_bit(block + 1, buddy)) break; /* both the buddies are free, try to coalesce them */ @@ -1208,8 +1254,8 @@ static int mb_free_blocks(struct inode * if (order > 0) { /* for special purposes, we don't set * free bits in bitmap */ - ext4_set_bit(block, buddy); - ext4_set_bit(block + 1, buddy); + mb_set_bit(block, buddy); + mb_set_bit(block + 1, buddy); } e4b->bd_info->bb_counters[order]--; e4b->bd_info->bb_counters[order]--; @@ -1218,7 +1264,7 @@ static int mb_free_blocks(struct inode * order++; e4b->bd_info->bb_counters[order]++; - ext4_clear_bit(block, buddy2); + mb_clear_bit(block, buddy2); buddy = buddy2; } while (1); } @@ -1241,7 +1287,7 @@ static int mb_find_extent(struct ext4_bu buddy = mb_find_buddy(e4b, order, &max); BUG_ON(buddy == NULL); BUG_ON(block >= max); - if (ext4_test_bit(block, buddy)) { + if (mb_test_bit(block, buddy)) { ex->fe_len = 0; ex->fe_start = 0; ex->fe_group = 0; @@ -1271,7 +1317,7 @@ static int mb_find_extent(struct ext4_bu break; next = (block + 1) * (1 << order); - if (ext4_test_bit(next, EXT4_MB_BITMAP(e4b))) + if (mb_test_bit(next, EXT4_MB_BITMAP(e4b))) break; ord = mb_find_order_for_block(e4b, next); @@ -1309,9 +1355,9 @@ static int mb_mark_used(struct ext4_budd /* let's maintain fragments counter */ if (start != 0) - mlen = !ext4_test_bit(start - 1, EXT4_MB_BITMAP(e4b)); + mlen = !mb_test_bit(start - 1, EXT4_MB_BITMAP(e4b)); if (start + len < EXT4_SB(e4b->bd_sb)->s_mb_maxs[0]) - max = !ext4_test_bit(start + len, EXT4_MB_BITMAP(e4b)); + max = !mb_test_bit(start + len, EXT4_MB_BITMAP(e4b)); if (mlen && max) e4b->bd_info->bb_fragments++; else if (!mlen && !max) @@ -1326,7 +1372,7 @@ static int mb_mark_used(struct ext4_budd mlen = 1 << ord; buddy = mb_find_buddy(e4b, ord, &max); BUG_ON((start >> ord) >= max); - ext4_set_bit(start >> ord, buddy); + mb_set_bit(start >> ord, buddy); e4b->bd_info->bb_counters[ord]--; start += mlen; len -= mlen; @@ -1341,14 +1387,14 @@ static int mb_mark_used(struct ext4_budd /* we have to split large buddy */ BUG_ON(ord <= 0); buddy = mb_find_buddy(e4b, ord, &max); - ext4_set_bit(start >> ord, buddy); + mb_set_bit(start >> ord, buddy); e4b->bd_info->bb_counters[ord]--; ord--; cur = (start >> ord) & ~1U; buddy = mb_find_buddy(e4b, ord, &max); - ext4_clear_bit(cur, buddy); - ext4_clear_bit(cur + 1, buddy); + mb_clear_bit(cur, buddy); + mb_clear_bit(cur + 1, buddy); e4b->bd_info->bb_counters[ord]++; e4b->bd_info->bb_counters[ord]++; } @@ -1694,7 +1740,7 @@ static void ext4_mb_scan_aligned(struct % EXT4_BLOCKS_PER_GROUP(sb); while (i < sb->s_blocksize * 8) { - if (!ext4_test_bit(i, bitmap)) { + if (!mb_test_bit(i, bitmap)) { max = mb_find_extent(e4b, 0, i, sbi->s_stripe, &ex); if (max >= sbi->s_stripe) { ac->ac_found++; @@ -2934,7 +2980,7 @@ static int ext4_mb_mark_diskspace_used(s { int i; for (i = 0; i < ac->ac_b_ex.fe_len; i++) { - BUG_ON(ext4_test_bit(ac->ac_b_ex.fe_start + i, + BUG_ON(mb_test_bit(ac->ac_b_ex.fe_start + i, bitmap_bh->b_data)); } } @@ -4353,7 +4399,7 @@ do_more: { int i; for (i = 0; i < count; i++) - BUG_ON(!ext4_test_bit(bit + i, bitmap_bh->b_data)); + BUG_ON(!mb_test_bit(bit + i, bitmap_bh->b_data)); } #endif mb_clear_bits(bitmap_bh->b_data, bit, count);