18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (C) 2013 Fusion IO. All rights reserved. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include <linux/pagemap.h> 78c2ecf20Sopenharmony_ci#include <linux/sched.h> 88c2ecf20Sopenharmony_ci#include <linux/slab.h> 98c2ecf20Sopenharmony_ci#include <linux/sizes.h> 108c2ecf20Sopenharmony_ci#include "btrfs-tests.h" 118c2ecf20Sopenharmony_ci#include "../ctree.h" 128c2ecf20Sopenharmony_ci#include "../extent_io.h" 138c2ecf20Sopenharmony_ci#include "../btrfs_inode.h" 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_ci#define PROCESS_UNLOCK (1 << 0) 168c2ecf20Sopenharmony_ci#define PROCESS_RELEASE (1 << 1) 178c2ecf20Sopenharmony_ci#define PROCESS_TEST_LOCKED (1 << 2) 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_cistatic noinline int process_page_range(struct inode *inode, u64 start, u64 end, 208c2ecf20Sopenharmony_ci unsigned long flags) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci int ret; 238c2ecf20Sopenharmony_ci struct page *pages[16]; 248c2ecf20Sopenharmony_ci unsigned long index = start >> PAGE_SHIFT; 258c2ecf20Sopenharmony_ci unsigned long end_index = end >> PAGE_SHIFT; 268c2ecf20Sopenharmony_ci unsigned long nr_pages = end_index - index + 1; 278c2ecf20Sopenharmony_ci int i; 288c2ecf20Sopenharmony_ci int count = 0; 298c2ecf20Sopenharmony_ci int loops = 0; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci while (nr_pages > 0) { 328c2ecf20Sopenharmony_ci ret = find_get_pages_contig(inode->i_mapping, index, 338c2ecf20Sopenharmony_ci min_t(unsigned long, nr_pages, 348c2ecf20Sopenharmony_ci ARRAY_SIZE(pages)), pages); 358c2ecf20Sopenharmony_ci for (i = 0; i < ret; i++) { 368c2ecf20Sopenharmony_ci if (flags & PROCESS_TEST_LOCKED && 378c2ecf20Sopenharmony_ci !PageLocked(pages[i])) 388c2ecf20Sopenharmony_ci count++; 398c2ecf20Sopenharmony_ci if (flags & PROCESS_UNLOCK && PageLocked(pages[i])) 408c2ecf20Sopenharmony_ci unlock_page(pages[i]); 418c2ecf20Sopenharmony_ci put_page(pages[i]); 428c2ecf20Sopenharmony_ci if (flags & PROCESS_RELEASE) 438c2ecf20Sopenharmony_ci put_page(pages[i]); 448c2ecf20Sopenharmony_ci } 458c2ecf20Sopenharmony_ci nr_pages -= ret; 468c2ecf20Sopenharmony_ci index += ret; 478c2ecf20Sopenharmony_ci cond_resched(); 488c2ecf20Sopenharmony_ci loops++; 498c2ecf20Sopenharmony_ci if (loops > 100000) { 508c2ecf20Sopenharmony_ci printk(KERN_ERR 518c2ecf20Sopenharmony_ci "stuck in a loop, start %llu, end %llu, nr_pages %lu, ret %d\n", 528c2ecf20Sopenharmony_ci start, end, nr_pages, ret); 538c2ecf20Sopenharmony_ci break; 548c2ecf20Sopenharmony_ci } 558c2ecf20Sopenharmony_ci } 568c2ecf20Sopenharmony_ci return count; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int test_find_delalloc(u32 sectorsize) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct inode *inode; 628c2ecf20Sopenharmony_ci struct extent_io_tree *tmp; 638c2ecf20Sopenharmony_ci struct page *page; 648c2ecf20Sopenharmony_ci struct page *locked_page = NULL; 658c2ecf20Sopenharmony_ci unsigned long index = 0; 668c2ecf20Sopenharmony_ci /* In this test we need at least 2 file extents at its maximum size */ 678c2ecf20Sopenharmony_ci u64 max_bytes = BTRFS_MAX_EXTENT_SIZE; 688c2ecf20Sopenharmony_ci u64 total_dirty = 2 * max_bytes; 698c2ecf20Sopenharmony_ci u64 start, end, test_start; 708c2ecf20Sopenharmony_ci bool found; 718c2ecf20Sopenharmony_ci int ret = -EINVAL; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci test_msg("running find delalloc tests"); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci inode = btrfs_new_test_inode(); 768c2ecf20Sopenharmony_ci if (!inode) { 778c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_INODE); 788c2ecf20Sopenharmony_ci return -ENOMEM; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci tmp = &BTRFS_I(inode)->io_tree; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci /* 838c2ecf20Sopenharmony_ci * Passing NULL as we don't have fs_info but tracepoints are not used 848c2ecf20Sopenharmony_ci * at this point 858c2ecf20Sopenharmony_ci */ 868c2ecf20Sopenharmony_ci extent_io_tree_init(NULL, tmp, IO_TREE_SELFTEST, NULL); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci /* 898c2ecf20Sopenharmony_ci * First go through and create and mark all of our pages dirty, we pin 908c2ecf20Sopenharmony_ci * everything to make sure our pages don't get evicted and screw up our 918c2ecf20Sopenharmony_ci * test. 928c2ecf20Sopenharmony_ci */ 938c2ecf20Sopenharmony_ci for (index = 0; index < (total_dirty >> PAGE_SHIFT); index++) { 948c2ecf20Sopenharmony_ci page = find_or_create_page(inode->i_mapping, index, GFP_KERNEL); 958c2ecf20Sopenharmony_ci if (!page) { 968c2ecf20Sopenharmony_ci test_err("failed to allocate test page"); 978c2ecf20Sopenharmony_ci ret = -ENOMEM; 988c2ecf20Sopenharmony_ci goto out; 998c2ecf20Sopenharmony_ci } 1008c2ecf20Sopenharmony_ci SetPageDirty(page); 1018c2ecf20Sopenharmony_ci if (index) { 1028c2ecf20Sopenharmony_ci unlock_page(page); 1038c2ecf20Sopenharmony_ci } else { 1048c2ecf20Sopenharmony_ci get_page(page); 1058c2ecf20Sopenharmony_ci locked_page = page; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci /* Test this scenario 1108c2ecf20Sopenharmony_ci * |--- delalloc ---| 1118c2ecf20Sopenharmony_ci * |--- search ---| 1128c2ecf20Sopenharmony_ci */ 1138c2ecf20Sopenharmony_ci set_extent_delalloc(tmp, 0, sectorsize - 1, 0, NULL); 1148c2ecf20Sopenharmony_ci start = 0; 1158c2ecf20Sopenharmony_ci end = 0; 1168c2ecf20Sopenharmony_ci found = find_lock_delalloc_range(inode, locked_page, &start, 1178c2ecf20Sopenharmony_ci &end); 1188c2ecf20Sopenharmony_ci if (!found) { 1198c2ecf20Sopenharmony_ci test_err("should have found at least one delalloc"); 1208c2ecf20Sopenharmony_ci goto out_bits; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci if (start != 0 || end != (sectorsize - 1)) { 1238c2ecf20Sopenharmony_ci test_err("expected start 0 end %u, got start %llu end %llu", 1248c2ecf20Sopenharmony_ci sectorsize - 1, start, end); 1258c2ecf20Sopenharmony_ci goto out_bits; 1268c2ecf20Sopenharmony_ci } 1278c2ecf20Sopenharmony_ci unlock_extent(tmp, start, end); 1288c2ecf20Sopenharmony_ci unlock_page(locked_page); 1298c2ecf20Sopenharmony_ci put_page(locked_page); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* 1328c2ecf20Sopenharmony_ci * Test this scenario 1338c2ecf20Sopenharmony_ci * 1348c2ecf20Sopenharmony_ci * |--- delalloc ---| 1358c2ecf20Sopenharmony_ci * |--- search ---| 1368c2ecf20Sopenharmony_ci */ 1378c2ecf20Sopenharmony_ci test_start = SZ_64M; 1388c2ecf20Sopenharmony_ci locked_page = find_lock_page(inode->i_mapping, 1398c2ecf20Sopenharmony_ci test_start >> PAGE_SHIFT); 1408c2ecf20Sopenharmony_ci if (!locked_page) { 1418c2ecf20Sopenharmony_ci test_err("couldn't find the locked page"); 1428c2ecf20Sopenharmony_ci goto out_bits; 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci set_extent_delalloc(tmp, sectorsize, max_bytes - 1, 0, NULL); 1458c2ecf20Sopenharmony_ci start = test_start; 1468c2ecf20Sopenharmony_ci end = 0; 1478c2ecf20Sopenharmony_ci found = find_lock_delalloc_range(inode, locked_page, &start, 1488c2ecf20Sopenharmony_ci &end); 1498c2ecf20Sopenharmony_ci if (!found) { 1508c2ecf20Sopenharmony_ci test_err("couldn't find delalloc in our range"); 1518c2ecf20Sopenharmony_ci goto out_bits; 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci if (start != test_start || end != max_bytes - 1) { 1548c2ecf20Sopenharmony_ci test_err("expected start %llu end %llu, got start %llu, end %llu", 1558c2ecf20Sopenharmony_ci test_start, max_bytes - 1, start, end); 1568c2ecf20Sopenharmony_ci goto out_bits; 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci if (process_page_range(inode, start, end, 1598c2ecf20Sopenharmony_ci PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) { 1608c2ecf20Sopenharmony_ci test_err("there were unlocked pages in the range"); 1618c2ecf20Sopenharmony_ci goto out_bits; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci unlock_extent(tmp, start, end); 1648c2ecf20Sopenharmony_ci /* locked_page was unlocked above */ 1658c2ecf20Sopenharmony_ci put_page(locked_page); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* 1688c2ecf20Sopenharmony_ci * Test this scenario 1698c2ecf20Sopenharmony_ci * |--- delalloc ---| 1708c2ecf20Sopenharmony_ci * |--- search ---| 1718c2ecf20Sopenharmony_ci */ 1728c2ecf20Sopenharmony_ci test_start = max_bytes + sectorsize; 1738c2ecf20Sopenharmony_ci locked_page = find_lock_page(inode->i_mapping, test_start >> 1748c2ecf20Sopenharmony_ci PAGE_SHIFT); 1758c2ecf20Sopenharmony_ci if (!locked_page) { 1768c2ecf20Sopenharmony_ci test_err("couldn't find the locked page"); 1778c2ecf20Sopenharmony_ci goto out_bits; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci start = test_start; 1808c2ecf20Sopenharmony_ci end = 0; 1818c2ecf20Sopenharmony_ci found = find_lock_delalloc_range(inode, locked_page, &start, 1828c2ecf20Sopenharmony_ci &end); 1838c2ecf20Sopenharmony_ci if (found) { 1848c2ecf20Sopenharmony_ci test_err("found range when we shouldn't have"); 1858c2ecf20Sopenharmony_ci goto out_bits; 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci if (end != (u64)-1) { 1888c2ecf20Sopenharmony_ci test_err("did not return the proper end offset"); 1898c2ecf20Sopenharmony_ci goto out_bits; 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci /* 1938c2ecf20Sopenharmony_ci * Test this scenario 1948c2ecf20Sopenharmony_ci * [------- delalloc -------| 1958c2ecf20Sopenharmony_ci * [max_bytes]|-- search--| 1968c2ecf20Sopenharmony_ci * 1978c2ecf20Sopenharmony_ci * We are re-using our test_start from above since it works out well. 1988c2ecf20Sopenharmony_ci */ 1998c2ecf20Sopenharmony_ci set_extent_delalloc(tmp, max_bytes, total_dirty - 1, 0, NULL); 2008c2ecf20Sopenharmony_ci start = test_start; 2018c2ecf20Sopenharmony_ci end = 0; 2028c2ecf20Sopenharmony_ci found = find_lock_delalloc_range(inode, locked_page, &start, 2038c2ecf20Sopenharmony_ci &end); 2048c2ecf20Sopenharmony_ci if (!found) { 2058c2ecf20Sopenharmony_ci test_err("didn't find our range"); 2068c2ecf20Sopenharmony_ci goto out_bits; 2078c2ecf20Sopenharmony_ci } 2088c2ecf20Sopenharmony_ci if (start != test_start || end != total_dirty - 1) { 2098c2ecf20Sopenharmony_ci test_err("expected start %llu end %llu, got start %llu end %llu", 2108c2ecf20Sopenharmony_ci test_start, total_dirty - 1, start, end); 2118c2ecf20Sopenharmony_ci goto out_bits; 2128c2ecf20Sopenharmony_ci } 2138c2ecf20Sopenharmony_ci if (process_page_range(inode, start, end, 2148c2ecf20Sopenharmony_ci PROCESS_TEST_LOCKED | PROCESS_UNLOCK)) { 2158c2ecf20Sopenharmony_ci test_err("pages in range were not all locked"); 2168c2ecf20Sopenharmony_ci goto out_bits; 2178c2ecf20Sopenharmony_ci } 2188c2ecf20Sopenharmony_ci unlock_extent(tmp, start, end); 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci /* 2218c2ecf20Sopenharmony_ci * Now to test where we run into a page that is no longer dirty in the 2228c2ecf20Sopenharmony_ci * range we want to find. 2238c2ecf20Sopenharmony_ci */ 2248c2ecf20Sopenharmony_ci page = find_get_page(inode->i_mapping, 2258c2ecf20Sopenharmony_ci (max_bytes + SZ_1M) >> PAGE_SHIFT); 2268c2ecf20Sopenharmony_ci if (!page) { 2278c2ecf20Sopenharmony_ci test_err("couldn't find our page"); 2288c2ecf20Sopenharmony_ci goto out_bits; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci ClearPageDirty(page); 2318c2ecf20Sopenharmony_ci put_page(page); 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci /* We unlocked it in the previous test */ 2348c2ecf20Sopenharmony_ci lock_page(locked_page); 2358c2ecf20Sopenharmony_ci start = test_start; 2368c2ecf20Sopenharmony_ci end = 0; 2378c2ecf20Sopenharmony_ci /* 2388c2ecf20Sopenharmony_ci * Currently if we fail to find dirty pages in the delalloc range we 2398c2ecf20Sopenharmony_ci * will adjust max_bytes down to PAGE_SIZE and then re-search. If 2408c2ecf20Sopenharmony_ci * this changes at any point in the future we will need to fix this 2418c2ecf20Sopenharmony_ci * tests expected behavior. 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci found = find_lock_delalloc_range(inode, locked_page, &start, 2448c2ecf20Sopenharmony_ci &end); 2458c2ecf20Sopenharmony_ci if (!found) { 2468c2ecf20Sopenharmony_ci test_err("didn't find our range"); 2478c2ecf20Sopenharmony_ci goto out_bits; 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci if (start != test_start && end != test_start + PAGE_SIZE - 1) { 2508c2ecf20Sopenharmony_ci test_err("expected start %llu end %llu, got start %llu end %llu", 2518c2ecf20Sopenharmony_ci test_start, test_start + PAGE_SIZE - 1, start, end); 2528c2ecf20Sopenharmony_ci goto out_bits; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci if (process_page_range(inode, start, end, PROCESS_TEST_LOCKED | 2558c2ecf20Sopenharmony_ci PROCESS_UNLOCK)) { 2568c2ecf20Sopenharmony_ci test_err("pages in range were not all locked"); 2578c2ecf20Sopenharmony_ci goto out_bits; 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci ret = 0; 2608c2ecf20Sopenharmony_ciout_bits: 2618c2ecf20Sopenharmony_ci clear_extent_bits(tmp, 0, total_dirty - 1, (unsigned)-1); 2628c2ecf20Sopenharmony_ciout: 2638c2ecf20Sopenharmony_ci if (locked_page) 2648c2ecf20Sopenharmony_ci put_page(locked_page); 2658c2ecf20Sopenharmony_ci process_page_range(inode, 0, total_dirty - 1, 2668c2ecf20Sopenharmony_ci PROCESS_UNLOCK | PROCESS_RELEASE); 2678c2ecf20Sopenharmony_ci iput(inode); 2688c2ecf20Sopenharmony_ci return ret; 2698c2ecf20Sopenharmony_ci} 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_cistatic int check_eb_bitmap(unsigned long *bitmap, struct extent_buffer *eb, 2728c2ecf20Sopenharmony_ci unsigned long len) 2738c2ecf20Sopenharmony_ci{ 2748c2ecf20Sopenharmony_ci unsigned long i; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci for (i = 0; i < len * BITS_PER_BYTE; i++) { 2778c2ecf20Sopenharmony_ci int bit, bit1; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci bit = !!test_bit(i, bitmap); 2808c2ecf20Sopenharmony_ci bit1 = !!extent_buffer_test_bit(eb, 0, i); 2818c2ecf20Sopenharmony_ci if (bit1 != bit) { 2828c2ecf20Sopenharmony_ci test_err("bits do not match"); 2838c2ecf20Sopenharmony_ci return -EINVAL; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci bit1 = !!extent_buffer_test_bit(eb, i / BITS_PER_BYTE, 2878c2ecf20Sopenharmony_ci i % BITS_PER_BYTE); 2888c2ecf20Sopenharmony_ci if (bit1 != bit) { 2898c2ecf20Sopenharmony_ci test_err("offset bits do not match"); 2908c2ecf20Sopenharmony_ci return -EINVAL; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci return 0; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int __test_eb_bitmaps(unsigned long *bitmap, struct extent_buffer *eb, 2978c2ecf20Sopenharmony_ci unsigned long len) 2988c2ecf20Sopenharmony_ci{ 2998c2ecf20Sopenharmony_ci unsigned long i, j; 3008c2ecf20Sopenharmony_ci u32 x; 3018c2ecf20Sopenharmony_ci int ret; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci memset(bitmap, 0, len); 3048c2ecf20Sopenharmony_ci memzero_extent_buffer(eb, 0, len); 3058c2ecf20Sopenharmony_ci if (memcmp_extent_buffer(eb, bitmap, 0, len) != 0) { 3068c2ecf20Sopenharmony_ci test_err("bitmap was not zeroed"); 3078c2ecf20Sopenharmony_ci return -EINVAL; 3088c2ecf20Sopenharmony_ci } 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci bitmap_set(bitmap, 0, len * BITS_PER_BYTE); 3118c2ecf20Sopenharmony_ci extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); 3128c2ecf20Sopenharmony_ci ret = check_eb_bitmap(bitmap, eb, len); 3138c2ecf20Sopenharmony_ci if (ret) { 3148c2ecf20Sopenharmony_ci test_err("setting all bits failed"); 3158c2ecf20Sopenharmony_ci return ret; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci bitmap_clear(bitmap, 0, len * BITS_PER_BYTE); 3198c2ecf20Sopenharmony_ci extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE); 3208c2ecf20Sopenharmony_ci ret = check_eb_bitmap(bitmap, eb, len); 3218c2ecf20Sopenharmony_ci if (ret) { 3228c2ecf20Sopenharmony_ci test_err("clearing all bits failed"); 3238c2ecf20Sopenharmony_ci return ret; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Straddling pages test */ 3278c2ecf20Sopenharmony_ci if (len > PAGE_SIZE) { 3288c2ecf20Sopenharmony_ci bitmap_set(bitmap, 3298c2ecf20Sopenharmony_ci (PAGE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE, 3308c2ecf20Sopenharmony_ci sizeof(long) * BITS_PER_BYTE); 3318c2ecf20Sopenharmony_ci extent_buffer_bitmap_set(eb, PAGE_SIZE - sizeof(long) / 2, 0, 3328c2ecf20Sopenharmony_ci sizeof(long) * BITS_PER_BYTE); 3338c2ecf20Sopenharmony_ci ret = check_eb_bitmap(bitmap, eb, len); 3348c2ecf20Sopenharmony_ci if (ret) { 3358c2ecf20Sopenharmony_ci test_err("setting straddling pages failed"); 3368c2ecf20Sopenharmony_ci return ret; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci bitmap_set(bitmap, 0, len * BITS_PER_BYTE); 3408c2ecf20Sopenharmony_ci bitmap_clear(bitmap, 3418c2ecf20Sopenharmony_ci (PAGE_SIZE - sizeof(long) / 2) * BITS_PER_BYTE, 3428c2ecf20Sopenharmony_ci sizeof(long) * BITS_PER_BYTE); 3438c2ecf20Sopenharmony_ci extent_buffer_bitmap_set(eb, 0, 0, len * BITS_PER_BYTE); 3448c2ecf20Sopenharmony_ci extent_buffer_bitmap_clear(eb, PAGE_SIZE - sizeof(long) / 2, 0, 3458c2ecf20Sopenharmony_ci sizeof(long) * BITS_PER_BYTE); 3468c2ecf20Sopenharmony_ci ret = check_eb_bitmap(bitmap, eb, len); 3478c2ecf20Sopenharmony_ci if (ret) { 3488c2ecf20Sopenharmony_ci test_err("clearing straddling pages failed"); 3498c2ecf20Sopenharmony_ci return ret; 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci } 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * Generate a wonky pseudo-random bit pattern for the sake of not using 3558c2ecf20Sopenharmony_ci * something repetitive that could miss some hypothetical off-by-n bug. 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci x = 0; 3588c2ecf20Sopenharmony_ci bitmap_clear(bitmap, 0, len * BITS_PER_BYTE); 3598c2ecf20Sopenharmony_ci extent_buffer_bitmap_clear(eb, 0, 0, len * BITS_PER_BYTE); 3608c2ecf20Sopenharmony_ci for (i = 0; i < len * BITS_PER_BYTE / 32; i++) { 3618c2ecf20Sopenharmony_ci x = (0x19660dULL * (u64)x + 0x3c6ef35fULL) & 0xffffffffU; 3628c2ecf20Sopenharmony_ci for (j = 0; j < 32; j++) { 3638c2ecf20Sopenharmony_ci if (x & (1U << j)) { 3648c2ecf20Sopenharmony_ci bitmap_set(bitmap, i * 32 + j, 1); 3658c2ecf20Sopenharmony_ci extent_buffer_bitmap_set(eb, 0, i * 32 + j, 1); 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci } 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ret = check_eb_bitmap(bitmap, eb, len); 3718c2ecf20Sopenharmony_ci if (ret) { 3728c2ecf20Sopenharmony_ci test_err("random bit pattern failed"); 3738c2ecf20Sopenharmony_ci return ret; 3748c2ecf20Sopenharmony_ci } 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci return 0; 3778c2ecf20Sopenharmony_ci} 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_cistatic int test_eb_bitmaps(u32 sectorsize, u32 nodesize) 3808c2ecf20Sopenharmony_ci{ 3818c2ecf20Sopenharmony_ci struct btrfs_fs_info *fs_info; 3828c2ecf20Sopenharmony_ci unsigned long len; 3838c2ecf20Sopenharmony_ci unsigned long *bitmap = NULL; 3848c2ecf20Sopenharmony_ci struct extent_buffer *eb = NULL; 3858c2ecf20Sopenharmony_ci int ret; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci test_msg("running extent buffer bitmap tests"); 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci /* 3908c2ecf20Sopenharmony_ci * In ppc64, sectorsize can be 64K, thus 4 * 64K will be larger than 3918c2ecf20Sopenharmony_ci * BTRFS_MAX_METADATA_BLOCKSIZE. 3928c2ecf20Sopenharmony_ci */ 3938c2ecf20Sopenharmony_ci len = (sectorsize < BTRFS_MAX_METADATA_BLOCKSIZE) 3948c2ecf20Sopenharmony_ci ? sectorsize * 4 : sectorsize; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci fs_info = btrfs_alloc_dummy_fs_info(len, len); 3978c2ecf20Sopenharmony_ci if (!fs_info) { 3988c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_FS_INFO); 3998c2ecf20Sopenharmony_ci return -ENOMEM; 4008c2ecf20Sopenharmony_ci } 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci bitmap = kmalloc(len, GFP_KERNEL); 4038c2ecf20Sopenharmony_ci if (!bitmap) { 4048c2ecf20Sopenharmony_ci test_err("couldn't allocate test bitmap"); 4058c2ecf20Sopenharmony_ci ret = -ENOMEM; 4068c2ecf20Sopenharmony_ci goto out; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci eb = __alloc_dummy_extent_buffer(fs_info, 0, len); 4108c2ecf20Sopenharmony_ci if (!eb) { 4118c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 4128c2ecf20Sopenharmony_ci ret = -ENOMEM; 4138c2ecf20Sopenharmony_ci goto out; 4148c2ecf20Sopenharmony_ci } 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci ret = __test_eb_bitmaps(bitmap, eb, len); 4178c2ecf20Sopenharmony_ci if (ret) 4188c2ecf20Sopenharmony_ci goto out; 4198c2ecf20Sopenharmony_ci 4208c2ecf20Sopenharmony_ci /* Do it over again with an extent buffer which isn't page-aligned. */ 4218c2ecf20Sopenharmony_ci free_extent_buffer(eb); 4228c2ecf20Sopenharmony_ci eb = __alloc_dummy_extent_buffer(fs_info, nodesize / 2, len); 4238c2ecf20Sopenharmony_ci if (!eb) { 4248c2ecf20Sopenharmony_ci test_std_err(TEST_ALLOC_ROOT); 4258c2ecf20Sopenharmony_ci ret = -ENOMEM; 4268c2ecf20Sopenharmony_ci goto out; 4278c2ecf20Sopenharmony_ci } 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci ret = __test_eb_bitmaps(bitmap, eb, len); 4308c2ecf20Sopenharmony_ciout: 4318c2ecf20Sopenharmony_ci free_extent_buffer(eb); 4328c2ecf20Sopenharmony_ci kfree(bitmap); 4338c2ecf20Sopenharmony_ci btrfs_free_dummy_fs_info(fs_info); 4348c2ecf20Sopenharmony_ci return ret; 4358c2ecf20Sopenharmony_ci} 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_cistatic int test_find_first_clear_extent_bit(void) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct extent_io_tree tree; 4408c2ecf20Sopenharmony_ci u64 start, end; 4418c2ecf20Sopenharmony_ci int ret = -EINVAL; 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci test_msg("running find_first_clear_extent_bit test"); 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci extent_io_tree_init(NULL, &tree, IO_TREE_SELFTEST, NULL); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* Test correct handling of empty tree */ 4488c2ecf20Sopenharmony_ci find_first_clear_extent_bit(&tree, 0, &start, &end, CHUNK_TRIMMED); 4498c2ecf20Sopenharmony_ci if (start != 0 || end != -1) { 4508c2ecf20Sopenharmony_ci test_err( 4518c2ecf20Sopenharmony_ci "error getting a range from completely empty tree: start %llu end %llu", 4528c2ecf20Sopenharmony_ci start, end); 4538c2ecf20Sopenharmony_ci goto out; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci /* 4568c2ecf20Sopenharmony_ci * Set 1M-4M alloc/discard and 32M-64M thus leaving a hole between 4578c2ecf20Sopenharmony_ci * 4M-32M 4588c2ecf20Sopenharmony_ci */ 4598c2ecf20Sopenharmony_ci set_extent_bits(&tree, SZ_1M, SZ_4M - 1, 4608c2ecf20Sopenharmony_ci CHUNK_TRIMMED | CHUNK_ALLOCATED); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci find_first_clear_extent_bit(&tree, SZ_512K, &start, &end, 4638c2ecf20Sopenharmony_ci CHUNK_TRIMMED | CHUNK_ALLOCATED); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci if (start != 0 || end != SZ_1M - 1) { 4668c2ecf20Sopenharmony_ci test_err("error finding beginning range: start %llu end %llu", 4678c2ecf20Sopenharmony_ci start, end); 4688c2ecf20Sopenharmony_ci goto out; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci /* Now add 32M-64M so that we have a hole between 4M-32M */ 4728c2ecf20Sopenharmony_ci set_extent_bits(&tree, SZ_32M, SZ_64M - 1, 4738c2ecf20Sopenharmony_ci CHUNK_TRIMMED | CHUNK_ALLOCATED); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* 4768c2ecf20Sopenharmony_ci * Request first hole starting at 12M, we should get 4M-32M 4778c2ecf20Sopenharmony_ci */ 4788c2ecf20Sopenharmony_ci find_first_clear_extent_bit(&tree, 12 * SZ_1M, &start, &end, 4798c2ecf20Sopenharmony_ci CHUNK_TRIMMED | CHUNK_ALLOCATED); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (start != SZ_4M || end != SZ_32M - 1) { 4828c2ecf20Sopenharmony_ci test_err("error finding trimmed range: start %llu end %llu", 4838c2ecf20Sopenharmony_ci start, end); 4848c2ecf20Sopenharmony_ci goto out; 4858c2ecf20Sopenharmony_ci } 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci /* 4888c2ecf20Sopenharmony_ci * Search in the middle of allocated range, should get the next one 4898c2ecf20Sopenharmony_ci * available, which happens to be unallocated -> 4M-32M 4908c2ecf20Sopenharmony_ci */ 4918c2ecf20Sopenharmony_ci find_first_clear_extent_bit(&tree, SZ_2M, &start, &end, 4928c2ecf20Sopenharmony_ci CHUNK_TRIMMED | CHUNK_ALLOCATED); 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (start != SZ_4M || end != SZ_32M - 1) { 4958c2ecf20Sopenharmony_ci test_err("error finding next unalloc range: start %llu end %llu", 4968c2ecf20Sopenharmony_ci start, end); 4978c2ecf20Sopenharmony_ci goto out; 4988c2ecf20Sopenharmony_ci } 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ci /* 5018c2ecf20Sopenharmony_ci * Set 64M-72M with CHUNK_ALLOC flag, then search for CHUNK_TRIMMED flag 5028c2ecf20Sopenharmony_ci * being unset in this range, we should get the entry in range 64M-72M 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_ci set_extent_bits(&tree, SZ_64M, SZ_64M + SZ_8M - 1, CHUNK_ALLOCATED); 5058c2ecf20Sopenharmony_ci find_first_clear_extent_bit(&tree, SZ_64M + SZ_1M, &start, &end, 5068c2ecf20Sopenharmony_ci CHUNK_TRIMMED); 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci if (start != SZ_64M || end != SZ_64M + SZ_8M - 1) { 5098c2ecf20Sopenharmony_ci test_err("error finding exact range: start %llu end %llu", 5108c2ecf20Sopenharmony_ci start, end); 5118c2ecf20Sopenharmony_ci goto out; 5128c2ecf20Sopenharmony_ci } 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci find_first_clear_extent_bit(&tree, SZ_64M - SZ_8M, &start, &end, 5158c2ecf20Sopenharmony_ci CHUNK_TRIMMED); 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci /* 5188c2ecf20Sopenharmony_ci * Search in the middle of set range whose immediate neighbour doesn't 5198c2ecf20Sopenharmony_ci * have the bits set so it must be returned 5208c2ecf20Sopenharmony_ci */ 5218c2ecf20Sopenharmony_ci if (start != SZ_64M || end != SZ_64M + SZ_8M - 1) { 5228c2ecf20Sopenharmony_ci test_err("error finding next alloc range: start %llu end %llu", 5238c2ecf20Sopenharmony_ci start, end); 5248c2ecf20Sopenharmony_ci goto out; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci /* 5288c2ecf20Sopenharmony_ci * Search beyond any known range, shall return after last known range 5298c2ecf20Sopenharmony_ci * and end should be -1 5308c2ecf20Sopenharmony_ci */ 5318c2ecf20Sopenharmony_ci find_first_clear_extent_bit(&tree, -1, &start, &end, CHUNK_TRIMMED); 5328c2ecf20Sopenharmony_ci if (start != SZ_64M + SZ_8M || end != -1) { 5338c2ecf20Sopenharmony_ci test_err( 5348c2ecf20Sopenharmony_ci "error handling beyond end of range search: start %llu end %llu", 5358c2ecf20Sopenharmony_ci start, end); 5368c2ecf20Sopenharmony_ci goto out; 5378c2ecf20Sopenharmony_ci } 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci ret = 0; 5408c2ecf20Sopenharmony_ciout: 5418c2ecf20Sopenharmony_ci clear_extent_bits(&tree, 0, (u64)-1, CHUNK_TRIMMED | CHUNK_ALLOCATED); 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci return ret; 5448c2ecf20Sopenharmony_ci} 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ciint btrfs_test_extent_io(u32 sectorsize, u32 nodesize) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci int ret; 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ci test_msg("running extent I/O tests"); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci ret = test_find_delalloc(sectorsize); 5538c2ecf20Sopenharmony_ci if (ret) 5548c2ecf20Sopenharmony_ci goto out; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci ret = test_find_first_clear_extent_bit(); 5578c2ecf20Sopenharmony_ci if (ret) 5588c2ecf20Sopenharmony_ci goto out; 5598c2ecf20Sopenharmony_ci 5608c2ecf20Sopenharmony_ci ret = test_eb_bitmaps(sectorsize, nodesize); 5618c2ecf20Sopenharmony_ciout: 5628c2ecf20Sopenharmony_ci return ret; 5638c2ecf20Sopenharmony_ci} 564