Btrfs: add extent buffer bitmap sanity tests
Sanity test the extent buffer bitmap operations (test, set, and clear) against the equivalent standard kernel operations. Signed-off-by: Omar Sandoval <osandov@fb.com> Signed-off-by: Chris Mason <clm@fb.com>
This commit is contained in:
parent
3e1e8bb770
commit
0f3312295d
@ -4730,24 +4730,14 @@ struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src)
|
|||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||||
u64 start)
|
u64 start, unsigned long len)
|
||||||
{
|
{
|
||||||
struct extent_buffer *eb;
|
struct extent_buffer *eb;
|
||||||
unsigned long len;
|
|
||||||
unsigned long num_pages;
|
unsigned long num_pages;
|
||||||
unsigned long i;
|
unsigned long i;
|
||||||
|
|
||||||
if (!fs_info) {
|
num_pages = num_extent_pages(start, len);
|
||||||
/*
|
|
||||||
* Called only from tests that don't always have a fs_info
|
|
||||||
* available, but we know that nodesize is 4096
|
|
||||||
*/
|
|
||||||
len = 4096;
|
|
||||||
} else {
|
|
||||||
len = fs_info->tree_root->nodesize;
|
|
||||||
}
|
|
||||||
num_pages = num_extent_pages(0, len);
|
|
||||||
|
|
||||||
eb = __alloc_extent_buffer(fs_info, start, len);
|
eb = __alloc_extent_buffer(fs_info, start, len);
|
||||||
if (!eb)
|
if (!eb)
|
||||||
@ -4770,6 +4760,24 @@ err:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||||
|
u64 start)
|
||||||
|
{
|
||||||
|
unsigned long len;
|
||||||
|
|
||||||
|
if (!fs_info) {
|
||||||
|
/*
|
||||||
|
* Called only from tests that don't always have a fs_info
|
||||||
|
* available, but we know that nodesize is 4096
|
||||||
|
*/
|
||||||
|
len = 4096;
|
||||||
|
} else {
|
||||||
|
len = fs_info->tree_root->nodesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
return __alloc_dummy_extent_buffer(fs_info, start, len);
|
||||||
|
}
|
||||||
|
|
||||||
static void check_buffer_tree_ref(struct extent_buffer *eb)
|
static void check_buffer_tree_ref(struct extent_buffer *eb)
|
||||||
{
|
{
|
||||||
int refs;
|
int refs;
|
||||||
|
@ -263,8 +263,10 @@ void set_page_extent_mapped(struct page *page);
|
|||||||
|
|
||||||
struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
|
struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||||
u64 start);
|
u64 start);
|
||||||
|
struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||||
|
u64 start, unsigned long len);
|
||||||
struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||||
u64 start);
|
u64 start);
|
||||||
struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
|
struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
|
||||||
struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
|
struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
|
||||||
u64 start);
|
u64 start);
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <linux/pagemap.h>
|
#include <linux/pagemap.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
#include "btrfs-tests.h"
|
#include "btrfs-tests.h"
|
||||||
#include "../extent_io.h"
|
#include "../extent_io.h"
|
||||||
|
|
||||||
@ -76,6 +77,8 @@ static int test_find_delalloc(void)
|
|||||||
u64 found;
|
u64 found;
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
|
|
||||||
|
test_msg("Running find delalloc tests\n");
|
||||||
|
|
||||||
inode = btrfs_new_test_inode();
|
inode = btrfs_new_test_inode();
|
||||||
if (!inode) {
|
if (!inode) {
|
||||||
test_msg("Failed to allocate test inode\n");
|
test_msg("Failed to allocate test inode\n");
|
||||||
@ -268,8 +271,139 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
|
||||||
|
unsigned long len)
|
||||||
|
{
|
||||||
|
unsigned long i, x;
|
||||||
|
|
||||||
|
memset(bitmap, 0, len);
|
||||||
|
memset_extent_buffer(eb, 0, 0, len);
|
||||||
|
if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
|
||||||
|
test_msg("Bitmap was not zeroed\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_set(bitmap, 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) {
|
||||||
|
test_msg("Setting all bits failed\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_clear(bitmap, 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) {
|
||||||
|
test_msg("Clearing all bits failed\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_set(bitmap, (PAGE_CACHE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
|
||||||
|
sizeof(long) * BITS_PER_BYTE);
|
||||||
|
extent_buffer_bitmap_set(eb, PAGE_CACHE_SIZE - sizeof(long) / 2, 0,
|
||||||
|
sizeof(long) * BITS_PER_BYTE);
|
||||||
|
if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
|
||||||
|
test_msg("Setting straddling pages failed\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
|
||||||
|
bitmap_clear(bitmap,
|
||||||
|
(PAGE_CACHE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
|
||||||
|
sizeof(long) * BITS_PER_BYTE);
|
||||||
|
extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
|
||||||
|
extent_buffer_bitmap_clear(eb, PAGE_CACHE_SIZE - sizeof(long) / 2, 0,
|
||||||
|
sizeof(long) * BITS_PER_BYTE);
|
||||||
|
if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
|
||||||
|
test_msg("Clearing straddling pages failed\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate a wonky pseudo-random bit pattern for the sake of not using
|
||||||
|
* something repetitive that could miss some hypothetical off-by-n bug.
|
||||||
|
*/
|
||||||
|
x = 0;
|
||||||
|
for (i = 0; i < len / sizeof(long); i++) {
|
||||||
|
x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffUL;
|
||||||
|
bitmap[i] = x;
|
||||||
|
}
|
||||||
|
write_extent_buffer(eb, bitmap, 0, len);
|
||||||
|
|
||||||
|
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("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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int test_eb_bitmaps(void)
|
||||||
|
{
|
||||||
|
unsigned long len = PAGE_CACHE_SIZE * 4;
|
||||||
|
unsigned long *bitmap;
|
||||||
|
struct extent_buffer *eb;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
test_msg("Running extent buffer bitmap tests\n");
|
||||||
|
|
||||||
|
bitmap = kmalloc(len, GFP_NOFS);
|
||||||
|
if (!bitmap) {
|
||||||
|
test_msg("Couldn't allocate test bitmap\n");
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
eb = __alloc_dummy_extent_buffer(NULL, 0, len);
|
||||||
|
if (!eb) {
|
||||||
|
test_msg("Couldn't allocate test extent buffer\n");
|
||||||
|
kfree(bitmap);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = __test_eb_bitmaps(bitmap, eb, len);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Do it over again with an extent buffer which isn't page-aligned. */
|
||||||
|
free_extent_buffer(eb);
|
||||||
|
eb = __alloc_dummy_extent_buffer(NULL, PAGE_CACHE_SIZE / 2, len);
|
||||||
|
if (!eb) {
|
||||||
|
test_msg("Couldn't allocate test extent buffer\n");
|
||||||
|
kfree(bitmap);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = __test_eb_bitmaps(bitmap, eb, len);
|
||||||
|
out:
|
||||||
|
free_extent_buffer(eb);
|
||||||
|
kfree(bitmap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
int btrfs_test_extent_io(void)
|
int btrfs_test_extent_io(void)
|
||||||
{
|
{
|
||||||
test_msg("Running find delalloc tests\n");
|
int ret;
|
||||||
return test_find_delalloc();
|
|
||||||
|
test_msg("Running extent I/O tests\n");
|
||||||
|
|
||||||
|
ret = test_find_delalloc();
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
ret = test_eb_bitmaps();
|
||||||
|
out:
|
||||||
|
test_msg("Extent I/O tests finished\n");
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user