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 | 161 ++++++++++++++++++++++++++++++++++++++++------------- 1 files changed, 121 insertions(+), 40 deletions(-) diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 4409c0c..79a3530 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -501,7 +501,88 @@ static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, 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 int mb_find_next_zero_bit(void *addr, int max, int start) +{ + int fix; +#if BITS_PER_LONG == 64 + fix = ((unsigned long) addr & 7UL) << 3; + addr = (void *) ((unsigned long) addr & ~7UL); +#elif BITS_PER_LONG == 32 + fix = ((unsigned long) addr & 3UL) << 3; + addr = (void *) ((unsigned long) addr & ~3UL); +#else +#error "how many bits you are?!" +#endif + max += fix; + start += fix; + return ext4_find_next_zero_bit(addr, max, start) - fix; +} + +static inline int mb_find_next_bit(void *addr, int max, int start) +{ + int fix; +#if BITS_PER_LONG == 64 + fix = ((unsigned long) addr & 7UL) << 3; + addr = (void *) ((unsigned long) addr & ~7UL); +#elif BITS_PER_LONG == 32 + fix = ((unsigned long) addr & 3UL) << 3; + addr = (void *) ((unsigned long) addr & ~3UL); +#else +#error "how many bits you are?!" +#endif + max += fix; + start += fix; + + return ext4_find_next_bit(addr, max, start) - fix; +} + +static inline void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max) { char *bb; @@ -536,7 +617,7 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b, 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 +629,7 @@ static void mb_free_blocks_double(struct inode *inode, struct ext4_buddy *e4b, 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 +641,8 @@ static void mb_mark_used_double(struct ext4_buddy *e4b, int first, int count) 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 +720,26 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, 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 +750,7 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, 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 +764,7 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, 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 +779,7 @@ static int __mb_check_buddy(struct ext4_buddy *e4b, char *file, 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 +838,7 @@ static void ext4_mb_mark_free_simple(struct super_block *sb, /* 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 +1176,7 @@ static int mb_find_order_for_block(struct ext4_buddy *e4b, int block) 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 +1199,7 @@ static void mb_clear_bits(void *bm, int cur, int len) cur += 32; continue; } - ext4_clear_bit_atomic(NULL, cur, bm); + mb_clear_bit_atomic(cur, bm); cur++; } } @@ -1136,7 +1217,7 @@ static void mb_set_bits(void *bm, int cur, int len) cur += 32; continue; } - ext4_set_bit_atomic(NULL, cur, bm); + mb_set_bit_atomic(cur, bm); cur++; } } @@ -1162,9 +1243,9 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, /* 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 +1256,7 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, 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 +1268,7 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, 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 +1276,8 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, 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 +1289,8 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, 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 +1299,7 @@ static int mb_free_blocks(struct inode *inode, struct ext4_buddy *e4b, order++; e4b->bd_info->bb_counters[order]++; - ext4_clear_bit(block, buddy2); + mb_clear_bit(block, buddy2); buddy = buddy2; } while (1); } @@ -1241,7 +1322,7 @@ static int mb_find_extent(struct ext4_buddy *e4b, int order, int block, 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 +1352,7 @@ static int mb_find_extent(struct ext4_buddy *e4b, int order, int block, 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 +1390,9 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex) /* 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 +1407,7 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex) 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 +1422,14 @@ static int mb_mark_used(struct ext4_buddy *e4b, struct ext4_free_extent *ex) /* 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 +1775,7 @@ static void ext4_mb_scan_aligned(struct ext4_allocation_context *ac, % 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++; @@ -2930,7 +3011,7 @@ static int ext4_mb_mark_diskspace_used(struct ext4_allocation_context *ac, { 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)); } } @@ -4352,7 +4433,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);