162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2017 Oracle. All rights reserved. 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/types.h> 762306a36Sopenharmony_ci#include "btrfs-tests.h" 862306a36Sopenharmony_ci#include "../ctree.h" 962306a36Sopenharmony_ci#include "../btrfs_inode.h" 1062306a36Sopenharmony_ci#include "../volumes.h" 1162306a36Sopenharmony_ci#include "../disk-io.h" 1262306a36Sopenharmony_ci#include "../block-group.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void free_extent_map_tree(struct extent_map_tree *em_tree) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct extent_map *em; 1762306a36Sopenharmony_ci struct rb_node *node; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci write_lock(&em_tree->lock); 2062306a36Sopenharmony_ci while (!RB_EMPTY_ROOT(&em_tree->map.rb_root)) { 2162306a36Sopenharmony_ci node = rb_first_cached(&em_tree->map); 2262306a36Sopenharmony_ci em = rb_entry(node, struct extent_map, rb_node); 2362306a36Sopenharmony_ci remove_extent_mapping(em_tree, em); 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#ifdef CONFIG_BTRFS_DEBUG 2662306a36Sopenharmony_ci if (refcount_read(&em->refs) != 1) { 2762306a36Sopenharmony_ci test_err( 2862306a36Sopenharmony_ci"em leak: em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx) refs %d", 2962306a36Sopenharmony_ci em->start, em->len, em->block_start, 3062306a36Sopenharmony_ci em->block_len, refcount_read(&em->refs)); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci refcount_set(&em->refs, 1); 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci#endif 3562306a36Sopenharmony_ci free_extent_map(em); 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci write_unlock(&em_tree->lock); 3862306a36Sopenharmony_ci} 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* 4162306a36Sopenharmony_ci * Test scenario: 4262306a36Sopenharmony_ci * 4362306a36Sopenharmony_ci * Suppose that no extent map has been loaded into memory yet, there is a file 4462306a36Sopenharmony_ci * extent [0, 16K), followed by another file extent [16K, 20K), two dio reads 4562306a36Sopenharmony_ci * are entering btrfs_get_extent() concurrently, t1 is reading [8K, 16K), t2 is 4662306a36Sopenharmony_ci * reading [0, 8K) 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * t1 t2 4962306a36Sopenharmony_ci * btrfs_get_extent() btrfs_get_extent() 5062306a36Sopenharmony_ci * -> lookup_extent_mapping() ->lookup_extent_mapping() 5162306a36Sopenharmony_ci * -> add_extent_mapping(0, 16K) 5262306a36Sopenharmony_ci * -> return em 5362306a36Sopenharmony_ci * ->add_extent_mapping(0, 16K) 5462306a36Sopenharmony_ci * -> #handle -EEXIST 5562306a36Sopenharmony_ci */ 5662306a36Sopenharmony_cistatic int test_case_1(struct btrfs_fs_info *fs_info, 5762306a36Sopenharmony_ci struct extent_map_tree *em_tree) 5862306a36Sopenharmony_ci{ 5962306a36Sopenharmony_ci struct extent_map *em; 6062306a36Sopenharmony_ci u64 start = 0; 6162306a36Sopenharmony_ci u64 len = SZ_8K; 6262306a36Sopenharmony_ci int ret; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci em = alloc_extent_map(); 6562306a36Sopenharmony_ci if (!em) { 6662306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 6762306a36Sopenharmony_ci return -ENOMEM; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Add [0, 16K) */ 7162306a36Sopenharmony_ci em->start = 0; 7262306a36Sopenharmony_ci em->len = SZ_16K; 7362306a36Sopenharmony_ci em->block_start = 0; 7462306a36Sopenharmony_ci em->block_len = SZ_16K; 7562306a36Sopenharmony_ci write_lock(&em_tree->lock); 7662306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 7762306a36Sopenharmony_ci write_unlock(&em_tree->lock); 7862306a36Sopenharmony_ci if (ret < 0) { 7962306a36Sopenharmony_ci test_err("cannot add extent range [0, 16K)"); 8062306a36Sopenharmony_ci goto out; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci free_extent_map(em); 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci /* Add [16K, 20K) following [0, 16K) */ 8562306a36Sopenharmony_ci em = alloc_extent_map(); 8662306a36Sopenharmony_ci if (!em) { 8762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 8862306a36Sopenharmony_ci ret = -ENOMEM; 8962306a36Sopenharmony_ci goto out; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci em->start = SZ_16K; 9362306a36Sopenharmony_ci em->len = SZ_4K; 9462306a36Sopenharmony_ci em->block_start = SZ_32K; /* avoid merging */ 9562306a36Sopenharmony_ci em->block_len = SZ_4K; 9662306a36Sopenharmony_ci write_lock(&em_tree->lock); 9762306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 9862306a36Sopenharmony_ci write_unlock(&em_tree->lock); 9962306a36Sopenharmony_ci if (ret < 0) { 10062306a36Sopenharmony_ci test_err("cannot add extent range [16K, 20K)"); 10162306a36Sopenharmony_ci goto out; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci free_extent_map(em); 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci em = alloc_extent_map(); 10662306a36Sopenharmony_ci if (!em) { 10762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 10862306a36Sopenharmony_ci ret = -ENOMEM; 10962306a36Sopenharmony_ci goto out; 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci /* Add [0, 8K), should return [0, 16K) instead. */ 11362306a36Sopenharmony_ci em->start = start; 11462306a36Sopenharmony_ci em->len = len; 11562306a36Sopenharmony_ci em->block_start = start; 11662306a36Sopenharmony_ci em->block_len = len; 11762306a36Sopenharmony_ci write_lock(&em_tree->lock); 11862306a36Sopenharmony_ci ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len); 11962306a36Sopenharmony_ci write_unlock(&em_tree->lock); 12062306a36Sopenharmony_ci if (ret) { 12162306a36Sopenharmony_ci test_err("case1 [%llu %llu]: ret %d", start, start + len, ret); 12262306a36Sopenharmony_ci goto out; 12362306a36Sopenharmony_ci } 12462306a36Sopenharmony_ci if (em && 12562306a36Sopenharmony_ci (em->start != 0 || extent_map_end(em) != SZ_16K || 12662306a36Sopenharmony_ci em->block_start != 0 || em->block_len != SZ_16K)) { 12762306a36Sopenharmony_ci test_err( 12862306a36Sopenharmony_ci"case1 [%llu %llu]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu", 12962306a36Sopenharmony_ci start, start + len, ret, em->start, em->len, 13062306a36Sopenharmony_ci em->block_start, em->block_len); 13162306a36Sopenharmony_ci ret = -EINVAL; 13262306a36Sopenharmony_ci } 13362306a36Sopenharmony_ci free_extent_map(em); 13462306a36Sopenharmony_ciout: 13562306a36Sopenharmony_ci free_extent_map_tree(em_tree); 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci return ret; 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci/* 14162306a36Sopenharmony_ci * Test scenario: 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * Reading the inline ending up with EEXIST, ie. read an inline 14462306a36Sopenharmony_ci * extent and discard page cache and read it again. 14562306a36Sopenharmony_ci */ 14662306a36Sopenharmony_cistatic int test_case_2(struct btrfs_fs_info *fs_info, 14762306a36Sopenharmony_ci struct extent_map_tree *em_tree) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct extent_map *em; 15062306a36Sopenharmony_ci int ret; 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci em = alloc_extent_map(); 15362306a36Sopenharmony_ci if (!em) { 15462306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 15562306a36Sopenharmony_ci return -ENOMEM; 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci /* Add [0, 1K) */ 15962306a36Sopenharmony_ci em->start = 0; 16062306a36Sopenharmony_ci em->len = SZ_1K; 16162306a36Sopenharmony_ci em->block_start = EXTENT_MAP_INLINE; 16262306a36Sopenharmony_ci em->block_len = (u64)-1; 16362306a36Sopenharmony_ci write_lock(&em_tree->lock); 16462306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 16562306a36Sopenharmony_ci write_unlock(&em_tree->lock); 16662306a36Sopenharmony_ci if (ret < 0) { 16762306a36Sopenharmony_ci test_err("cannot add extent range [0, 1K)"); 16862306a36Sopenharmony_ci goto out; 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci free_extent_map(em); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* Add [4K, 8K) following [0, 1K) */ 17362306a36Sopenharmony_ci em = alloc_extent_map(); 17462306a36Sopenharmony_ci if (!em) { 17562306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 17662306a36Sopenharmony_ci ret = -ENOMEM; 17762306a36Sopenharmony_ci goto out; 17862306a36Sopenharmony_ci } 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci em->start = SZ_4K; 18162306a36Sopenharmony_ci em->len = SZ_4K; 18262306a36Sopenharmony_ci em->block_start = SZ_4K; 18362306a36Sopenharmony_ci em->block_len = SZ_4K; 18462306a36Sopenharmony_ci write_lock(&em_tree->lock); 18562306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 18662306a36Sopenharmony_ci write_unlock(&em_tree->lock); 18762306a36Sopenharmony_ci if (ret < 0) { 18862306a36Sopenharmony_ci test_err("cannot add extent range [4K, 8K)"); 18962306a36Sopenharmony_ci goto out; 19062306a36Sopenharmony_ci } 19162306a36Sopenharmony_ci free_extent_map(em); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci em = alloc_extent_map(); 19462306a36Sopenharmony_ci if (!em) { 19562306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 19662306a36Sopenharmony_ci ret = -ENOMEM; 19762306a36Sopenharmony_ci goto out; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Add [0, 1K) */ 20162306a36Sopenharmony_ci em->start = 0; 20262306a36Sopenharmony_ci em->len = SZ_1K; 20362306a36Sopenharmony_ci em->block_start = EXTENT_MAP_INLINE; 20462306a36Sopenharmony_ci em->block_len = (u64)-1; 20562306a36Sopenharmony_ci write_lock(&em_tree->lock); 20662306a36Sopenharmony_ci ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len); 20762306a36Sopenharmony_ci write_unlock(&em_tree->lock); 20862306a36Sopenharmony_ci if (ret) { 20962306a36Sopenharmony_ci test_err("case2 [0 1K]: ret %d", ret); 21062306a36Sopenharmony_ci goto out; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci if (em && 21362306a36Sopenharmony_ci (em->start != 0 || extent_map_end(em) != SZ_1K || 21462306a36Sopenharmony_ci em->block_start != EXTENT_MAP_INLINE || em->block_len != (u64)-1)) { 21562306a36Sopenharmony_ci test_err( 21662306a36Sopenharmony_ci"case2 [0 1K]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu", 21762306a36Sopenharmony_ci ret, em->start, em->len, em->block_start, 21862306a36Sopenharmony_ci em->block_len); 21962306a36Sopenharmony_ci ret = -EINVAL; 22062306a36Sopenharmony_ci } 22162306a36Sopenharmony_ci free_extent_map(em); 22262306a36Sopenharmony_ciout: 22362306a36Sopenharmony_ci free_extent_map_tree(em_tree); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci return ret; 22662306a36Sopenharmony_ci} 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_cistatic int __test_case_3(struct btrfs_fs_info *fs_info, 22962306a36Sopenharmony_ci struct extent_map_tree *em_tree, u64 start) 23062306a36Sopenharmony_ci{ 23162306a36Sopenharmony_ci struct extent_map *em; 23262306a36Sopenharmony_ci u64 len = SZ_4K; 23362306a36Sopenharmony_ci int ret; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci em = alloc_extent_map(); 23662306a36Sopenharmony_ci if (!em) { 23762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 23862306a36Sopenharmony_ci return -ENOMEM; 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci /* Add [4K, 8K) */ 24262306a36Sopenharmony_ci em->start = SZ_4K; 24362306a36Sopenharmony_ci em->len = SZ_4K; 24462306a36Sopenharmony_ci em->block_start = SZ_4K; 24562306a36Sopenharmony_ci em->block_len = SZ_4K; 24662306a36Sopenharmony_ci write_lock(&em_tree->lock); 24762306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 24862306a36Sopenharmony_ci write_unlock(&em_tree->lock); 24962306a36Sopenharmony_ci if (ret < 0) { 25062306a36Sopenharmony_ci test_err("cannot add extent range [4K, 8K)"); 25162306a36Sopenharmony_ci goto out; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci free_extent_map(em); 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci em = alloc_extent_map(); 25662306a36Sopenharmony_ci if (!em) { 25762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 25862306a36Sopenharmony_ci ret = -ENOMEM; 25962306a36Sopenharmony_ci goto out; 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci 26262306a36Sopenharmony_ci /* Add [0, 16K) */ 26362306a36Sopenharmony_ci em->start = 0; 26462306a36Sopenharmony_ci em->len = SZ_16K; 26562306a36Sopenharmony_ci em->block_start = 0; 26662306a36Sopenharmony_ci em->block_len = SZ_16K; 26762306a36Sopenharmony_ci write_lock(&em_tree->lock); 26862306a36Sopenharmony_ci ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len); 26962306a36Sopenharmony_ci write_unlock(&em_tree->lock); 27062306a36Sopenharmony_ci if (ret) { 27162306a36Sopenharmony_ci test_err("case3 [0x%llx 0x%llx): ret %d", 27262306a36Sopenharmony_ci start, start + len, ret); 27362306a36Sopenharmony_ci goto out; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci /* 27662306a36Sopenharmony_ci * Since bytes within em are contiguous, em->block_start is identical to 27762306a36Sopenharmony_ci * em->start. 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_ci if (em && 28062306a36Sopenharmony_ci (start < em->start || start + len > extent_map_end(em) || 28162306a36Sopenharmony_ci em->start != em->block_start || em->len != em->block_len)) { 28262306a36Sopenharmony_ci test_err( 28362306a36Sopenharmony_ci"case3 [0x%llx 0x%llx): ret %d em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)", 28462306a36Sopenharmony_ci start, start + len, ret, em->start, em->len, 28562306a36Sopenharmony_ci em->block_start, em->block_len); 28662306a36Sopenharmony_ci ret = -EINVAL; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci free_extent_map(em); 28962306a36Sopenharmony_ciout: 29062306a36Sopenharmony_ci free_extent_map_tree(em_tree); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci return ret; 29362306a36Sopenharmony_ci} 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci/* 29662306a36Sopenharmony_ci * Test scenario: 29762306a36Sopenharmony_ci * 29862306a36Sopenharmony_ci * Suppose that no extent map has been loaded into memory yet. 29962306a36Sopenharmony_ci * There is a file extent [0, 16K), two jobs are running concurrently 30062306a36Sopenharmony_ci * against it, t1 is buffered writing to [4K, 8K) and t2 is doing dio 30162306a36Sopenharmony_ci * read from [0, 4K) or [8K, 12K) or [12K, 16K). 30262306a36Sopenharmony_ci * 30362306a36Sopenharmony_ci * t1 goes ahead of t2 and adds em [4K, 8K) into tree. 30462306a36Sopenharmony_ci * 30562306a36Sopenharmony_ci * t1 t2 30662306a36Sopenharmony_ci * cow_file_range() btrfs_get_extent() 30762306a36Sopenharmony_ci * -> lookup_extent_mapping() 30862306a36Sopenharmony_ci * -> add_extent_mapping() 30962306a36Sopenharmony_ci * -> add_extent_mapping() 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_cistatic int test_case_3(struct btrfs_fs_info *fs_info, 31262306a36Sopenharmony_ci struct extent_map_tree *em_tree) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci int ret; 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci ret = __test_case_3(fs_info, em_tree, 0); 31762306a36Sopenharmony_ci if (ret) 31862306a36Sopenharmony_ci return ret; 31962306a36Sopenharmony_ci ret = __test_case_3(fs_info, em_tree, SZ_8K); 32062306a36Sopenharmony_ci if (ret) 32162306a36Sopenharmony_ci return ret; 32262306a36Sopenharmony_ci ret = __test_case_3(fs_info, em_tree, (12 * SZ_1K)); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci return ret; 32562306a36Sopenharmony_ci} 32662306a36Sopenharmony_ci 32762306a36Sopenharmony_cistatic int __test_case_4(struct btrfs_fs_info *fs_info, 32862306a36Sopenharmony_ci struct extent_map_tree *em_tree, u64 start) 32962306a36Sopenharmony_ci{ 33062306a36Sopenharmony_ci struct extent_map *em; 33162306a36Sopenharmony_ci u64 len = SZ_4K; 33262306a36Sopenharmony_ci int ret; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci em = alloc_extent_map(); 33562306a36Sopenharmony_ci if (!em) { 33662306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 33762306a36Sopenharmony_ci return -ENOMEM; 33862306a36Sopenharmony_ci } 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci /* Add [0K, 8K) */ 34162306a36Sopenharmony_ci em->start = 0; 34262306a36Sopenharmony_ci em->len = SZ_8K; 34362306a36Sopenharmony_ci em->block_start = 0; 34462306a36Sopenharmony_ci em->block_len = SZ_8K; 34562306a36Sopenharmony_ci write_lock(&em_tree->lock); 34662306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 34762306a36Sopenharmony_ci write_unlock(&em_tree->lock); 34862306a36Sopenharmony_ci if (ret < 0) { 34962306a36Sopenharmony_ci test_err("cannot add extent range [0, 8K)"); 35062306a36Sopenharmony_ci goto out; 35162306a36Sopenharmony_ci } 35262306a36Sopenharmony_ci free_extent_map(em); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci em = alloc_extent_map(); 35562306a36Sopenharmony_ci if (!em) { 35662306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 35762306a36Sopenharmony_ci ret = -ENOMEM; 35862306a36Sopenharmony_ci goto out; 35962306a36Sopenharmony_ci } 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci /* Add [8K, 32K) */ 36262306a36Sopenharmony_ci em->start = SZ_8K; 36362306a36Sopenharmony_ci em->len = 24 * SZ_1K; 36462306a36Sopenharmony_ci em->block_start = SZ_16K; /* avoid merging */ 36562306a36Sopenharmony_ci em->block_len = 24 * SZ_1K; 36662306a36Sopenharmony_ci write_lock(&em_tree->lock); 36762306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 36862306a36Sopenharmony_ci write_unlock(&em_tree->lock); 36962306a36Sopenharmony_ci if (ret < 0) { 37062306a36Sopenharmony_ci test_err("cannot add extent range [8K, 32K)"); 37162306a36Sopenharmony_ci goto out; 37262306a36Sopenharmony_ci } 37362306a36Sopenharmony_ci free_extent_map(em); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci em = alloc_extent_map(); 37662306a36Sopenharmony_ci if (!em) { 37762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 37862306a36Sopenharmony_ci ret = -ENOMEM; 37962306a36Sopenharmony_ci goto out; 38062306a36Sopenharmony_ci } 38162306a36Sopenharmony_ci /* Add [0K, 32K) */ 38262306a36Sopenharmony_ci em->start = 0; 38362306a36Sopenharmony_ci em->len = SZ_32K; 38462306a36Sopenharmony_ci em->block_start = 0; 38562306a36Sopenharmony_ci em->block_len = SZ_32K; 38662306a36Sopenharmony_ci write_lock(&em_tree->lock); 38762306a36Sopenharmony_ci ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len); 38862306a36Sopenharmony_ci write_unlock(&em_tree->lock); 38962306a36Sopenharmony_ci if (ret) { 39062306a36Sopenharmony_ci test_err("case4 [0x%llx 0x%llx): ret %d", 39162306a36Sopenharmony_ci start, len, ret); 39262306a36Sopenharmony_ci goto out; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci if (em && (start < em->start || start + len > extent_map_end(em))) { 39562306a36Sopenharmony_ci test_err( 39662306a36Sopenharmony_ci"case4 [0x%llx 0x%llx): ret %d, added wrong em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)", 39762306a36Sopenharmony_ci start, len, ret, em->start, em->len, em->block_start, 39862306a36Sopenharmony_ci em->block_len); 39962306a36Sopenharmony_ci ret = -EINVAL; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci free_extent_map(em); 40262306a36Sopenharmony_ciout: 40362306a36Sopenharmony_ci free_extent_map_tree(em_tree); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return ret; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci/* 40962306a36Sopenharmony_ci * Test scenario: 41062306a36Sopenharmony_ci * 41162306a36Sopenharmony_ci * Suppose that no extent map has been loaded into memory yet. 41262306a36Sopenharmony_ci * There is a file extent [0, 32K), two jobs are running concurrently 41362306a36Sopenharmony_ci * against it, t1 is doing dio write to [8K, 32K) and t2 is doing dio 41462306a36Sopenharmony_ci * read from [0, 4K) or [4K, 8K). 41562306a36Sopenharmony_ci * 41662306a36Sopenharmony_ci * t1 goes ahead of t2 and splits em [0, 32K) to em [0K, 8K) and [8K 32K). 41762306a36Sopenharmony_ci * 41862306a36Sopenharmony_ci * t1 t2 41962306a36Sopenharmony_ci * btrfs_get_blocks_direct() btrfs_get_blocks_direct() 42062306a36Sopenharmony_ci * -> btrfs_get_extent() -> btrfs_get_extent() 42162306a36Sopenharmony_ci * -> lookup_extent_mapping() 42262306a36Sopenharmony_ci * -> add_extent_mapping() -> lookup_extent_mapping() 42362306a36Sopenharmony_ci * # load [0, 32K) 42462306a36Sopenharmony_ci * -> btrfs_new_extent_direct() 42562306a36Sopenharmony_ci * -> btrfs_drop_extent_cache() 42662306a36Sopenharmony_ci * # split [0, 32K) 42762306a36Sopenharmony_ci * -> add_extent_mapping() 42862306a36Sopenharmony_ci * # add [8K, 32K) 42962306a36Sopenharmony_ci * -> add_extent_mapping() 43062306a36Sopenharmony_ci * # handle -EEXIST when adding 43162306a36Sopenharmony_ci * # [0, 32K) 43262306a36Sopenharmony_ci */ 43362306a36Sopenharmony_cistatic int test_case_4(struct btrfs_fs_info *fs_info, 43462306a36Sopenharmony_ci struct extent_map_tree *em_tree) 43562306a36Sopenharmony_ci{ 43662306a36Sopenharmony_ci int ret; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci ret = __test_case_4(fs_info, em_tree, 0); 43962306a36Sopenharmony_ci if (ret) 44062306a36Sopenharmony_ci return ret; 44162306a36Sopenharmony_ci ret = __test_case_4(fs_info, em_tree, SZ_4K); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci return ret; 44462306a36Sopenharmony_ci} 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_cistatic int add_compressed_extent(struct extent_map_tree *em_tree, 44762306a36Sopenharmony_ci u64 start, u64 len, u64 block_start) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci struct extent_map *em; 45062306a36Sopenharmony_ci int ret; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci em = alloc_extent_map(); 45362306a36Sopenharmony_ci if (!em) { 45462306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 45562306a36Sopenharmony_ci return -ENOMEM; 45662306a36Sopenharmony_ci } 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci em->start = start; 45962306a36Sopenharmony_ci em->len = len; 46062306a36Sopenharmony_ci em->block_start = block_start; 46162306a36Sopenharmony_ci em->block_len = SZ_4K; 46262306a36Sopenharmony_ci set_bit(EXTENT_FLAG_COMPRESSED, &em->flags); 46362306a36Sopenharmony_ci write_lock(&em_tree->lock); 46462306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 46562306a36Sopenharmony_ci write_unlock(&em_tree->lock); 46662306a36Sopenharmony_ci free_extent_map(em); 46762306a36Sopenharmony_ci if (ret < 0) { 46862306a36Sopenharmony_ci test_err("cannot add extent map [%llu, %llu)", start, start + len); 46962306a36Sopenharmony_ci return ret; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 0; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistruct extent_range { 47662306a36Sopenharmony_ci u64 start; 47762306a36Sopenharmony_ci u64 len; 47862306a36Sopenharmony_ci}; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci/* The valid states of the tree after every drop, as described below. */ 48162306a36Sopenharmony_cistruct extent_range valid_ranges[][7] = { 48262306a36Sopenharmony_ci { 48362306a36Sopenharmony_ci { .start = 0, .len = SZ_8K }, /* [0, 8K) */ 48462306a36Sopenharmony_ci { .start = SZ_4K * 3, .len = SZ_4K * 3}, /* [12k, 24k) */ 48562306a36Sopenharmony_ci { .start = SZ_4K * 6, .len = SZ_4K * 3}, /* [24k, 36k) */ 48662306a36Sopenharmony_ci { .start = SZ_32K + SZ_4K, .len = SZ_4K}, /* [36k, 40k) */ 48762306a36Sopenharmony_ci { .start = SZ_4K * 10, .len = SZ_4K * 6}, /* [40k, 64k) */ 48862306a36Sopenharmony_ci }, 48962306a36Sopenharmony_ci { 49062306a36Sopenharmony_ci { .start = 0, .len = SZ_8K }, /* [0, 8K) */ 49162306a36Sopenharmony_ci { .start = SZ_4K * 5, .len = SZ_4K}, /* [20k, 24k) */ 49262306a36Sopenharmony_ci { .start = SZ_4K * 6, .len = SZ_4K * 3}, /* [24k, 36k) */ 49362306a36Sopenharmony_ci { .start = SZ_32K + SZ_4K, .len = SZ_4K}, /* [36k, 40k) */ 49462306a36Sopenharmony_ci { .start = SZ_4K * 10, .len = SZ_4K * 6}, /* [40k, 64k) */ 49562306a36Sopenharmony_ci }, 49662306a36Sopenharmony_ci { 49762306a36Sopenharmony_ci { .start = 0, .len = SZ_8K }, /* [0, 8K) */ 49862306a36Sopenharmony_ci { .start = SZ_4K * 5, .len = SZ_4K}, /* [20k, 24k) */ 49962306a36Sopenharmony_ci { .start = SZ_4K * 6, .len = SZ_4K}, /* [24k, 28k) */ 50062306a36Sopenharmony_ci { .start = SZ_32K, .len = SZ_4K}, /* [32k, 36k) */ 50162306a36Sopenharmony_ci { .start = SZ_32K + SZ_4K, .len = SZ_4K}, /* [36k, 40k) */ 50262306a36Sopenharmony_ci { .start = SZ_4K * 10, .len = SZ_4K * 6}, /* [40k, 64k) */ 50362306a36Sopenharmony_ci }, 50462306a36Sopenharmony_ci { 50562306a36Sopenharmony_ci { .start = 0, .len = SZ_8K}, /* [0, 8K) */ 50662306a36Sopenharmony_ci { .start = SZ_4K * 5, .len = SZ_4K}, /* [20k, 24k) */ 50762306a36Sopenharmony_ci { .start = SZ_4K * 6, .len = SZ_4K}, /* [24k, 28k) */ 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci}; 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_cistatic int validate_range(struct extent_map_tree *em_tree, int index) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci struct rb_node *n; 51462306a36Sopenharmony_ci int i; 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci for (i = 0, n = rb_first_cached(&em_tree->map); 51762306a36Sopenharmony_ci valid_ranges[index][i].len && n; 51862306a36Sopenharmony_ci i++, n = rb_next(n)) { 51962306a36Sopenharmony_ci struct extent_map *entry = rb_entry(n, struct extent_map, rb_node); 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci if (entry->start != valid_ranges[index][i].start) { 52262306a36Sopenharmony_ci test_err("mapping has start %llu expected %llu", 52362306a36Sopenharmony_ci entry->start, valid_ranges[index][i].start); 52462306a36Sopenharmony_ci return -EINVAL; 52562306a36Sopenharmony_ci } 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci if (entry->len != valid_ranges[index][i].len) { 52862306a36Sopenharmony_ci test_err("mapping has len %llu expected %llu", 52962306a36Sopenharmony_ci entry->len, valid_ranges[index][i].len); 53062306a36Sopenharmony_ci return -EINVAL; 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci } 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci /* 53562306a36Sopenharmony_ci * We exited because we don't have any more entries in the extent_map 53662306a36Sopenharmony_ci * but we still expect more valid entries. 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_ci if (valid_ranges[index][i].len) { 53962306a36Sopenharmony_ci test_err("missing an entry"); 54062306a36Sopenharmony_ci return -EINVAL; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci /* We exited the loop but still have entries in the extent map. */ 54462306a36Sopenharmony_ci if (n) { 54562306a36Sopenharmony_ci test_err("we have a left over entry in the extent map we didn't expect"); 54662306a36Sopenharmony_ci return -EINVAL; 54762306a36Sopenharmony_ci } 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci return 0; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci/* 55362306a36Sopenharmony_ci * Test scenario: 55462306a36Sopenharmony_ci * 55562306a36Sopenharmony_ci * Test the various edge cases of btrfs_drop_extent_map_range, create the 55662306a36Sopenharmony_ci * following ranges 55762306a36Sopenharmony_ci * 55862306a36Sopenharmony_ci * [0, 12k)[12k, 24k)[24k, 36k)[36k, 40k)[40k,64k) 55962306a36Sopenharmony_ci * 56062306a36Sopenharmony_ci * And then we'll drop: 56162306a36Sopenharmony_ci * 56262306a36Sopenharmony_ci * [8k, 12k) - test the single front split 56362306a36Sopenharmony_ci * [12k, 20k) - test the single back split 56462306a36Sopenharmony_ci * [28k, 32k) - test the double split 56562306a36Sopenharmony_ci * [32k, 64k) - test whole em dropping 56662306a36Sopenharmony_ci * 56762306a36Sopenharmony_ci * They'll have the EXTENT_FLAG_COMPRESSED flag set to keep the em tree from 56862306a36Sopenharmony_ci * merging the em's. 56962306a36Sopenharmony_ci */ 57062306a36Sopenharmony_cistatic int test_case_5(void) 57162306a36Sopenharmony_ci{ 57262306a36Sopenharmony_ci struct extent_map_tree *em_tree; 57362306a36Sopenharmony_ci struct inode *inode; 57462306a36Sopenharmony_ci u64 start, end; 57562306a36Sopenharmony_ci int ret; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci test_msg("Running btrfs_drop_extent_map_range tests"); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci inode = btrfs_new_test_inode(); 58062306a36Sopenharmony_ci if (!inode) { 58162306a36Sopenharmony_ci test_std_err(TEST_ALLOC_INODE); 58262306a36Sopenharmony_ci return -ENOMEM; 58362306a36Sopenharmony_ci } 58462306a36Sopenharmony_ci 58562306a36Sopenharmony_ci em_tree = &BTRFS_I(inode)->extent_tree; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci /* [0, 12k) */ 58862306a36Sopenharmony_ci ret = add_compressed_extent(em_tree, 0, SZ_4K * 3, 0); 58962306a36Sopenharmony_ci if (ret) { 59062306a36Sopenharmony_ci test_err("cannot add extent range [0, 12K)"); 59162306a36Sopenharmony_ci goto out; 59262306a36Sopenharmony_ci } 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* [12k, 24k) */ 59562306a36Sopenharmony_ci ret = add_compressed_extent(em_tree, SZ_4K * 3, SZ_4K * 3, SZ_4K); 59662306a36Sopenharmony_ci if (ret) { 59762306a36Sopenharmony_ci test_err("cannot add extent range [12k, 24k)"); 59862306a36Sopenharmony_ci goto out; 59962306a36Sopenharmony_ci } 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* [24k, 36k) */ 60262306a36Sopenharmony_ci ret = add_compressed_extent(em_tree, SZ_4K * 6, SZ_4K * 3, SZ_8K); 60362306a36Sopenharmony_ci if (ret) { 60462306a36Sopenharmony_ci test_err("cannot add extent range [12k, 24k)"); 60562306a36Sopenharmony_ci goto out; 60662306a36Sopenharmony_ci } 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci /* [36k, 40k) */ 60962306a36Sopenharmony_ci ret = add_compressed_extent(em_tree, SZ_32K + SZ_4K, SZ_4K, SZ_4K * 3); 61062306a36Sopenharmony_ci if (ret) { 61162306a36Sopenharmony_ci test_err("cannot add extent range [12k, 24k)"); 61262306a36Sopenharmony_ci goto out; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci /* [40k, 64k) */ 61662306a36Sopenharmony_ci ret = add_compressed_extent(em_tree, SZ_4K * 10, SZ_4K * 6, SZ_16K); 61762306a36Sopenharmony_ci if (ret) { 61862306a36Sopenharmony_ci test_err("cannot add extent range [12k, 24k)"); 61962306a36Sopenharmony_ci goto out; 62062306a36Sopenharmony_ci } 62162306a36Sopenharmony_ci 62262306a36Sopenharmony_ci /* Drop [8k, 12k) */ 62362306a36Sopenharmony_ci start = SZ_8K; 62462306a36Sopenharmony_ci end = (3 * SZ_4K) - 1; 62562306a36Sopenharmony_ci btrfs_drop_extent_map_range(BTRFS_I(inode), start, end, false); 62662306a36Sopenharmony_ci ret = validate_range(&BTRFS_I(inode)->extent_tree, 0); 62762306a36Sopenharmony_ci if (ret) 62862306a36Sopenharmony_ci goto out; 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci /* Drop [12k, 20k) */ 63162306a36Sopenharmony_ci start = SZ_4K * 3; 63262306a36Sopenharmony_ci end = SZ_16K + SZ_4K - 1; 63362306a36Sopenharmony_ci btrfs_drop_extent_map_range(BTRFS_I(inode), start, end, false); 63462306a36Sopenharmony_ci ret = validate_range(&BTRFS_I(inode)->extent_tree, 1); 63562306a36Sopenharmony_ci if (ret) 63662306a36Sopenharmony_ci goto out; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci /* Drop [28k, 32k) */ 63962306a36Sopenharmony_ci start = SZ_32K - SZ_4K; 64062306a36Sopenharmony_ci end = SZ_32K - 1; 64162306a36Sopenharmony_ci btrfs_drop_extent_map_range(BTRFS_I(inode), start, end, false); 64262306a36Sopenharmony_ci ret = validate_range(&BTRFS_I(inode)->extent_tree, 2); 64362306a36Sopenharmony_ci if (ret) 64462306a36Sopenharmony_ci goto out; 64562306a36Sopenharmony_ci 64662306a36Sopenharmony_ci /* Drop [32k, 64k) */ 64762306a36Sopenharmony_ci start = SZ_32K; 64862306a36Sopenharmony_ci end = SZ_64K - 1; 64962306a36Sopenharmony_ci btrfs_drop_extent_map_range(BTRFS_I(inode), start, end, false); 65062306a36Sopenharmony_ci ret = validate_range(&BTRFS_I(inode)->extent_tree, 3); 65162306a36Sopenharmony_ci if (ret) 65262306a36Sopenharmony_ci goto out; 65362306a36Sopenharmony_ciout: 65462306a36Sopenharmony_ci iput(inode); 65562306a36Sopenharmony_ci return ret; 65662306a36Sopenharmony_ci} 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci/* 65962306a36Sopenharmony_ci * Test the btrfs_add_extent_mapping helper which will attempt to create an em 66062306a36Sopenharmony_ci * for areas between two existing ems. Validate it doesn't do this when there 66162306a36Sopenharmony_ci * are two unmerged em's side by side. 66262306a36Sopenharmony_ci */ 66362306a36Sopenharmony_cistatic int test_case_6(struct btrfs_fs_info *fs_info, struct extent_map_tree *em_tree) 66462306a36Sopenharmony_ci{ 66562306a36Sopenharmony_ci struct extent_map *em = NULL; 66662306a36Sopenharmony_ci int ret; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci ret = add_compressed_extent(em_tree, 0, SZ_4K, 0); 66962306a36Sopenharmony_ci if (ret) 67062306a36Sopenharmony_ci goto out; 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci ret = add_compressed_extent(em_tree, SZ_4K, SZ_4K, 0); 67362306a36Sopenharmony_ci if (ret) 67462306a36Sopenharmony_ci goto out; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci em = alloc_extent_map(); 67762306a36Sopenharmony_ci if (!em) { 67862306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 67962306a36Sopenharmony_ci return -ENOMEM; 68062306a36Sopenharmony_ci } 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci em->start = SZ_4K; 68362306a36Sopenharmony_ci em->len = SZ_4K; 68462306a36Sopenharmony_ci em->block_start = SZ_16K; 68562306a36Sopenharmony_ci em->block_len = SZ_16K; 68662306a36Sopenharmony_ci write_lock(&em_tree->lock); 68762306a36Sopenharmony_ci ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, 0, SZ_8K); 68862306a36Sopenharmony_ci write_unlock(&em_tree->lock); 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci if (ret != 0) { 69162306a36Sopenharmony_ci test_err("got an error when adding our em: %d", ret); 69262306a36Sopenharmony_ci goto out; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci ret = -EINVAL; 69662306a36Sopenharmony_ci if (em->start != 0) { 69762306a36Sopenharmony_ci test_err("unexpected em->start at %llu, wanted 0", em->start); 69862306a36Sopenharmony_ci goto out; 69962306a36Sopenharmony_ci } 70062306a36Sopenharmony_ci if (em->len != SZ_4K) { 70162306a36Sopenharmony_ci test_err("unexpected em->len %llu, expected 4K", em->len); 70262306a36Sopenharmony_ci goto out; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci ret = 0; 70562306a36Sopenharmony_ciout: 70662306a36Sopenharmony_ci free_extent_map(em); 70762306a36Sopenharmony_ci free_extent_map_tree(em_tree); 70862306a36Sopenharmony_ci return ret; 70962306a36Sopenharmony_ci} 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci/* 71262306a36Sopenharmony_ci * Regression test for btrfs_drop_extent_map_range. Calling with skip_pinned == 71362306a36Sopenharmony_ci * true would mess up the start/end calculations and subsequent splits would be 71462306a36Sopenharmony_ci * incorrect. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_cistatic int test_case_7(void) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct extent_map_tree *em_tree; 71962306a36Sopenharmony_ci struct extent_map *em; 72062306a36Sopenharmony_ci struct inode *inode; 72162306a36Sopenharmony_ci int ret; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci test_msg("Running btrfs_drop_extent_cache with pinned"); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci inode = btrfs_new_test_inode(); 72662306a36Sopenharmony_ci if (!inode) { 72762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_INODE); 72862306a36Sopenharmony_ci return -ENOMEM; 72962306a36Sopenharmony_ci } 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci em_tree = &BTRFS_I(inode)->extent_tree; 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci em = alloc_extent_map(); 73462306a36Sopenharmony_ci if (!em) { 73562306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 73662306a36Sopenharmony_ci ret = -ENOMEM; 73762306a36Sopenharmony_ci goto out; 73862306a36Sopenharmony_ci } 73962306a36Sopenharmony_ci 74062306a36Sopenharmony_ci /* [0, 16K), pinned */ 74162306a36Sopenharmony_ci em->start = 0; 74262306a36Sopenharmony_ci em->len = SZ_16K; 74362306a36Sopenharmony_ci em->block_start = 0; 74462306a36Sopenharmony_ci em->block_len = SZ_4K; 74562306a36Sopenharmony_ci set_bit(EXTENT_FLAG_PINNED, &em->flags); 74662306a36Sopenharmony_ci write_lock(&em_tree->lock); 74762306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 74862306a36Sopenharmony_ci write_unlock(&em_tree->lock); 74962306a36Sopenharmony_ci if (ret < 0) { 75062306a36Sopenharmony_ci test_err("couldn't add extent map"); 75162306a36Sopenharmony_ci goto out; 75262306a36Sopenharmony_ci } 75362306a36Sopenharmony_ci free_extent_map(em); 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci em = alloc_extent_map(); 75662306a36Sopenharmony_ci if (!em) { 75762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 75862306a36Sopenharmony_ci ret = -ENOMEM; 75962306a36Sopenharmony_ci goto out; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* [32K, 48K), not pinned */ 76362306a36Sopenharmony_ci em->start = SZ_32K; 76462306a36Sopenharmony_ci em->len = SZ_16K; 76562306a36Sopenharmony_ci em->block_start = SZ_32K; 76662306a36Sopenharmony_ci em->block_len = SZ_16K; 76762306a36Sopenharmony_ci write_lock(&em_tree->lock); 76862306a36Sopenharmony_ci ret = add_extent_mapping(em_tree, em, 0); 76962306a36Sopenharmony_ci write_unlock(&em_tree->lock); 77062306a36Sopenharmony_ci if (ret < 0) { 77162306a36Sopenharmony_ci test_err("couldn't add extent map"); 77262306a36Sopenharmony_ci goto out; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci free_extent_map(em); 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci /* 77762306a36Sopenharmony_ci * Drop [0, 36K) This should skip the [0, 4K) extent and then split the 77862306a36Sopenharmony_ci * [32K, 48K) extent. 77962306a36Sopenharmony_ci */ 78062306a36Sopenharmony_ci btrfs_drop_extent_map_range(BTRFS_I(inode), 0, (36 * SZ_1K) - 1, true); 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* Make sure our extent maps look sane. */ 78362306a36Sopenharmony_ci ret = -EINVAL; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci em = lookup_extent_mapping(em_tree, 0, SZ_16K); 78662306a36Sopenharmony_ci if (!em) { 78762306a36Sopenharmony_ci test_err("didn't find an em at 0 as expected"); 78862306a36Sopenharmony_ci goto out; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (em->start != 0) { 79262306a36Sopenharmony_ci test_err("em->start is %llu, expected 0", em->start); 79362306a36Sopenharmony_ci goto out; 79462306a36Sopenharmony_ci } 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci if (em->len != SZ_16K) { 79762306a36Sopenharmony_ci test_err("em->len is %llu, expected 16K", em->len); 79862306a36Sopenharmony_ci goto out; 79962306a36Sopenharmony_ci } 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci free_extent_map(em); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci read_lock(&em_tree->lock); 80462306a36Sopenharmony_ci em = lookup_extent_mapping(em_tree, SZ_16K, SZ_16K); 80562306a36Sopenharmony_ci read_unlock(&em_tree->lock); 80662306a36Sopenharmony_ci if (em) { 80762306a36Sopenharmony_ci test_err("found an em when we weren't expecting one"); 80862306a36Sopenharmony_ci goto out; 80962306a36Sopenharmony_ci } 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci read_lock(&em_tree->lock); 81262306a36Sopenharmony_ci em = lookup_extent_mapping(em_tree, SZ_32K, SZ_16K); 81362306a36Sopenharmony_ci read_unlock(&em_tree->lock); 81462306a36Sopenharmony_ci if (!em) { 81562306a36Sopenharmony_ci test_err("didn't find an em at 32K as expected"); 81662306a36Sopenharmony_ci goto out; 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci if (em->start != (36 * SZ_1K)) { 82062306a36Sopenharmony_ci test_err("em->start is %llu, expected 36K", em->start); 82162306a36Sopenharmony_ci goto out; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (em->len != (12 * SZ_1K)) { 82562306a36Sopenharmony_ci test_err("em->len is %llu, expected 12K", em->len); 82662306a36Sopenharmony_ci goto out; 82762306a36Sopenharmony_ci } 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci free_extent_map(em); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci read_lock(&em_tree->lock); 83262306a36Sopenharmony_ci em = lookup_extent_mapping(em_tree, 48 * SZ_1K, (u64)-1); 83362306a36Sopenharmony_ci read_unlock(&em_tree->lock); 83462306a36Sopenharmony_ci if (em) { 83562306a36Sopenharmony_ci test_err("found an unexpected em above 48K"); 83662306a36Sopenharmony_ci goto out; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci ret = 0; 84062306a36Sopenharmony_ciout: 84162306a36Sopenharmony_ci free_extent_map(em); 84262306a36Sopenharmony_ci iput(inode); 84362306a36Sopenharmony_ci return ret; 84462306a36Sopenharmony_ci} 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_cistruct rmap_test_vector { 84762306a36Sopenharmony_ci u64 raid_type; 84862306a36Sopenharmony_ci u64 physical_start; 84962306a36Sopenharmony_ci u64 data_stripe_size; 85062306a36Sopenharmony_ci u64 num_data_stripes; 85162306a36Sopenharmony_ci u64 num_stripes; 85262306a36Sopenharmony_ci /* Assume we won't have more than 5 physical stripes */ 85362306a36Sopenharmony_ci u64 data_stripe_phys_start[5]; 85462306a36Sopenharmony_ci bool expected_mapped_addr; 85562306a36Sopenharmony_ci /* Physical to logical addresses */ 85662306a36Sopenharmony_ci u64 mapped_logical[5]; 85762306a36Sopenharmony_ci}; 85862306a36Sopenharmony_ci 85962306a36Sopenharmony_cistatic int test_rmap_block(struct btrfs_fs_info *fs_info, 86062306a36Sopenharmony_ci struct rmap_test_vector *test) 86162306a36Sopenharmony_ci{ 86262306a36Sopenharmony_ci struct extent_map *em; 86362306a36Sopenharmony_ci struct map_lookup *map = NULL; 86462306a36Sopenharmony_ci u64 *logical = NULL; 86562306a36Sopenharmony_ci int i, out_ndaddrs, out_stripe_len; 86662306a36Sopenharmony_ci int ret; 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci em = alloc_extent_map(); 86962306a36Sopenharmony_ci if (!em) { 87062306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 87162306a36Sopenharmony_ci return -ENOMEM; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci map = kmalloc(map_lookup_size(test->num_stripes), GFP_KERNEL); 87562306a36Sopenharmony_ci if (!map) { 87662306a36Sopenharmony_ci kfree(em); 87762306a36Sopenharmony_ci test_std_err(TEST_ALLOC_EXTENT_MAP); 87862306a36Sopenharmony_ci return -ENOMEM; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); 88262306a36Sopenharmony_ci /* Start at 4GiB logical address */ 88362306a36Sopenharmony_ci em->start = SZ_4G; 88462306a36Sopenharmony_ci em->len = test->data_stripe_size * test->num_data_stripes; 88562306a36Sopenharmony_ci em->block_len = em->len; 88662306a36Sopenharmony_ci em->orig_block_len = test->data_stripe_size; 88762306a36Sopenharmony_ci em->map_lookup = map; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci map->num_stripes = test->num_stripes; 89062306a36Sopenharmony_ci map->type = test->raid_type; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci for (i = 0; i < map->num_stripes; i++) { 89362306a36Sopenharmony_ci struct btrfs_device *dev = btrfs_alloc_dummy_device(fs_info); 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci if (IS_ERR(dev)) { 89662306a36Sopenharmony_ci test_err("cannot allocate device"); 89762306a36Sopenharmony_ci ret = PTR_ERR(dev); 89862306a36Sopenharmony_ci goto out; 89962306a36Sopenharmony_ci } 90062306a36Sopenharmony_ci map->stripes[i].dev = dev; 90162306a36Sopenharmony_ci map->stripes[i].physical = test->data_stripe_phys_start[i]; 90262306a36Sopenharmony_ci } 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci write_lock(&fs_info->mapping_tree.lock); 90562306a36Sopenharmony_ci ret = add_extent_mapping(&fs_info->mapping_tree, em, 0); 90662306a36Sopenharmony_ci write_unlock(&fs_info->mapping_tree.lock); 90762306a36Sopenharmony_ci if (ret) { 90862306a36Sopenharmony_ci test_err("error adding block group mapping to mapping tree"); 90962306a36Sopenharmony_ci goto out_free; 91062306a36Sopenharmony_ci } 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci ret = btrfs_rmap_block(fs_info, em->start, btrfs_sb_offset(1), 91362306a36Sopenharmony_ci &logical, &out_ndaddrs, &out_stripe_len); 91462306a36Sopenharmony_ci if (ret || (out_ndaddrs == 0 && test->expected_mapped_addr)) { 91562306a36Sopenharmony_ci test_err("didn't rmap anything but expected %d", 91662306a36Sopenharmony_ci test->expected_mapped_addr); 91762306a36Sopenharmony_ci goto out; 91862306a36Sopenharmony_ci } 91962306a36Sopenharmony_ci 92062306a36Sopenharmony_ci if (out_stripe_len != BTRFS_STRIPE_LEN) { 92162306a36Sopenharmony_ci test_err("calculated stripe length doesn't match"); 92262306a36Sopenharmony_ci goto out; 92362306a36Sopenharmony_ci } 92462306a36Sopenharmony_ci 92562306a36Sopenharmony_ci if (out_ndaddrs != test->expected_mapped_addr) { 92662306a36Sopenharmony_ci for (i = 0; i < out_ndaddrs; i++) 92762306a36Sopenharmony_ci test_msg("mapped %llu", logical[i]); 92862306a36Sopenharmony_ci test_err("unexpected number of mapped addresses: %d", out_ndaddrs); 92962306a36Sopenharmony_ci goto out; 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci for (i = 0; i < out_ndaddrs; i++) { 93362306a36Sopenharmony_ci if (logical[i] != test->mapped_logical[i]) { 93462306a36Sopenharmony_ci test_err("unexpected logical address mapped"); 93562306a36Sopenharmony_ci goto out; 93662306a36Sopenharmony_ci } 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci ret = 0; 94062306a36Sopenharmony_ciout: 94162306a36Sopenharmony_ci write_lock(&fs_info->mapping_tree.lock); 94262306a36Sopenharmony_ci remove_extent_mapping(&fs_info->mapping_tree, em); 94362306a36Sopenharmony_ci write_unlock(&fs_info->mapping_tree.lock); 94462306a36Sopenharmony_ci /* For us */ 94562306a36Sopenharmony_ci free_extent_map(em); 94662306a36Sopenharmony_ciout_free: 94762306a36Sopenharmony_ci /* For the tree */ 94862306a36Sopenharmony_ci free_extent_map(em); 94962306a36Sopenharmony_ci kfree(logical); 95062306a36Sopenharmony_ci return ret; 95162306a36Sopenharmony_ci} 95262306a36Sopenharmony_ci 95362306a36Sopenharmony_ciint btrfs_test_extent_map(void) 95462306a36Sopenharmony_ci{ 95562306a36Sopenharmony_ci struct btrfs_fs_info *fs_info = NULL; 95662306a36Sopenharmony_ci struct extent_map_tree *em_tree; 95762306a36Sopenharmony_ci int ret = 0, i; 95862306a36Sopenharmony_ci struct rmap_test_vector rmap_tests[] = { 95962306a36Sopenharmony_ci { 96062306a36Sopenharmony_ci /* 96162306a36Sopenharmony_ci * Test a chunk with 2 data stripes one of which 96262306a36Sopenharmony_ci * intersects the physical address of the super block 96362306a36Sopenharmony_ci * is correctly recognised. 96462306a36Sopenharmony_ci */ 96562306a36Sopenharmony_ci .raid_type = BTRFS_BLOCK_GROUP_RAID1, 96662306a36Sopenharmony_ci .physical_start = SZ_64M - SZ_4M, 96762306a36Sopenharmony_ci .data_stripe_size = SZ_256M, 96862306a36Sopenharmony_ci .num_data_stripes = 2, 96962306a36Sopenharmony_ci .num_stripes = 2, 97062306a36Sopenharmony_ci .data_stripe_phys_start = 97162306a36Sopenharmony_ci {SZ_64M - SZ_4M, SZ_64M - SZ_4M + SZ_256M}, 97262306a36Sopenharmony_ci .expected_mapped_addr = true, 97362306a36Sopenharmony_ci .mapped_logical= {SZ_4G + SZ_4M} 97462306a36Sopenharmony_ci }, 97562306a36Sopenharmony_ci { 97662306a36Sopenharmony_ci /* 97762306a36Sopenharmony_ci * Test that out-of-range physical addresses are 97862306a36Sopenharmony_ci * ignored 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci /* SINGLE chunk type */ 98262306a36Sopenharmony_ci .raid_type = 0, 98362306a36Sopenharmony_ci .physical_start = SZ_4G, 98462306a36Sopenharmony_ci .data_stripe_size = SZ_256M, 98562306a36Sopenharmony_ci .num_data_stripes = 1, 98662306a36Sopenharmony_ci .num_stripes = 1, 98762306a36Sopenharmony_ci .data_stripe_phys_start = {SZ_256M}, 98862306a36Sopenharmony_ci .expected_mapped_addr = false, 98962306a36Sopenharmony_ci .mapped_logical = {0} 99062306a36Sopenharmony_ci } 99162306a36Sopenharmony_ci }; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci test_msg("running extent_map tests"); 99462306a36Sopenharmony_ci 99562306a36Sopenharmony_ci /* 99662306a36Sopenharmony_ci * Note: the fs_info is not set up completely, we only need 99762306a36Sopenharmony_ci * fs_info::fsid for the tracepoint. 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_ci fs_info = btrfs_alloc_dummy_fs_info(PAGE_SIZE, PAGE_SIZE); 100062306a36Sopenharmony_ci if (!fs_info) { 100162306a36Sopenharmony_ci test_std_err(TEST_ALLOC_FS_INFO); 100262306a36Sopenharmony_ci return -ENOMEM; 100362306a36Sopenharmony_ci } 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci em_tree = kzalloc(sizeof(*em_tree), GFP_KERNEL); 100662306a36Sopenharmony_ci if (!em_tree) { 100762306a36Sopenharmony_ci ret = -ENOMEM; 100862306a36Sopenharmony_ci goto out; 100962306a36Sopenharmony_ci } 101062306a36Sopenharmony_ci 101162306a36Sopenharmony_ci extent_map_tree_init(em_tree); 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci ret = test_case_1(fs_info, em_tree); 101462306a36Sopenharmony_ci if (ret) 101562306a36Sopenharmony_ci goto out; 101662306a36Sopenharmony_ci ret = test_case_2(fs_info, em_tree); 101762306a36Sopenharmony_ci if (ret) 101862306a36Sopenharmony_ci goto out; 101962306a36Sopenharmony_ci ret = test_case_3(fs_info, em_tree); 102062306a36Sopenharmony_ci if (ret) 102162306a36Sopenharmony_ci goto out; 102262306a36Sopenharmony_ci ret = test_case_4(fs_info, em_tree); 102362306a36Sopenharmony_ci if (ret) 102462306a36Sopenharmony_ci goto out; 102562306a36Sopenharmony_ci ret = test_case_5(); 102662306a36Sopenharmony_ci if (ret) 102762306a36Sopenharmony_ci goto out; 102862306a36Sopenharmony_ci ret = test_case_6(fs_info, em_tree); 102962306a36Sopenharmony_ci if (ret) 103062306a36Sopenharmony_ci goto out; 103162306a36Sopenharmony_ci ret = test_case_7(); 103262306a36Sopenharmony_ci if (ret) 103362306a36Sopenharmony_ci goto out; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci test_msg("running rmap tests"); 103662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(rmap_tests); i++) { 103762306a36Sopenharmony_ci ret = test_rmap_block(fs_info, &rmap_tests[i]); 103862306a36Sopenharmony_ci if (ret) 103962306a36Sopenharmony_ci goto out; 104062306a36Sopenharmony_ci } 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ciout: 104362306a36Sopenharmony_ci kfree(em_tree); 104462306a36Sopenharmony_ci btrfs_free_dummy_fs_info(fs_info); 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci return ret; 104762306a36Sopenharmony_ci} 1048