cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

extent-io-tests.c (15846B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2013 Fusion IO.  All rights reserved.
      4 */
      5
      6#include <linux/pagemap.h>
      7#include <linux/sched.h>
      8#include <linux/slab.h>
      9#include <linux/sizes.h>
     10#include "btrfs-tests.h"
     11#include "../ctree.h"
     12#include "../extent_io.h"
     13#include "../btrfs_inode.h"
     14
     15#define PROCESS_UNLOCK		(1 << 0)
     16#define PROCESS_RELEASE		(1 << 1)
     17#define PROCESS_TEST_LOCKED	(1 << 2)
     18
     19static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
     20				       unsigned long flags)
     21{
     22	int ret;
     23	struct page *pages[16];
     24	unsigned long index = start >> PAGE_SHIFT;
     25	unsigned long end_index = end >> PAGE_SHIFT;
     26	unsigned long nr_pages = end_index - index + 1;
     27	int i;
     28	int count = 0;
     29	int loops = 0;
     30
     31	while (nr_pages > 0) {
     32		ret = find_get_pages_contig(inode->i_mapping, index,
     33				     min_t(unsigned long, nr_pages,
     34				     ARRAY_SIZE(pages)), pages);
     35		for (i = 0; i < ret; i++) {
     36			if (flags & PROCESS_TEST_LOCKED &&
     37			    !PageLocked(pages[i]))
     38				count++;
     39			if (flags & PROCESS_UNLOCK && PageLocked(pages[i]))
     40				unlock_page(pages[i]);
     41			put_page(pages[i]);
     42			if (flags & PROCESS_RELEASE)
     43				put_page(pages[i]);
     44		}
     45		nr_pages -= ret;
     46		index += ret;
     47		cond_resched();
     48		loops++;
     49		if (loops > 100000) {
     50			printk(KERN_ERR
     51		"stuck in a loop, start %llu, end %llu, nr_pages %lu, ret %d\n",
     52				start, end, nr_pages, ret);
     53			break;
     54		}
     55	}
     56	return count;
     57}
     58
     59#define STATE_FLAG_STR_LEN			256
     60
     61#define PRINT_ONE_FLAG(state, dest, cur, name)				\
     62({									\
     63	if (state->state & EXTENT_##name)				\
     64		cur += scnprintf(dest + cur, STATE_FLAG_STR_LEN - cur,	\
     65				 "%s" #name, cur == 0 ? "" : "|");	\
     66})
     67
     68static void extent_flag_to_str(const struct extent_state *state, char *dest)
     69{
     70	int cur = 0;
     71
     72	dest[0] = 0;
     73	PRINT_ONE_FLAG(state, dest, cur, DIRTY);
     74	PRINT_ONE_FLAG(state, dest, cur, UPTODATE);
     75	PRINT_ONE_FLAG(state, dest, cur, LOCKED);
     76	PRINT_ONE_FLAG(state, dest, cur, NEW);
     77	PRINT_ONE_FLAG(state, dest, cur, DELALLOC);
     78	PRINT_ONE_FLAG(state, dest, cur, DEFRAG);
     79	PRINT_ONE_FLAG(state, dest, cur, BOUNDARY);
     80	PRINT_ONE_FLAG(state, dest, cur, NODATASUM);
     81	PRINT_ONE_FLAG(state, dest, cur, CLEAR_META_RESV);
     82	PRINT_ONE_FLAG(state, dest, cur, NEED_WAIT);
     83	PRINT_ONE_FLAG(state, dest, cur, DAMAGED);
     84	PRINT_ONE_FLAG(state, dest, cur, NORESERVE);
     85	PRINT_ONE_FLAG(state, dest, cur, QGROUP_RESERVED);
     86	PRINT_ONE_FLAG(state, dest, cur, CLEAR_DATA_RESV);
     87}
     88
     89static void dump_extent_io_tree(const struct extent_io_tree *tree)
     90{
     91	struct rb_node *node;
     92	char flags_str[STATE_FLAG_STR_LEN];
     93
     94	node = rb_first(&tree->state);
     95	test_msg("io tree content:");
     96	while (node) {
     97		struct extent_state *state;
     98
     99		state = rb_entry(node, struct extent_state, rb_node);
    100		extent_flag_to_str(state, flags_str);
    101		test_msg("  start=%llu len=%llu flags=%s", state->start,
    102			 state->end + 1 - state->start, flags_str);
    103		node = rb_next(node);
    104	}
    105}
    106
    107static int test_find_delalloc(u32 sectorsize)
    108{
    109	struct inode *inode;
    110	struct extent_io_tree *tmp;
    111	struct page *page;
    112	struct page *locked_page = NULL;
    113	unsigned long index = 0;
    114	/* In this test we need at least 2 file extents at its maximum size */
    115	u64 max_bytes = BTRFS_MAX_EXTENT_SIZE;
    116	u64 total_dirty = 2 * max_bytes;
    117	u64 start, end, test_start;
    118	bool found;
    119	int ret = -EINVAL;
    120
    121	test_msg("running find delalloc tests");
    122
    123	inode = btrfs_new_test_inode();
    124	if (!inode) {
    125		test_std_err(TEST_ALLOC_INODE);
    126		return -ENOMEM;
    127	}
    128	tmp = &BTRFS_I(inode)->io_tree;
    129
    130	/*
    131	 * Passing NULL as we don't have fs_info but tracepoints are not used
    132	 * at this point
    133	 */
    134	extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST, NULL);
    135
    136	/*
    137	 * First go through and create and mark all of our pages dirty, we pin
    138	 * everything to make sure our pages don't get evicted and screw up our
    139	 * test.
    140	 */
    141	for (index = 0; index < (total_dirty >> PAGE_SHIFT); index++) {
    142		page = find_or_create_page(inode->i_mapping, index, GFP_KERNEL);
    143		if (!page) {
    144			test_err("failed to allocate test page");
    145			ret = -ENOMEM;
    146			goto out;
    147		}
    148		SetPageDirty(page);
    149		if (index) {
    150			unlock_page(page);
    151		} else {
    152			get_page(page);
    153			locked_page = page;
    154		}
    155	}
    156
    157	/* Test this scenario
    158	 * |--- delalloc ---|
    159	 * |---  search  ---|
    160	 */
    161	set_extent_delalloc(tmp, 0, sectorsize - 1, 0, NULL);
    162	start = 0;
    163	end = start + PAGE_SIZE - 1;
    164	found = find_lock_delalloc_range(inode, locked_page, &start,
    165					 &end);
    166	if (!found) {
    167		test_err("should have found at least one delalloc");
    168		goto out_bits;
    169	}
    170	if (start != 0 || end != (sectorsize - 1)) {
    171		test_err("expected start 0 end %u, got start %llu end %llu",
    172			sectorsize - 1, start, end);
    173		goto out_bits;
    174	}
    175	unlock_extent(tmp, start, end);
    176	unlock_page(locked_page);
    177	put_page(locked_page);
    178
    179	/*
    180	 * Test this scenario
    181	 *
    182	 * |--- delalloc ---|
    183	 *           |--- search ---|
    184	 */
    185	test_start = SZ_64M;
    186	locked_page = find_lock_page(inode->i_mapping,
    187				     test_start >> PAGE_SHIFT);
    188	if (!locked_page) {
    189		test_err("couldn't find the locked page");
    190		goto out_bits;
    191	}
    192	set_extent_delalloc(tmp, sectorsize, max_bytes - 1, 0, NULL);
    193	start = test_start;
    194	end = start + PAGE_SIZE - 1;
    195	found = find_lock_delalloc_range(inode, locked_page, &start,
    196					 &end);
    197	if (!found) {
    198		test_err("couldn't find delalloc in our range");
    199		goto out_bits;
    200	}
    201	if (start != test_start || end != max_bytes - 1) {
    202		test_err("expected start %llu end %llu, got start %llu, end %llu",
    203				test_start, max_bytes - 1, start, end);
    204		goto out_bits;
    205	}
    206	if (process_page_range(inode, start, end,
    207			       PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
    208		test_err("there were unlocked pages in the range");
    209		goto out_bits;
    210	}
    211	unlock_extent(tmp, start, end);
    212	/* locked_page was unlocked above */
    213	put_page(locked_page);
    214
    215	/*
    216	 * Test this scenario
    217	 * |--- delalloc ---|
    218	 *                    |--- search ---|
    219	 */
    220	test_start = max_bytes + sectorsize;
    221	locked_page = find_lock_page(inode->i_mapping, test_start >>
    222				     PAGE_SHIFT);
    223	if (!locked_page) {
    224		test_err("couldn't find the locked page");
    225		goto out_bits;
    226	}
    227	start = test_start;
    228	end = start + PAGE_SIZE - 1;
    229	found = find_lock_delalloc_range(inode, locked_page, &start,
    230					 &end);
    231	if (found) {
    232		test_err("found range when we shouldn't have");
    233		goto out_bits;
    234	}
    235	if (end != test_start + PAGE_SIZE - 1) {
    236		test_err("did not return the proper end offset");
    237		goto out_bits;
    238	}
    239
    240	/*
    241	 * Test this scenario
    242	 * [------- delalloc -------|
    243	 * [max_bytes]|-- search--|
    244	 *
    245	 * We are re-using our test_start from above since it works out well.
    246	 */
    247	set_extent_delalloc(tmp, max_bytes, total_dirty - 1, 0, NULL);
    248	start = test_start;
    249	end = start + PAGE_SIZE - 1;
    250	found = find_lock_delalloc_range(inode, locked_page, &start,
    251					 &end);
    252	if (!found) {
    253		test_err("didn't find our range");
    254		goto out_bits;
    255	}
    256	if (start != test_start || end != total_dirty - 1) {
    257		test_err("expected start %llu end %llu, got start %llu end %llu",
    258			 test_start, total_dirty - 1, start, end);
    259		goto out_bits;
    260	}
    261	if (process_page_range(inode, start, end,
    262			       PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
    263		test_err("pages in range were not all locked");
    264		goto out_bits;
    265	}
    266	unlock_extent(tmp, start, end);
    267
    268	/*
    269	 * Now to test where we run into a page that is no longer dirty in the
    270	 * range we want to find.
    271	 */
    272	page = find_get_page(inode->i_mapping,
    273			     (max_bytes + SZ_1M) >> PAGE_SHIFT);
    274	if (!page) {
    275		test_err("couldn't find our page");
    276		goto out_bits;
    277	}
    278	ClearPageDirty(page);
    279	put_page(page);
    280
    281	/* We unlocked it in the previous test */
    282	lock_page(locked_page);
    283	start = test_start;
    284	end = start + PAGE_SIZE - 1;
    285	/*
    286	 * Currently if we fail to find dirty pages in the delalloc range we
    287	 * will adjust max_bytes down to PAGE_SIZE and then re-search.  If
    288	 * this changes at any point in the future we will need to fix this
    289	 * tests expected behavior.
    290	 */
    291	found = find_lock_delalloc_range(inode, locked_page, &start,
    292					 &end);
    293	if (!found) {
    294		test_err("didn't find our range");
    295		goto out_bits;
    296	}
    297	if (start != test_start && end != test_start + PAGE_SIZE - 1) {
    298		test_err("expected start %llu end %llu, got start %llu end %llu",
    299			 test_start, test_start + PAGE_SIZE - 1, start, end);
    300		goto out_bits;
    301	}
    302	if (process_page_range(inode, start, end, PROCESS_TEST_LOCKED |
    303			       PROCESS_UNLOCK)) {
    304		test_err("pages in range were not all locked");
    305		goto out_bits;
    306	}
    307	ret = 0;
    308out_bits:
    309	if (ret)
    310		dump_extent_io_tree(tmp);
    311	clear_extent_bits(tmp, 0, total_dirty - 1, (unsigned)-1);
    312out:
    313	if (locked_page)
    314		put_page(locked_page);
    315	process_page_range(inode, 0, total_dirty - 1,
    316			   PROCESS_UNLOCK | PROCESS_RELEASE);
    317	iput(inode);
    318	return ret;
    319}
    320
    321static int check_eb_bitmap(unsigned long *bitmap, struct extent_buffer *eb,
    322			   unsigned long len)
    323{
    324	unsigned long i;
    325
    326	for (i = 0; i < len * BITS_PER_BYTE; i++) {
    327		int bit, bit1;
    328
    329		bit = !!test_bit(i, bitmap);
    330		bit1 = !!extent_buffer_test_bit(eb, 0, i);
    331		if (bit1 != bit) {
    332			test_err("bits do not match");
    333			return -EINVAL;
    334		}
    335
    336		bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE,
    337						i % BITS_PER_BYTE);
    338		if (bit1 != bit) {
    339			test_err("offset bits do not match");
    340			return -EINVAL;
    341		}
    342	}
    343	return 0;
    344}
    345
    346static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
    347			     unsigned long len)
    348{
    349	unsigned long i, j;
    350	u32 x;
    351	int ret;
    352
    353	memset(bitmap, 0, len);
    354	memzero_extent_buffer(eb, 0, len);
    355	if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
    356		test_err("bitmap was not zeroed");
    357		return -EINVAL;
    358	}
    359
    360	bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
    361	extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
    362	ret = check_eb_bitmap(bitmap, eb, len);
    363	if (ret) {
    364		test_err("setting all bits failed");
    365		return ret;
    366	}
    367
    368	bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
    369	extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
    370	ret = check_eb_bitmap(bitmap, eb, len);
    371	if (ret) {
    372		test_err("clearing all bits failed");
    373		return ret;
    374	}
    375
    376	/* Straddling pages test */
    377	if (len > PAGE_SIZE) {
    378		bitmap_set(bitmap,
    379			(PAGE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
    380			sizeof(long) * BITS_PER_BYTE);
    381		extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0,
    382					sizeof(long) * BITS_PER_BYTE);
    383		ret = check_eb_bitmap(bitmap, eb, len);
    384		if (ret) {
    385			test_err("setting straddling pages failed");
    386			return ret;
    387		}
    388
    389		bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
    390		bitmap_clear(bitmap,
    391			(PAGE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
    392			sizeof(long) * BITS_PER_BYTE);
    393		extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
    394		extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0,
    395					sizeof(long) * BITS_PER_BYTE);
    396		ret = check_eb_bitmap(bitmap, eb, len);
    397		if (ret) {
    398			test_err("clearing straddling pages failed");
    399			return ret;
    400		}
    401	}
    402
    403	/*
    404	 * Generate a wonky pseudo-random bit pattern for the sake of not using
    405	 * something repetitive that could miss some hypothetical off-by-n bug.
    406	 */
    407	x = 0;
    408	bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
    409	extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
    410	for (i = 0; i < len * BITS_PER_BYTE / 32; i++) {
    411		x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffU;
    412		for (j = 0; j < 32; j++) {
    413			if (x & (1U << j)) {
    414				bitmap_set(bitmap, i * 32 + j, 1);
    415				extent_buffer_bitmap_set(eb, 0, i * 32 + j, 1);
    416			}
    417		}
    418	}
    419
    420	ret = check_eb_bitmap(bitmap, eb, len);
    421	if (ret) {
    422		test_err("random bit pattern failed");
    423		return ret;
    424	}
    425
    426	return 0;
    427}
    428
    429static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
    430{
    431	struct btrfs_fs_info *fs_info;
    432	unsigned long *bitmap = NULL;
    433	struct extent_buffer *eb = NULL;
    434	int ret;
    435
    436	test_msg("running extent buffer bitmap tests");
    437
    438	fs_info = btrfs_alloc_dummy_fs_info(nodesize, sectorsize);
    439	if (!fs_info) {
    440		test_std_err(TEST_ALLOC_FS_INFO);
    441		return -ENOMEM;
    442	}
    443
    444	bitmap = kmalloc(nodesize, GFP_KERNEL);
    445	if (!bitmap) {
    446		test_err("couldn't allocate test bitmap");
    447		ret = -ENOMEM;
    448		goto out;
    449	}
    450
    451	eb = __alloc_dummy_extent_buffer(fs_info, 0, nodesize);
    452	if (!eb) {
    453		test_std_err(TEST_ALLOC_ROOT);
    454		ret = -ENOMEM;
    455		goto out;
    456	}
    457
    458	ret = __test_eb_bitmaps(bitmap, eb, nodesize);
    459	if (ret)
    460		goto out;
    461
    462	free_extent_buffer(eb);
    463
    464	/*
    465	 * Test again for case where the tree block is sectorsize aligned but
    466	 * not nodesize aligned.
    467	 */
    468	eb = __alloc_dummy_extent_buffer(fs_info, sectorsize, nodesize);
    469	if (!eb) {
    470		test_std_err(TEST_ALLOC_ROOT);
    471		ret = -ENOMEM;
    472		goto out;
    473	}
    474
    475	ret = __test_eb_bitmaps(bitmap, eb, nodesize);
    476out:
    477	free_extent_buffer(eb);
    478	kfree(bitmap);
    479	btrfs_free_dummy_fs_info(fs_info);
    480	return ret;
    481}
    482
    483static int test_find_first_clear_extent_bit(void)
    484{
    485	struct extent_io_tree tree;
    486	u64 start, end;
    487	int ret = -EINVAL;
    488
    489	test_msg("running find_first_clear_extent_bit test");
    490
    491	extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST, NULL);
    492
    493	/* Test correct handling of empty tree */
    494	find_first_clear_extent_bit(&tree, 0, &start, &end, CHUNK_TRIMMED);
    495	if (start != 0 || end != -1) {
    496		test_err(
    497	"error getting a range from completely empty tree: start %llu end %llu",
    498			 start, end);
    499		goto out;
    500	}
    501	/*
    502	 * Set 1M-4M alloc/discard and 32M-64M thus leaving a hole between
    503	 * 4M-32M
    504	 */
    505	set_extent_bits(&tree, SZ_1M, SZ_4M - 1,
    506			CHUNK_TRIMMED | CHUNK_ALLOCATED);
    507
    508	find_first_clear_extent_bit(&tree, SZ_512K, &start, &end,
    509				    CHUNK_TRIMMED | CHUNK_ALLOCATED);
    510
    511	if (start != 0 || end != SZ_1M - 1) {
    512		test_err("error finding beginning range: start %llu end %llu",
    513			 start, end);
    514		goto out;
    515	}
    516
    517	/* Now add 32M-64M so that we have a hole between 4M-32M */
    518	set_extent_bits(&tree, SZ_32M, SZ_64M - 1,
    519			CHUNK_TRIMMED | CHUNK_ALLOCATED);
    520
    521	/*
    522	 * Request first hole starting at 12M, we should get 4M-32M
    523	 */
    524	find_first_clear_extent_bit(&tree, 12 * SZ_1M, &start, &end,
    525				    CHUNK_TRIMMED | CHUNK_ALLOCATED);
    526
    527	if (start != SZ_4M || end != SZ_32M - 1) {
    528		test_err("error finding trimmed range: start %llu end %llu",
    529			 start, end);
    530		goto out;
    531	}
    532
    533	/*
    534	 * Search in the middle of allocated range, should get the next one
    535	 * available, which happens to be unallocated -> 4M-32M
    536	 */
    537	find_first_clear_extent_bit(&tree, SZ_2M, &start, &end,
    538				    CHUNK_TRIMMED | CHUNK_ALLOCATED);
    539
    540	if (start != SZ_4M || end != SZ_32M - 1) {
    541		test_err("error finding next unalloc range: start %llu end %llu",
    542			 start, end);
    543		goto out;
    544	}
    545
    546	/*
    547	 * Set 64M-72M with CHUNK_ALLOC flag, then search for CHUNK_TRIMMED flag
    548	 * being unset in this range, we should get the entry in range 64M-72M
    549	 */
    550	set_extent_bits(&tree, SZ_64M, SZ_64M + SZ_8M - 1, CHUNK_ALLOCATED);
    551	find_first_clear_extent_bit(&tree, SZ_64M + SZ_1M, &start, &end,
    552				    CHUNK_TRIMMED);
    553
    554	if (start != SZ_64M || end != SZ_64M + SZ_8M - 1) {
    555		test_err("error finding exact range: start %llu end %llu",
    556			 start, end);
    557		goto out;
    558	}
    559
    560	find_first_clear_extent_bit(&tree, SZ_64M - SZ_8M, &start, &end,
    561				    CHUNK_TRIMMED);
    562
    563	/*
    564	 * Search in the middle of set range whose immediate neighbour doesn't
    565	 * have the bits set so it must be returned
    566	 */
    567	if (start != SZ_64M || end != SZ_64M + SZ_8M - 1) {
    568		test_err("error finding next alloc range: start %llu end %llu",
    569			 start, end);
    570		goto out;
    571	}
    572
    573	/*
    574	 * Search beyond any known range, shall return after last known range
    575	 * and end should be -1
    576	 */
    577	find_first_clear_extent_bit(&tree, -1, &start, &end, CHUNK_TRIMMED);
    578	if (start != SZ_64M + SZ_8M || end != -1) {
    579		test_err(
    580		"error handling beyond end of range search: start %llu end %llu",
    581			start, end);
    582		goto out;
    583	}
    584
    585	ret = 0;
    586out:
    587	if (ret)
    588		dump_extent_io_tree(&tree);
    589	clear_extent_bits(&tree, 0, (u64)-1, CHUNK_TRIMMED | CHUNK_ALLOCATED);
    590
    591	return ret;
    592}
    593
    594int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
    595{
    596	int ret;
    597
    598	test_msg("running extent I/O tests");
    599
    600	ret = test_find_delalloc(sectorsize);
    601	if (ret)
    602		goto out;
    603
    604	ret = test_find_first_clear_extent_bit();
    605	if (ret)
    606		goto out;
    607
    608	ret = test_eb_bitmaps(sectorsize, nodesize);
    609out:
    610	return ret;
    611}