Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 0f331229 authored by Omar Sandoval's avatar Omar Sandoval Committed by Chris Mason
Browse files

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: default avatarOmar Sandoval <osandov@fb.com>
Signed-off-by: default avatarChris Mason <clm@fb.com>
parent 3e1e8bb7
Loading
Loading
Loading
Loading
+21 −13
Original line number Diff line number Diff line
@@ -4730,24 +4730,14 @@ struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src)
	return new;
}

struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
						u64 start)
struct extent_buffer *__alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
						  u64 start, unsigned long len)
{
	struct extent_buffer *eb;
	unsigned long len;
	unsigned long num_pages;
	unsigned long i;

	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;
	}
	num_pages = num_extent_pages(0, len);
	num_pages = num_extent_pages(start, len);

	eb = __alloc_extent_buffer(fs_info, start, len);
	if (!eb)
@@ -4770,6 +4760,24 @@ struct extent_buffer *alloc_dummy_extent_buffer(struct btrfs_fs_info *fs_info,
	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)
{
	int refs;
+3 −1
Original line number Diff line number Diff line
@@ -263,6 +263,8 @@ void set_page_extent_mapped(struct page *page);

struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
					  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,
						u64 start);
struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
+136 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#include <linux/pagemap.h>
#include <linux/sched.h>
#include <linux/slab.h>
#include "btrfs-tests.h"
#include "../extent_io.h"

@@ -76,6 +77,8 @@ static int test_find_delalloc(void)
	u64 found;
	int ret = -EINVAL;

	test_msg("Running find delalloc tests\n");

	inode = btrfs_new_test_inode();
	if (!inode) {
		test_msg("Failed to allocate test inode\n");
@@ -268,8 +271,139 @@ static int test_find_delalloc(void)
	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)
{
	test_msg("Running find delalloc tests\n");
	return test_find_delalloc();
	int ret;

	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;
}