Btrfs: fix extent buffer bitmap tests on big-endian systems
The in-memory bitmap code manipulates words and is therefore sensitive to endianness, while the extent buffer bitmap code addresses bytes and is byte-order agnostic. Because the byte addressing of the extent buffer bitmaps is equivalent to a little-endian in-memory bitmap, the extent buffer bitmap tests fail on big-endian systems. 34b3e6c92af1 ("Btrfs: self-tests: Fix extent buffer bitmap test fail on BE system") worked around another endianness bug in the tests but missed this one because ed9e4afdb055 ("Btrfs: self-tests: Execute page straddling test only when nodesize < PAGE_SIZE") disables this part of the test on ppc64. That change lost the original meaning of the test, however. We really want to test that an equivalent series of operations using the in-memory bitmap API and the extent buffer bitmap API produces equivalent results. To fix this, don't use memcmp_extent_buffer() or write_extent_buffer(); do everything bit-by-bit. Reported-by: Anatoly Pugachev <matorola@gmail.com> Tested-by: Anatoly Pugachev <matorola@gmail.com> Tested-by: Feifei Xu <xufeifei@linux.vnet.ibm.com> Tested-by: Chandan Rajendra <chandan@linux.vnet.ibm.com> Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
committed by
David Sterba
parent
6675df311d
commit
9426ce754f
@ -273,20 +273,37 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static int check_eb_bitmap(unsigned long *bitmap, struct extent_buffer *eb,
|
||||||
* test_bit_in_byte - Determine whether a bit is set in a byte
|
unsigned long len)
|
||||||
* @nr: bit number to test
|
|
||||||
* @addr: Address to start counting from
|
|
||||||
*/
|
|
||||||
static inline int test_bit_in_byte(int nr, const u8 *addr)
|
|
||||||
{
|
{
|
||||||
return 1UL & (addr[nr / BITS_PER_BYTE] >> (nr & (BITS_PER_BYTE - 1)));
|
unsigned long i;
|
||||||
|
|
||||||
|
for (i = 0; i < len * BITS_PER_BYTE; i++) {
|
||||||
|
int bit, bit1;
|
||||||
|
|
||||||
|
bit = !!test_bit(i, bitmap);
|
||||||
|
bit1 = !!extent_buffer_test_bit(eb, 0, i);
|
||||||
|
if (bit1 != bit) {
|
||||||
|
test_msg("Bits do not match\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE,
|
||||||
|
i % BITS_PER_BYTE);
|
||||||
|
if (bit1 != bit) {
|
||||||
|
test_msg("Offset bits do not match\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
|
static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
|
||||||
unsigned long len)
|
unsigned long len)
|
||||||
{
|
{
|
||||||
unsigned long i, x;
|
unsigned long i, j;
|
||||||
|
u32 x;
|
||||||
|
int ret;
|
||||||
|
|
||||||
memset(bitmap, 0, len);
|
memset(bitmap, 0, len);
|
||||||
memset_extent_buffer(eb, 0, 0, len);
|
memset_extent_buffer(eb, 0, 0, len);
|
||||||
@ -297,16 +314,18 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
|
|||||||
|
|
||||||
bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
|
bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
|
||||||
extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
|
extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
|
||||||
if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
|
ret = check_eb_bitmap(bitmap, eb, len);
|
||||||
|
if (ret) {
|
||||||
test_msg("Setting all bits failed\n");
|
test_msg("Setting all bits failed\n");
|
||||||
return -EINVAL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
|
bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
|
||||||
extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
|
extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
|
||||||
if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
|
ret = check_eb_bitmap(bitmap, eb, len);
|
||||||
|
if (ret) {
|
||||||
test_msg("Clearing all bits failed\n");
|
test_msg("Clearing all bits failed\n");
|
||||||
return -EINVAL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Straddling pages test */
|
/* Straddling pages test */
|
||||||
@ -316,9 +335,10 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
|
|||||||
sizeof(long) * BITS_PER_BYTE);
|
sizeof(long) * BITS_PER_BYTE);
|
||||||
extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0,
|
extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0,
|
||||||
sizeof(long) * BITS_PER_BYTE);
|
sizeof(long) * BITS_PER_BYTE);
|
||||||
if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
|
ret = check_eb_bitmap(bitmap, eb, len);
|
||||||
|
if (ret) {
|
||||||
test_msg("Setting straddling pages failed\n");
|
test_msg("Setting straddling pages failed\n");
|
||||||
return -EINVAL;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
|
bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
|
||||||
@ -328,9 +348,10 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
|
|||||||
extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
|
extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
|
||||||
extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0,
|
extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0,
|
||||||
sizeof(long) * BITS_PER_BYTE);
|
sizeof(long) * BITS_PER_BYTE);
|
||||||
if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
|
ret = check_eb_bitmap(bitmap, eb, len);
|
||||||
|
if (ret) {
|
||||||
test_msg("Clearing straddling pages failed\n");
|
test_msg("Clearing straddling pages failed\n");
|
||||||
return -EINVAL;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -339,28 +360,22 @@ static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
|
|||||||
* something repetitive that could miss some hypothetical off-by-n bug.
|
* something repetitive that could miss some hypothetical off-by-n bug.
|
||||||
*/
|
*/
|
||||||
x = 0;
|
x = 0;
|
||||||
for (i = 0; i < len / sizeof(long); i++) {
|
bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
|
||||||
x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffUL;
|
extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
|
||||||
bitmap[i] = x;
|
for (i = 0; i < len * BITS_PER_BYTE / 32; i++) {
|
||||||
|
x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffU;
|
||||||
|
for (j = 0; j < 32; j++) {
|
||||||
|
if (x & (1U << j)) {
|
||||||
|
bitmap_set(bitmap, i * 32 + j, 1);
|
||||||
|
extent_buffer_bitmap_set(eb, 0, i * 32 + j, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
write_extent_buffer(eb, bitmap, 0, len);
|
|
||||||
|
|
||||||
for (i = 0; i < len * BITS_PER_BYTE; i++) {
|
ret = check_eb_bitmap(bitmap, eb, len);
|
||||||
int bit, bit1;
|
if (ret) {
|
||||||
|
test_msg("Random bit pattern failed\n");
|
||||||
bit = !!test_bit_in_byte(i, (u8 *)bitmap);
|
return ret;
|
||||||
bit1 = !!extent_buffer_test_bit(eb, 0, i);
|
|
||||||
if (bit1 != bit) {
|
|
||||||
test_msg("Testing bit pattern failed\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE,
|
|
||||||
i % BITS_PER_BYTE);
|
|
||||||
if (bit1 != bit) {
|
|
||||||
test_msg("Testing bit pattern with offset failed\n");
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user