xref: /openbmc/linux/fs/btrfs/tests/extent-io-tests.c (revision d2ba09c1)
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 
14 #define PROCESS_UNLOCK		(1 << 0)
15 #define PROCESS_RELEASE		(1 << 1)
16 #define PROCESS_TEST_LOCKED	(1 << 2)
17 
18 static noinline int process_page_range(struct inode *inode, u64 start, u64 end,
19 				       unsigned long flags)
20 {
21 	int ret;
22 	struct page *pages[16];
23 	unsigned long index = start >> PAGE_SHIFT;
24 	unsigned long end_index = end >> PAGE_SHIFT;
25 	unsigned long nr_pages = end_index - index + 1;
26 	int i;
27 	int count = 0;
28 	int loops = 0;
29 
30 	while (nr_pages > 0) {
31 		ret = find_get_pages_contig(inode->i_mapping, index,
32 				     min_t(unsigned long, nr_pages,
33 				     ARRAY_SIZE(pages)), pages);
34 		for (i = 0; i < ret; i++) {
35 			if (flags & PROCESS_TEST_LOCKED &&
36 			    !PageLocked(pages[i]))
37 				count++;
38 			if (flags & PROCESS_UNLOCK && PageLocked(pages[i]))
39 				unlock_page(pages[i]);
40 			put_page(pages[i]);
41 			if (flags & PROCESS_RELEASE)
42 				put_page(pages[i]);
43 		}
44 		nr_pages -= ret;
45 		index += ret;
46 		cond_resched();
47 		loops++;
48 		if (loops > 100000) {
49 			printk(KERN_ERR "stuck in a loop, start %Lu, end %Lu, nr_pages %lu, ret %d\n", start, end, nr_pages, ret);
50 			break;
51 		}
52 	}
53 	return count;
54 }
55 
56 static int test_find_delalloc(u32 sectorsize)
57 {
58 	struct inode *inode;
59 	struct extent_io_tree tmp;
60 	struct page *page;
61 	struct page *locked_page = NULL;
62 	unsigned long index = 0;
63 	u64 total_dirty = SZ_256M;
64 	u64 max_bytes = SZ_128M;
65 	u64 start, end, test_start;
66 	u64 found;
67 	int ret = -EINVAL;
68 
69 	test_msg("Running find delalloc tests\n");
70 
71 	inode = btrfs_new_test_inode();
72 	if (!inode) {
73 		test_msg("Failed to allocate test inode\n");
74 		return -ENOMEM;
75 	}
76 
77 	extent_io_tree_init(&tmp, inode);
78 
79 	/*
80 	 * First go through and create and mark all of our pages dirty, we pin
81 	 * everything to make sure our pages don't get evicted and screw up our
82 	 * test.
83 	 */
84 	for (index = 0; index < (total_dirty >> PAGE_SHIFT); index++) {
85 		page = find_or_create_page(inode->i_mapping, index, GFP_KERNEL);
86 		if (!page) {
87 			test_msg("Failed to allocate test page\n");
88 			ret = -ENOMEM;
89 			goto out;
90 		}
91 		SetPageDirty(page);
92 		if (index) {
93 			unlock_page(page);
94 		} else {
95 			get_page(page);
96 			locked_page = page;
97 		}
98 	}
99 
100 	/* Test this scenario
101 	 * |--- delalloc ---|
102 	 * |---  search  ---|
103 	 */
104 	set_extent_delalloc(&tmp, 0, sectorsize - 1, 0, NULL);
105 	start = 0;
106 	end = 0;
107 	found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
108 					 &end, max_bytes);
109 	if (!found) {
110 		test_msg("Should have found at least one delalloc\n");
111 		goto out_bits;
112 	}
113 	if (start != 0 || end != (sectorsize - 1)) {
114 		test_msg("Expected start 0 end %u, got start %llu end %llu\n",
115 			sectorsize - 1, start, end);
116 		goto out_bits;
117 	}
118 	unlock_extent(&tmp, start, end);
119 	unlock_page(locked_page);
120 	put_page(locked_page);
121 
122 	/*
123 	 * Test this scenario
124 	 *
125 	 * |--- delalloc ---|
126 	 *           |--- search ---|
127 	 */
128 	test_start = SZ_64M;
129 	locked_page = find_lock_page(inode->i_mapping,
130 				     test_start >> PAGE_SHIFT);
131 	if (!locked_page) {
132 		test_msg("Couldn't find the locked page\n");
133 		goto out_bits;
134 	}
135 	set_extent_delalloc(&tmp, sectorsize, max_bytes - 1, 0, NULL);
136 	start = test_start;
137 	end = 0;
138 	found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
139 					 &end, max_bytes);
140 	if (!found) {
141 		test_msg("Couldn't find delalloc in our range\n");
142 		goto out_bits;
143 	}
144 	if (start != test_start || end != max_bytes - 1) {
145 		test_msg("Expected start %Lu end %Lu, got start %Lu, end "
146 			 "%Lu\n", test_start, max_bytes - 1, start, end);
147 		goto out_bits;
148 	}
149 	if (process_page_range(inode, start, end,
150 			       PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
151 		test_msg("There were unlocked pages in the range\n");
152 		goto out_bits;
153 	}
154 	unlock_extent(&tmp, start, end);
155 	/* locked_page was unlocked above */
156 	put_page(locked_page);
157 
158 	/*
159 	 * Test this scenario
160 	 * |--- delalloc ---|
161 	 *                    |--- search ---|
162 	 */
163 	test_start = max_bytes + sectorsize;
164 	locked_page = find_lock_page(inode->i_mapping, test_start >>
165 				     PAGE_SHIFT);
166 	if (!locked_page) {
167 		test_msg("Couldn't find the locked page\n");
168 		goto out_bits;
169 	}
170 	start = test_start;
171 	end = 0;
172 	found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
173 					 &end, max_bytes);
174 	if (found) {
175 		test_msg("Found range when we shouldn't have\n");
176 		goto out_bits;
177 	}
178 	if (end != (u64)-1) {
179 		test_msg("Did not return the proper end offset\n");
180 		goto out_bits;
181 	}
182 
183 	/*
184 	 * Test this scenario
185 	 * [------- delalloc -------|
186 	 * [max_bytes]|-- search--|
187 	 *
188 	 * We are re-using our test_start from above since it works out well.
189 	 */
190 	set_extent_delalloc(&tmp, max_bytes, total_dirty - 1, 0, NULL);
191 	start = test_start;
192 	end = 0;
193 	found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
194 					 &end, max_bytes);
195 	if (!found) {
196 		test_msg("Didn't find our range\n");
197 		goto out_bits;
198 	}
199 	if (start != test_start || end != total_dirty - 1) {
200 		test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
201 			 test_start, total_dirty - 1, start, end);
202 		goto out_bits;
203 	}
204 	if (process_page_range(inode, start, end,
205 			       PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) {
206 		test_msg("Pages in range were not all locked\n");
207 		goto out_bits;
208 	}
209 	unlock_extent(&tmp, start, end);
210 
211 	/*
212 	 * Now to test where we run into a page that is no longer dirty in the
213 	 * range we want to find.
214 	 */
215 	page = find_get_page(inode->i_mapping,
216 			     (max_bytes + SZ_1M) >> PAGE_SHIFT);
217 	if (!page) {
218 		test_msg("Couldn't find our page\n");
219 		goto out_bits;
220 	}
221 	ClearPageDirty(page);
222 	put_page(page);
223 
224 	/* We unlocked it in the previous test */
225 	lock_page(locked_page);
226 	start = test_start;
227 	end = 0;
228 	/*
229 	 * Currently if we fail to find dirty pages in the delalloc range we
230 	 * will adjust max_bytes down to PAGE_SIZE and then re-search.  If
231 	 * this changes at any point in the future we will need to fix this
232 	 * tests expected behavior.
233 	 */
234 	found = find_lock_delalloc_range(inode, &tmp, locked_page, &start,
235 					 &end, max_bytes);
236 	if (!found) {
237 		test_msg("Didn't find our range\n");
238 		goto out_bits;
239 	}
240 	if (start != test_start && end != test_start + PAGE_SIZE - 1) {
241 		test_msg("Expected start %Lu end %Lu, got start %Lu end %Lu\n",
242 			 test_start, test_start + PAGE_SIZE - 1, start,
243 			 end);
244 		goto out_bits;
245 	}
246 	if (process_page_range(inode, start, end, PROCESS_TEST_LOCKED |
247 			       PROCESS_UNLOCK)) {
248 		test_msg("Pages in range were not all locked\n");
249 		goto out_bits;
250 	}
251 	ret = 0;
252 out_bits:
253 	clear_extent_bits(&tmp, 0, total_dirty - 1, (unsigned)-1);
254 out:
255 	if (locked_page)
256 		put_page(locked_page);
257 	process_page_range(inode, 0, total_dirty - 1,
258 			   PROCESS_UNLOCK | PROCESS_RELEASE);
259 	iput(inode);
260 	return ret;
261 }
262 
263 static int check_eb_bitmap(unsigned long *bitmap, struct extent_buffer *eb,
264 			   unsigned long len)
265 {
266 	unsigned long i;
267 
268 	for (i = 0; i < len * BITS_PER_BYTE; i++) {
269 		int bit, bit1;
270 
271 		bit = !!test_bit(i, bitmap);
272 		bit1 = !!extent_buffer_test_bit(eb, 0, i);
273 		if (bit1 != bit) {
274 			test_msg("Bits do not match\n");
275 			return -EINVAL;
276 		}
277 
278 		bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE,
279 						i % BITS_PER_BYTE);
280 		if (bit1 != bit) {
281 			test_msg("Offset bits do not match\n");
282 			return -EINVAL;
283 		}
284 	}
285 	return 0;
286 }
287 
288 static int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb,
289 			     unsigned long len)
290 {
291 	unsigned long i, j;
292 	u32 x;
293 	int ret;
294 
295 	memset(bitmap, 0, len);
296 	memzero_extent_buffer(eb, 0, len);
297 	if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) {
298 		test_msg("Bitmap was not zeroed\n");
299 		return -EINVAL;
300 	}
301 
302 	bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
303 	extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
304 	ret = check_eb_bitmap(bitmap, eb, len);
305 	if (ret) {
306 		test_msg("Setting all bits failed\n");
307 		return ret;
308 	}
309 
310 	bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
311 	extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
312 	ret = check_eb_bitmap(bitmap, eb, len);
313 	if (ret) {
314 		test_msg("Clearing all bits failed\n");
315 		return ret;
316 	}
317 
318 	/* Straddling pages test */
319 	if (len > PAGE_SIZE) {
320 		bitmap_set(bitmap,
321 			(PAGE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
322 			sizeof(long) * BITS_PER_BYTE);
323 		extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0,
324 					sizeof(long) * BITS_PER_BYTE);
325 		ret = check_eb_bitmap(bitmap, eb, len);
326 		if (ret) {
327 			test_msg("Setting straddling pages failed\n");
328 			return ret;
329 		}
330 
331 		bitmap_set(bitmap, 0, len * BITS_PER_BYTE);
332 		bitmap_clear(bitmap,
333 			(PAGE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE,
334 			sizeof(long) * BITS_PER_BYTE);
335 		extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE);
336 		extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0,
337 					sizeof(long) * BITS_PER_BYTE);
338 		ret = check_eb_bitmap(bitmap, eb, len);
339 		if (ret) {
340 			test_msg("Clearing straddling pages failed\n");
341 			return ret;
342 		}
343 	}
344 
345 	/*
346 	 * Generate a wonky pseudo-random bit pattern for the sake of not using
347 	 * something repetitive that could miss some hypothetical off-by-n bug.
348 	 */
349 	x = 0;
350 	bitmap_clear(bitmap, 0, len * BITS_PER_BYTE);
351 	extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE);
352 	for (i = 0; i < len * BITS_PER_BYTE / 32; i++) {
353 		x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffU;
354 		for (j = 0; j < 32; j++) {
355 			if (x & (1U << j)) {
356 				bitmap_set(bitmap, i * 32 + j, 1);
357 				extent_buffer_bitmap_set(eb, 0, i * 32 + j, 1);
358 			}
359 		}
360 	}
361 
362 	ret = check_eb_bitmap(bitmap, eb, len);
363 	if (ret) {
364 		test_msg("Random bit pattern failed\n");
365 		return ret;
366 	}
367 
368 	return 0;
369 }
370 
371 static int test_eb_bitmaps(u32 sectorsize, u32 nodesize)
372 {
373 	struct btrfs_fs_info *fs_info;
374 	unsigned long len;
375 	unsigned long *bitmap;
376 	struct extent_buffer *eb;
377 	int ret;
378 
379 	test_msg("Running extent buffer bitmap tests\n");
380 
381 	/*
382 	 * In ppc64, sectorsize can be 64K, thus 4 * 64K will be larger than
383 	 * BTRFS_MAX_METADATA_BLOCKSIZE.
384 	 */
385 	len = (sectorsize < BTRFS_MAX_METADATA_BLOCKSIZE)
386 		? sectorsize * 4 : sectorsize;
387 
388 	fs_info = btrfs_alloc_dummy_fs_info(len, len);
389 
390 	bitmap = kmalloc(len, GFP_KERNEL);
391 	if (!bitmap) {
392 		test_msg("Couldn't allocate test bitmap\n");
393 		return -ENOMEM;
394 	}
395 
396 	eb = __alloc_dummy_extent_buffer(fs_info, 0, len);
397 	if (!eb) {
398 		test_msg("Couldn't allocate test extent buffer\n");
399 		kfree(bitmap);
400 		return -ENOMEM;
401 	}
402 
403 	ret = __test_eb_bitmaps(bitmap, eb, len);
404 	if (ret)
405 		goto out;
406 
407 	/* Do it over again with an extent buffer which isn't page-aligned. */
408 	free_extent_buffer(eb);
409 	eb = __alloc_dummy_extent_buffer(NULL, nodesize / 2, len);
410 	if (!eb) {
411 		test_msg("Couldn't allocate test extent buffer\n");
412 		kfree(bitmap);
413 		return -ENOMEM;
414 	}
415 
416 	ret = __test_eb_bitmaps(bitmap, eb, len);
417 out:
418 	free_extent_buffer(eb);
419 	kfree(bitmap);
420 	return ret;
421 }
422 
423 int btrfs_test_extent_io(u32 sectorsize, u32 nodesize)
424 {
425 	int ret;
426 
427 	test_msg("Running extent I/O tests\n");
428 
429 	ret = test_find_delalloc(sectorsize);
430 	if (ret)
431 		goto out;
432 
433 	ret = test_eb_bitmaps(sectorsize, nodesize);
434 out:
435 	test_msg("Extent I/O tests finished\n");
436 	return ret;
437 }
438