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