Commit ffad0a44 authored by Aneesh Kumar K.V's avatar Aneesh Kumar K.V Committed by Theodore Ts'o

ext4: ext4_find_next_zero_bit needs an aligned address on some arch

ext4_find_next_zero_bit and ext4_find_next_bit needs a long aligned
address on x8_64. Add mb_find_next_zero_bit and mb_find_next_bit
and use them in the mballoc.

Fix: https://bugzilla.redhat.com/show_bug.cgi?id=433286

Eric Sandeen debugged the problem and suggested the fix.
Signed-off-by: default avatarAneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Acked-by: default avatarEric Sandeen <sandeen@redhat.com>
Signed-off-by: default avatarMingming Cao <cmm@us.ibm.com>
Signed-off-by: default avatar"Theodore Ts'o" <tytso@mit.edu>
parent 42bf0383
...@@ -627,21 +627,19 @@ static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb, ...@@ -627,21 +627,19 @@ static ext4_fsblk_t ext4_grp_offs_to_block(struct super_block *sb,
return block; return block;
} }
static inline void *mb_correct_addr_and_bit(int *bit, void *addr)
{
#if BITS_PER_LONG == 64 #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);
bit += ((unsigned long) addr & 7UL) << 3; \
addr = (void *) ((unsigned long) addr & ~7UL); \
}
#elif BITS_PER_LONG == 32 #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);
bit += ((unsigned long) addr & 3UL) << 3; \
addr = (void *) ((unsigned long) addr & ~3UL); \
}
#else #else
#error "how many bits you are?!" #error "how many bits you are?!"
#endif #endif
return addr;
}
static inline int mb_test_bit(int bit, void *addr) static inline int mb_test_bit(int bit, void *addr)
{ {
...@@ -649,34 +647,54 @@ static inline int mb_test_bit(int bit, void *addr) ...@@ -649,34 +647,54 @@ static inline int mb_test_bit(int bit, void *addr)
* ext4_test_bit on architecture like powerpc * ext4_test_bit on architecture like powerpc
* needs unsigned long aligned address * needs unsigned long aligned address
*/ */
mb_correct_addr_and_bit(bit, addr); addr = mb_correct_addr_and_bit(&bit, addr);
return ext4_test_bit(bit, addr); return ext4_test_bit(bit, addr);
} }
static inline void mb_set_bit(int bit, void *addr) static inline void mb_set_bit(int bit, void *addr)
{ {
mb_correct_addr_and_bit(bit, addr); addr = mb_correct_addr_and_bit(&bit, addr);
ext4_set_bit(bit, addr); ext4_set_bit(bit, addr);
} }
static inline void mb_set_bit_atomic(spinlock_t *lock, int bit, void *addr) static inline void mb_set_bit_atomic(spinlock_t *lock, int bit, void *addr)
{ {
mb_correct_addr_and_bit(bit, addr); addr = mb_correct_addr_and_bit(&bit, addr);
ext4_set_bit_atomic(lock, bit, addr); ext4_set_bit_atomic(lock, bit, addr);
} }
static inline void mb_clear_bit(int bit, void *addr) static inline void mb_clear_bit(int bit, void *addr)
{ {
mb_correct_addr_and_bit(bit, addr); addr = mb_correct_addr_and_bit(&bit, addr);
ext4_clear_bit(bit, addr); ext4_clear_bit(bit, addr);
} }
static inline void mb_clear_bit_atomic(spinlock_t *lock, int bit, void *addr) static inline void mb_clear_bit_atomic(spinlock_t *lock, int bit, void *addr)
{ {
mb_correct_addr_and_bit(bit, addr); addr = mb_correct_addr_and_bit(&bit, addr);
ext4_clear_bit_atomic(lock, bit, addr); ext4_clear_bit_atomic(lock, bit, addr);
} }
static inline int mb_find_next_zero_bit(void *addr, int max, int start)
{
int fix = 0;
addr = mb_correct_addr_and_bit(&fix, addr);
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 = 0;
addr = mb_correct_addr_and_bit(&fix, addr);
max += fix;
start += fix;
return ext4_find_next_bit(addr, max, start) - fix;
}
static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max) static void *mb_find_buddy(struct ext4_buddy *e4b, int order, int *max)
{ {
char *bb; char *bb;
...@@ -946,12 +964,12 @@ static void ext4_mb_generate_buddy(struct super_block *sb, ...@@ -946,12 +964,12 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
/* initialize buddy from bitmap which is aggregation /* initialize buddy from bitmap which is aggregation
* of on-disk bitmap and preallocations */ * of on-disk bitmap and preallocations */
i = ext4_find_next_zero_bit(bitmap, max, 0); i = mb_find_next_zero_bit(bitmap, max, 0);
grp->bb_first_free = i; grp->bb_first_free = i;
while (i < max) { while (i < max) {
fragments++; fragments++;
first = i; first = i;
i = ext4_find_next_bit(bitmap, max, i); i = mb_find_next_bit(bitmap, max, i);
len = i - first; len = i - first;
free += len; free += len;
if (len > 1) if (len > 1)
...@@ -959,7 +977,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb, ...@@ -959,7 +977,7 @@ static void ext4_mb_generate_buddy(struct super_block *sb,
else else
grp->bb_counters[0]++; grp->bb_counters[0]++;
if (i < max) if (i < max)
i = ext4_find_next_zero_bit(bitmap, max, i); i = mb_find_next_zero_bit(bitmap, max, i);
} }
grp->bb_fragments = fragments; grp->bb_fragments = fragments;
...@@ -1782,7 +1800,7 @@ static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac, ...@@ -1782,7 +1800,7 @@ static void ext4_mb_simple_scan_group(struct ext4_allocation_context *ac,
buddy = mb_find_buddy(e4b, i, &max); buddy = mb_find_buddy(e4b, i, &max);
BUG_ON(buddy == NULL); BUG_ON(buddy == NULL);
k = ext4_find_next_zero_bit(buddy, max, 0); k = mb_find_next_zero_bit(buddy, max, 0);
BUG_ON(k >= max); BUG_ON(k >= max);
ac->ac_found++; ac->ac_found++;
...@@ -1822,7 +1840,7 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac, ...@@ -1822,7 +1840,7 @@ static void ext4_mb_complex_scan_group(struct ext4_allocation_context *ac,
i = e4b->bd_info->bb_first_free; i = e4b->bd_info->bb_first_free;
while (free && ac->ac_status == AC_STATUS_CONTINUE) { while (free && ac->ac_status == AC_STATUS_CONTINUE) {
i = ext4_find_next_zero_bit(bitmap, i = mb_find_next_zero_bit(bitmap,
EXT4_BLOCKS_PER_GROUP(sb), i); EXT4_BLOCKS_PER_GROUP(sb), i);
if (i >= EXT4_BLOCKS_PER_GROUP(sb)) { if (i >= EXT4_BLOCKS_PER_GROUP(sb)) {
/* /*
...@@ -3750,10 +3768,10 @@ static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b, ...@@ -3750,10 +3768,10 @@ static int ext4_mb_release_inode_pa(struct ext4_buddy *e4b,
} }
while (bit < end) { while (bit < end) {
bit = ext4_find_next_zero_bit(bitmap_bh->b_data, end, bit); bit = mb_find_next_zero_bit(bitmap_bh->b_data, end, bit);
if (bit >= end) if (bit >= end)
break; break;
next = ext4_find_next_bit(bitmap_bh->b_data, end, bit); next = mb_find_next_bit(bitmap_bh->b_data, end, bit);
if (next > end) if (next > end)
next = end; next = end;
start = group * EXT4_BLOCKS_PER_GROUP(sb) + bit + start = group * EXT4_BLOCKS_PER_GROUP(sb) + bit +
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment