1c1d7c514SDavid Sterba // SPDX-License-Identifier: GPL-2.0 272b28077SLiu Bo /* 372b28077SLiu Bo * Copyright (C) 2017 Oracle. All rights reserved. 472b28077SLiu Bo */ 572b28077SLiu Bo 672b28077SLiu Bo #include <linux/types.h> 772b28077SLiu Bo #include "btrfs-tests.h" 872b28077SLiu Bo #include "../ctree.h" 9bf2e2eb0SNikolay Borisov #include "../volumes.h" 10bf2e2eb0SNikolay Borisov #include "../disk-io.h" 11bf2e2eb0SNikolay Borisov #include "../block-group.h" 1272b28077SLiu Bo 1372b28077SLiu Bo static void free_extent_map_tree(struct extent_map_tree *em_tree) 1472b28077SLiu Bo { 1572b28077SLiu Bo struct extent_map *em; 1672b28077SLiu Bo struct rb_node *node; 1772b28077SLiu Bo 186d3b050eSFilipe Manana write_lock(&em_tree->lock); 1907e1ce09SLiu Bo while (!RB_EMPTY_ROOT(&em_tree->map.rb_root)) { 2007e1ce09SLiu Bo node = rb_first_cached(&em_tree->map); 2172b28077SLiu Bo em = rb_entry(node, struct extent_map, rb_node); 2272b28077SLiu Bo remove_extent_mapping(em_tree, em); 2372b28077SLiu Bo 2472b28077SLiu Bo #ifdef CONFIG_BTRFS_DEBUG 2572b28077SLiu Bo if (refcount_read(&em->refs) != 1) { 263c7251f2SDavid Sterba test_err( 273c7251f2SDavid Sterba "em leak: em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx) refs %d", 2872b28077SLiu Bo em->start, em->len, em->block_start, 2972b28077SLiu Bo em->block_len, refcount_read(&em->refs)); 3072b28077SLiu Bo 3172b28077SLiu Bo refcount_set(&em->refs, 1); 3272b28077SLiu Bo } 3372b28077SLiu Bo #endif 3472b28077SLiu Bo free_extent_map(em); 3572b28077SLiu Bo } 366d3b050eSFilipe Manana write_unlock(&em_tree->lock); 3772b28077SLiu Bo } 3872b28077SLiu Bo 3972b28077SLiu Bo /* 4072b28077SLiu Bo * Test scenario: 4172b28077SLiu Bo * 4272b28077SLiu Bo * Suppose that no extent map has been loaded into memory yet, there is a file 4372b28077SLiu Bo * extent [0, 16K), followed by another file extent [16K, 20K), two dio reads 4472b28077SLiu Bo * are entering btrfs_get_extent() concurrently, t1 is reading [8K, 16K), t2 is 4572b28077SLiu Bo * reading [0, 8K) 4672b28077SLiu Bo * 4772b28077SLiu Bo * t1 t2 4872b28077SLiu Bo * btrfs_get_extent() btrfs_get_extent() 4972b28077SLiu Bo * -> lookup_extent_mapping() ->lookup_extent_mapping() 5072b28077SLiu Bo * -> add_extent_mapping(0, 16K) 5172b28077SLiu Bo * -> return em 5272b28077SLiu Bo * ->add_extent_mapping(0, 16K) 5372b28077SLiu Bo * -> #handle -EEXIST 5472b28077SLiu Bo */ 55488f6730SDavid Sterba static int test_case_1(struct btrfs_fs_info *fs_info, 560e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 5772b28077SLiu Bo { 5872b28077SLiu Bo struct extent_map *em; 5972b28077SLiu Bo u64 start = 0; 6072b28077SLiu Bo u64 len = SZ_8K; 6172b28077SLiu Bo int ret; 6272b28077SLiu Bo 6372b28077SLiu Bo em = alloc_extent_map(); 646c304746SDavid Sterba if (!em) { 656c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 66488f6730SDavid Sterba return -ENOMEM; 676c304746SDavid Sterba } 6872b28077SLiu Bo 6972b28077SLiu Bo /* Add [0, 16K) */ 7072b28077SLiu Bo em->start = 0; 7172b28077SLiu Bo em->len = SZ_16K; 7272b28077SLiu Bo em->block_start = 0; 7372b28077SLiu Bo em->block_len = SZ_16K; 7493ead46bSDavid Sterba write_lock(&em_tree->lock); 7572b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 7693ead46bSDavid Sterba write_unlock(&em_tree->lock); 77d7de4b08SDavid Sterba if (ret < 0) { 78d7de4b08SDavid Sterba test_err("cannot add extent range [0, 16K)"); 79d7de4b08SDavid Sterba goto out; 80d7de4b08SDavid Sterba } 8172b28077SLiu Bo free_extent_map(em); 8272b28077SLiu Bo 8372b28077SLiu Bo /* Add [16K, 20K) following [0, 16K) */ 8472b28077SLiu Bo em = alloc_extent_map(); 85488f6730SDavid Sterba if (!em) { 866c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 87488f6730SDavid Sterba ret = -ENOMEM; 8872b28077SLiu Bo goto out; 89488f6730SDavid Sterba } 9072b28077SLiu Bo 9172b28077SLiu Bo em->start = SZ_16K; 9272b28077SLiu Bo em->len = SZ_4K; 9372b28077SLiu Bo em->block_start = SZ_32K; /* avoid merging */ 9472b28077SLiu Bo em->block_len = SZ_4K; 9593ead46bSDavid Sterba write_lock(&em_tree->lock); 9672b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 9793ead46bSDavid Sterba write_unlock(&em_tree->lock); 98d7de4b08SDavid Sterba if (ret < 0) { 99d7de4b08SDavid Sterba test_err("cannot add extent range [16K, 20K)"); 100d7de4b08SDavid Sterba goto out; 101d7de4b08SDavid Sterba } 10272b28077SLiu Bo free_extent_map(em); 10372b28077SLiu Bo 10472b28077SLiu Bo em = alloc_extent_map(); 105488f6730SDavid Sterba if (!em) { 1066c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 107488f6730SDavid Sterba ret = -ENOMEM; 10872b28077SLiu Bo goto out; 109488f6730SDavid Sterba } 11072b28077SLiu Bo 11172b28077SLiu Bo /* Add [0, 8K), should return [0, 16K) instead. */ 11272b28077SLiu Bo em->start = start; 11372b28077SLiu Bo em->len = len; 11472b28077SLiu Bo em->block_start = start; 11572b28077SLiu Bo em->block_len = len; 11693ead46bSDavid Sterba write_lock(&em_tree->lock); 117f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len); 11893ead46bSDavid Sterba write_unlock(&em_tree->lock); 119d7de4b08SDavid Sterba if (ret) { 1203c7251f2SDavid Sterba test_err("case1 [%llu %llu]: ret %d", start, start + len, ret); 121d7de4b08SDavid Sterba goto out; 122d7de4b08SDavid Sterba } 12372b28077SLiu Bo if (em && 12472b28077SLiu Bo (em->start != 0 || extent_map_end(em) != SZ_16K || 125d7de4b08SDavid Sterba em->block_start != 0 || em->block_len != SZ_16K)) { 1263c7251f2SDavid Sterba test_err( 1273c7251f2SDavid Sterba "case1 [%llu %llu]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu", 12872b28077SLiu Bo start, start + len, ret, em->start, em->len, 12972b28077SLiu Bo em->block_start, em->block_len); 130d7de4b08SDavid Sterba ret = -EINVAL; 131d7de4b08SDavid Sterba } 13272b28077SLiu Bo free_extent_map(em); 13372b28077SLiu Bo out: 13472b28077SLiu Bo free_extent_map_tree(em_tree); 135488f6730SDavid Sterba 136488f6730SDavid Sterba return ret; 13772b28077SLiu Bo } 13872b28077SLiu Bo 13972b28077SLiu Bo /* 14072b28077SLiu Bo * Test scenario: 14172b28077SLiu Bo * 14272b28077SLiu Bo * Reading the inline ending up with EEXIST, ie. read an inline 14372b28077SLiu Bo * extent and discard page cache and read it again. 14472b28077SLiu Bo */ 145488f6730SDavid Sterba static int test_case_2(struct btrfs_fs_info *fs_info, 1460e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 14772b28077SLiu Bo { 14872b28077SLiu Bo struct extent_map *em; 14972b28077SLiu Bo int ret; 15072b28077SLiu Bo 15172b28077SLiu Bo em = alloc_extent_map(); 1526c304746SDavid Sterba if (!em) { 1536c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 154488f6730SDavid Sterba return -ENOMEM; 1556c304746SDavid Sterba } 15672b28077SLiu Bo 15772b28077SLiu Bo /* Add [0, 1K) */ 15872b28077SLiu Bo em->start = 0; 15972b28077SLiu Bo em->len = SZ_1K; 16072b28077SLiu Bo em->block_start = EXTENT_MAP_INLINE; 16172b28077SLiu Bo em->block_len = (u64)-1; 16293ead46bSDavid Sterba write_lock(&em_tree->lock); 16372b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 16493ead46bSDavid Sterba write_unlock(&em_tree->lock); 165e71f2e17SDavid Sterba if (ret < 0) { 166e71f2e17SDavid Sterba test_err("cannot add extent range [0, 1K)"); 167e71f2e17SDavid Sterba goto out; 168e71f2e17SDavid Sterba } 16972b28077SLiu Bo free_extent_map(em); 17072b28077SLiu Bo 1713173fd92SDavid Sterba /* Add [4K, 8K) following [0, 1K) */ 17272b28077SLiu Bo em = alloc_extent_map(); 173488f6730SDavid Sterba if (!em) { 1746c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 175488f6730SDavid Sterba ret = -ENOMEM; 17672b28077SLiu Bo goto out; 177488f6730SDavid Sterba } 17872b28077SLiu Bo 17972b28077SLiu Bo em->start = SZ_4K; 18072b28077SLiu Bo em->len = SZ_4K; 18172b28077SLiu Bo em->block_start = SZ_4K; 18272b28077SLiu Bo em->block_len = SZ_4K; 18393ead46bSDavid Sterba write_lock(&em_tree->lock); 18472b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 18593ead46bSDavid Sterba write_unlock(&em_tree->lock); 186e71f2e17SDavid Sterba if (ret < 0) { 187e71f2e17SDavid Sterba test_err("cannot add extent range [4K, 8K)"); 188e71f2e17SDavid Sterba goto out; 189e71f2e17SDavid Sterba } 19072b28077SLiu Bo free_extent_map(em); 19172b28077SLiu Bo 19272b28077SLiu Bo em = alloc_extent_map(); 193488f6730SDavid Sterba if (!em) { 1946c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 195488f6730SDavid Sterba ret = -ENOMEM; 19672b28077SLiu Bo goto out; 197488f6730SDavid Sterba } 19872b28077SLiu Bo 19972b28077SLiu Bo /* Add [0, 1K) */ 20072b28077SLiu Bo em->start = 0; 20172b28077SLiu Bo em->len = SZ_1K; 20272b28077SLiu Bo em->block_start = EXTENT_MAP_INLINE; 20372b28077SLiu Bo em->block_len = (u64)-1; 20493ead46bSDavid Sterba write_lock(&em_tree->lock); 205f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len); 20693ead46bSDavid Sterba write_unlock(&em_tree->lock); 207e71f2e17SDavid Sterba if (ret) { 2083c7251f2SDavid Sterba test_err("case2 [0 1K]: ret %d", ret); 209e71f2e17SDavid Sterba goto out; 210e71f2e17SDavid Sterba } 21172b28077SLiu Bo if (em && 21272b28077SLiu Bo (em->start != 0 || extent_map_end(em) != SZ_1K || 213e71f2e17SDavid Sterba em->block_start != EXTENT_MAP_INLINE || em->block_len != (u64)-1)) { 2143c7251f2SDavid Sterba test_err( 2153c7251f2SDavid Sterba "case2 [0 1K]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu", 21672b28077SLiu Bo ret, em->start, em->len, em->block_start, 21772b28077SLiu Bo em->block_len); 218e71f2e17SDavid Sterba ret = -EINVAL; 219e71f2e17SDavid Sterba } 22072b28077SLiu Bo free_extent_map(em); 22172b28077SLiu Bo out: 22272b28077SLiu Bo free_extent_map_tree(em_tree); 223488f6730SDavid Sterba 224488f6730SDavid Sterba return ret; 22572b28077SLiu Bo } 22672b28077SLiu Bo 227488f6730SDavid Sterba static int __test_case_3(struct btrfs_fs_info *fs_info, 2280e08eb9bSDavid Sterba struct extent_map_tree *em_tree, u64 start) 229fd87526fSLiu Bo { 230fd87526fSLiu Bo struct extent_map *em; 231fd87526fSLiu Bo u64 len = SZ_4K; 232fd87526fSLiu Bo int ret; 233fd87526fSLiu Bo 234fd87526fSLiu Bo em = alloc_extent_map(); 2356c304746SDavid Sterba if (!em) { 2366c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 237488f6730SDavid Sterba return -ENOMEM; 2386c304746SDavid Sterba } 239fd87526fSLiu Bo 240fd87526fSLiu Bo /* Add [4K, 8K) */ 241fd87526fSLiu Bo em->start = SZ_4K; 242fd87526fSLiu Bo em->len = SZ_4K; 243fd87526fSLiu Bo em->block_start = SZ_4K; 244fd87526fSLiu Bo em->block_len = SZ_4K; 24593ead46bSDavid Sterba write_lock(&em_tree->lock); 246fd87526fSLiu Bo ret = add_extent_mapping(em_tree, em, 0); 24793ead46bSDavid Sterba write_unlock(&em_tree->lock); 248992dce74SDavid Sterba if (ret < 0) { 249992dce74SDavid Sterba test_err("cannot add extent range [4K, 8K)"); 250992dce74SDavid Sterba goto out; 251992dce74SDavid Sterba } 252fd87526fSLiu Bo free_extent_map(em); 253fd87526fSLiu Bo 254fd87526fSLiu Bo em = alloc_extent_map(); 255488f6730SDavid Sterba if (!em) { 2566c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 257488f6730SDavid Sterba ret = -ENOMEM; 258fd87526fSLiu Bo goto out; 259488f6730SDavid Sterba } 260fd87526fSLiu Bo 261fd87526fSLiu Bo /* Add [0, 16K) */ 262fd87526fSLiu Bo em->start = 0; 263fd87526fSLiu Bo em->len = SZ_16K; 264fd87526fSLiu Bo em->block_start = 0; 265fd87526fSLiu Bo em->block_len = SZ_16K; 26693ead46bSDavid Sterba write_lock(&em_tree->lock); 267f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len); 26893ead46bSDavid Sterba write_unlock(&em_tree->lock); 269992dce74SDavid Sterba if (ret) { 2703c7251f2SDavid Sterba test_err("case3 [0x%llx 0x%llx): ret %d", 271fd87526fSLiu Bo start, start + len, ret); 272992dce74SDavid Sterba goto out; 273992dce74SDavid Sterba } 274fd87526fSLiu Bo /* 275fd87526fSLiu Bo * Since bytes within em are contiguous, em->block_start is identical to 276fd87526fSLiu Bo * em->start. 277fd87526fSLiu Bo */ 278fd87526fSLiu Bo if (em && 279fd87526fSLiu Bo (start < em->start || start + len > extent_map_end(em) || 280992dce74SDavid Sterba em->start != em->block_start || em->len != em->block_len)) { 2813c7251f2SDavid Sterba test_err( 2823c7251f2SDavid Sterba "case3 [0x%llx 0x%llx): ret %d em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)", 283fd87526fSLiu Bo start, start + len, ret, em->start, em->len, 284fd87526fSLiu Bo em->block_start, em->block_len); 285992dce74SDavid Sterba ret = -EINVAL; 286992dce74SDavid Sterba } 287fd87526fSLiu Bo free_extent_map(em); 288fd87526fSLiu Bo out: 289fd87526fSLiu Bo free_extent_map_tree(em_tree); 290488f6730SDavid Sterba 291488f6730SDavid Sterba return ret; 292fd87526fSLiu Bo } 293fd87526fSLiu Bo 294fd87526fSLiu Bo /* 295fd87526fSLiu Bo * Test scenario: 296fd87526fSLiu Bo * 297fd87526fSLiu Bo * Suppose that no extent map has been loaded into memory yet. 298fd87526fSLiu Bo * There is a file extent [0, 16K), two jobs are running concurrently 299fd87526fSLiu Bo * against it, t1 is buffered writing to [4K, 8K) and t2 is doing dio 300fd87526fSLiu Bo * read from [0, 4K) or [8K, 12K) or [12K, 16K). 301fd87526fSLiu Bo * 302fd87526fSLiu Bo * t1 goes ahead of t2 and adds em [4K, 8K) into tree. 303fd87526fSLiu Bo * 304fd87526fSLiu Bo * t1 t2 305fd87526fSLiu Bo * cow_file_range() btrfs_get_extent() 306fd87526fSLiu Bo * -> lookup_extent_mapping() 307fd87526fSLiu Bo * -> add_extent_mapping() 308fd87526fSLiu Bo * -> add_extent_mapping() 309fd87526fSLiu Bo */ 310ccfada1fSDavid Sterba static int test_case_3(struct btrfs_fs_info *fs_info, 3110e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 312fd87526fSLiu Bo { 313ccfada1fSDavid Sterba int ret; 314ccfada1fSDavid Sterba 315ccfada1fSDavid Sterba ret = __test_case_3(fs_info, em_tree, 0); 316ccfada1fSDavid Sterba if (ret) 317ccfada1fSDavid Sterba return ret; 318ccfada1fSDavid Sterba ret = __test_case_3(fs_info, em_tree, SZ_8K); 319ccfada1fSDavid Sterba if (ret) 320ccfada1fSDavid Sterba return ret; 32143f7cddcSDavid Sterba ret = __test_case_3(fs_info, em_tree, (12 * SZ_1K)); 322ccfada1fSDavid Sterba 323ccfada1fSDavid Sterba return ret; 324fd87526fSLiu Bo } 325fd87526fSLiu Bo 326488f6730SDavid Sterba static int __test_case_4(struct btrfs_fs_info *fs_info, 3270e08eb9bSDavid Sterba struct extent_map_tree *em_tree, u64 start) 328cd77f4f8SLiu Bo { 329cd77f4f8SLiu Bo struct extent_map *em; 330cd77f4f8SLiu Bo u64 len = SZ_4K; 331cd77f4f8SLiu Bo int ret; 332cd77f4f8SLiu Bo 333cd77f4f8SLiu Bo em = alloc_extent_map(); 3346c304746SDavid Sterba if (!em) { 3356c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 336488f6730SDavid Sterba return -ENOMEM; 3376c304746SDavid Sterba } 338cd77f4f8SLiu Bo 339cd77f4f8SLiu Bo /* Add [0K, 8K) */ 340cd77f4f8SLiu Bo em->start = 0; 341cd77f4f8SLiu Bo em->len = SZ_8K; 342cd77f4f8SLiu Bo em->block_start = 0; 343cd77f4f8SLiu Bo em->block_len = SZ_8K; 34493ead46bSDavid Sterba write_lock(&em_tree->lock); 345cd77f4f8SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 34693ead46bSDavid Sterba write_unlock(&em_tree->lock); 3477c6f6700SDavid Sterba if (ret < 0) { 3487c6f6700SDavid Sterba test_err("cannot add extent range [0, 8K)"); 3497c6f6700SDavid Sterba goto out; 3507c6f6700SDavid Sterba } 351cd77f4f8SLiu Bo free_extent_map(em); 352cd77f4f8SLiu Bo 353cd77f4f8SLiu Bo em = alloc_extent_map(); 354488f6730SDavid Sterba if (!em) { 3556c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 356488f6730SDavid Sterba ret = -ENOMEM; 357cd77f4f8SLiu Bo goto out; 358488f6730SDavid Sterba } 359cd77f4f8SLiu Bo 3603173fd92SDavid Sterba /* Add [8K, 32K) */ 361cd77f4f8SLiu Bo em->start = SZ_8K; 36243f7cddcSDavid Sterba em->len = 24 * SZ_1K; 363cd77f4f8SLiu Bo em->block_start = SZ_16K; /* avoid merging */ 36443f7cddcSDavid Sterba em->block_len = 24 * SZ_1K; 36593ead46bSDavid Sterba write_lock(&em_tree->lock); 366cd77f4f8SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 36793ead46bSDavid Sterba write_unlock(&em_tree->lock); 3687c6f6700SDavid Sterba if (ret < 0) { 3697c6f6700SDavid Sterba test_err("cannot add extent range [8K, 32K)"); 3707c6f6700SDavid Sterba goto out; 3717c6f6700SDavid Sterba } 372cd77f4f8SLiu Bo free_extent_map(em); 373cd77f4f8SLiu Bo 374cd77f4f8SLiu Bo em = alloc_extent_map(); 375488f6730SDavid Sterba if (!em) { 3766c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 377488f6730SDavid Sterba ret = -ENOMEM; 378cd77f4f8SLiu Bo goto out; 379488f6730SDavid Sterba } 380cd77f4f8SLiu Bo /* Add [0K, 32K) */ 381cd77f4f8SLiu Bo em->start = 0; 382cd77f4f8SLiu Bo em->len = SZ_32K; 383cd77f4f8SLiu Bo em->block_start = 0; 384cd77f4f8SLiu Bo em->block_len = SZ_32K; 38593ead46bSDavid Sterba write_lock(&em_tree->lock); 386f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len); 38793ead46bSDavid Sterba write_unlock(&em_tree->lock); 3887c6f6700SDavid Sterba if (ret) { 3893c7251f2SDavid Sterba test_err("case4 [0x%llx 0x%llx): ret %d", 390cd77f4f8SLiu Bo start, len, ret); 3917c6f6700SDavid Sterba goto out; 3927c6f6700SDavid Sterba } 3937c6f6700SDavid Sterba if (em && (start < em->start || start + len > extent_map_end(em))) { 3943c7251f2SDavid Sterba test_err( 3953c7251f2SDavid Sterba "case4 [0x%llx 0x%llx): ret %d, added wrong em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)", 396cd77f4f8SLiu Bo start, len, ret, em->start, em->len, em->block_start, 397cd77f4f8SLiu Bo em->block_len); 3987c6f6700SDavid Sterba ret = -EINVAL; 3997c6f6700SDavid Sterba } 400cd77f4f8SLiu Bo free_extent_map(em); 401cd77f4f8SLiu Bo out: 402cd77f4f8SLiu Bo free_extent_map_tree(em_tree); 403488f6730SDavid Sterba 404488f6730SDavid Sterba return ret; 405cd77f4f8SLiu Bo } 406cd77f4f8SLiu Bo 407cd77f4f8SLiu Bo /* 408cd77f4f8SLiu Bo * Test scenario: 409cd77f4f8SLiu Bo * 410cd77f4f8SLiu Bo * Suppose that no extent map has been loaded into memory yet. 411cd77f4f8SLiu Bo * There is a file extent [0, 32K), two jobs are running concurrently 412cd77f4f8SLiu Bo * against it, t1 is doing dio write to [8K, 32K) and t2 is doing dio 413cd77f4f8SLiu Bo * read from [0, 4K) or [4K, 8K). 414cd77f4f8SLiu Bo * 415cd77f4f8SLiu Bo * t1 goes ahead of t2 and splits em [0, 32K) to em [0K, 8K) and [8K 32K). 416cd77f4f8SLiu Bo * 417cd77f4f8SLiu Bo * t1 t2 418cd77f4f8SLiu Bo * btrfs_get_blocks_direct() btrfs_get_blocks_direct() 419cd77f4f8SLiu Bo * -> btrfs_get_extent() -> btrfs_get_extent() 420cd77f4f8SLiu Bo * -> lookup_extent_mapping() 421cd77f4f8SLiu Bo * -> add_extent_mapping() -> lookup_extent_mapping() 422cd77f4f8SLiu Bo * # load [0, 32K) 423cd77f4f8SLiu Bo * -> btrfs_new_extent_direct() 424cd77f4f8SLiu Bo * -> btrfs_drop_extent_cache() 425cd77f4f8SLiu Bo * # split [0, 32K) 426cd77f4f8SLiu Bo * -> add_extent_mapping() 427cd77f4f8SLiu Bo * # add [8K, 32K) 428cd77f4f8SLiu Bo * -> add_extent_mapping() 429cd77f4f8SLiu Bo * # handle -EEXIST when adding 430cd77f4f8SLiu Bo * # [0, 32K) 431cd77f4f8SLiu Bo */ 432ccfada1fSDavid Sterba static int test_case_4(struct btrfs_fs_info *fs_info, 4330e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 434cd77f4f8SLiu Bo { 435ccfada1fSDavid Sterba int ret; 436ccfada1fSDavid Sterba 437ccfada1fSDavid Sterba ret = __test_case_4(fs_info, em_tree, 0); 438ccfada1fSDavid Sterba if (ret) 439ccfada1fSDavid Sterba return ret; 440ccfada1fSDavid Sterba ret = __test_case_4(fs_info, em_tree, SZ_4K); 441ccfada1fSDavid Sterba 442ccfada1fSDavid Sterba return ret; 443cd77f4f8SLiu Bo } 444cd77f4f8SLiu Bo 445bf2e2eb0SNikolay Borisov struct rmap_test_vector { 446bf2e2eb0SNikolay Borisov u64 raid_type; 447bf2e2eb0SNikolay Borisov u64 physical_start; 448bf2e2eb0SNikolay Borisov u64 data_stripe_size; 449bf2e2eb0SNikolay Borisov u64 num_data_stripes; 450bf2e2eb0SNikolay Borisov u64 num_stripes; 451bf2e2eb0SNikolay Borisov /* Assume we won't have more than 5 physical stripes */ 452bf2e2eb0SNikolay Borisov u64 data_stripe_phys_start[5]; 453bf2e2eb0SNikolay Borisov bool expected_mapped_addr; 454bf2e2eb0SNikolay Borisov /* Physical to logical addresses */ 455bf2e2eb0SNikolay Borisov u64 mapped_logical[5]; 456bf2e2eb0SNikolay Borisov }; 457bf2e2eb0SNikolay Borisov 458bf2e2eb0SNikolay Borisov static int test_rmap_block(struct btrfs_fs_info *fs_info, 459bf2e2eb0SNikolay Borisov struct rmap_test_vector *test) 460bf2e2eb0SNikolay Borisov { 461bf2e2eb0SNikolay Borisov struct extent_map *em; 462bf2e2eb0SNikolay Borisov struct map_lookup *map = NULL; 463bf2e2eb0SNikolay Borisov u64 *logical = NULL; 464bf2e2eb0SNikolay Borisov int i, out_ndaddrs, out_stripe_len; 465bf2e2eb0SNikolay Borisov int ret; 466bf2e2eb0SNikolay Borisov 467bf2e2eb0SNikolay Borisov em = alloc_extent_map(); 468bf2e2eb0SNikolay Borisov if (!em) { 469bf2e2eb0SNikolay Borisov test_std_err(TEST_ALLOC_EXTENT_MAP); 470bf2e2eb0SNikolay Borisov return -ENOMEM; 471bf2e2eb0SNikolay Borisov } 472bf2e2eb0SNikolay Borisov 473bf2e2eb0SNikolay Borisov map = kmalloc(map_lookup_size(test->num_stripes), GFP_KERNEL); 474bf2e2eb0SNikolay Borisov if (!map) { 475bf2e2eb0SNikolay Borisov kfree(em); 476bf2e2eb0SNikolay Borisov test_std_err(TEST_ALLOC_EXTENT_MAP); 477bf2e2eb0SNikolay Borisov return -ENOMEM; 478bf2e2eb0SNikolay Borisov } 479bf2e2eb0SNikolay Borisov 480bf2e2eb0SNikolay Borisov set_bit(EXTENT_FLAG_FS_MAPPING, &em->flags); 481bf2e2eb0SNikolay Borisov /* Start at 4GiB logical address */ 482bf2e2eb0SNikolay Borisov em->start = SZ_4G; 483bf2e2eb0SNikolay Borisov em->len = test->data_stripe_size * test->num_data_stripes; 484bf2e2eb0SNikolay Borisov em->block_len = em->len; 485bf2e2eb0SNikolay Borisov em->orig_block_len = test->data_stripe_size; 486bf2e2eb0SNikolay Borisov em->map_lookup = map; 487bf2e2eb0SNikolay Borisov 488bf2e2eb0SNikolay Borisov map->num_stripes = test->num_stripes; 489bf2e2eb0SNikolay Borisov map->stripe_len = BTRFS_STRIPE_LEN; 490bf2e2eb0SNikolay Borisov map->type = test->raid_type; 491bf2e2eb0SNikolay Borisov 492bf2e2eb0SNikolay Borisov for (i = 0; i < map->num_stripes; i++) { 493bf2e2eb0SNikolay Borisov struct btrfs_device *dev = btrfs_alloc_dummy_device(fs_info); 494bf2e2eb0SNikolay Borisov 495bf2e2eb0SNikolay Borisov if (IS_ERR(dev)) { 496bf2e2eb0SNikolay Borisov test_err("cannot allocate device"); 497bf2e2eb0SNikolay Borisov ret = PTR_ERR(dev); 498bf2e2eb0SNikolay Borisov goto out; 499bf2e2eb0SNikolay Borisov } 500bf2e2eb0SNikolay Borisov map->stripes[i].dev = dev; 501bf2e2eb0SNikolay Borisov map->stripes[i].physical = test->data_stripe_phys_start[i]; 502bf2e2eb0SNikolay Borisov } 503bf2e2eb0SNikolay Borisov 504bf2e2eb0SNikolay Borisov write_lock(&fs_info->mapping_tree.lock); 505bf2e2eb0SNikolay Borisov ret = add_extent_mapping(&fs_info->mapping_tree, em, 0); 506bf2e2eb0SNikolay Borisov write_unlock(&fs_info->mapping_tree.lock); 507bf2e2eb0SNikolay Borisov if (ret) { 508bf2e2eb0SNikolay Borisov test_err("error adding block group mapping to mapping tree"); 509bf2e2eb0SNikolay Borisov goto out_free; 510bf2e2eb0SNikolay Borisov } 511bf2e2eb0SNikolay Borisov 512*1eb82ef8SChristoph Hellwig ret = btrfs_rmap_block(fs_info, em->start, btrfs_sb_offset(1), 513bf2e2eb0SNikolay Borisov &logical, &out_ndaddrs, &out_stripe_len); 514bf2e2eb0SNikolay Borisov if (ret || (out_ndaddrs == 0 && test->expected_mapped_addr)) { 515bf2e2eb0SNikolay Borisov test_err("didn't rmap anything but expected %d", 516bf2e2eb0SNikolay Borisov test->expected_mapped_addr); 517bf2e2eb0SNikolay Borisov goto out; 518bf2e2eb0SNikolay Borisov } 519bf2e2eb0SNikolay Borisov 520bf2e2eb0SNikolay Borisov if (out_stripe_len != BTRFS_STRIPE_LEN) { 521bf2e2eb0SNikolay Borisov test_err("calculated stripe length doesn't match"); 522bf2e2eb0SNikolay Borisov goto out; 523bf2e2eb0SNikolay Borisov } 524bf2e2eb0SNikolay Borisov 525bf2e2eb0SNikolay Borisov if (out_ndaddrs != test->expected_mapped_addr) { 526bf2e2eb0SNikolay Borisov for (i = 0; i < out_ndaddrs; i++) 527bf2e2eb0SNikolay Borisov test_msg("mapped %llu", logical[i]); 528bf2e2eb0SNikolay Borisov test_err("unexpected number of mapped addresses: %d", out_ndaddrs); 529bf2e2eb0SNikolay Borisov goto out; 530bf2e2eb0SNikolay Borisov } 531bf2e2eb0SNikolay Borisov 532bf2e2eb0SNikolay Borisov for (i = 0; i < out_ndaddrs; i++) { 533bf2e2eb0SNikolay Borisov if (logical[i] != test->mapped_logical[i]) { 534bf2e2eb0SNikolay Borisov test_err("unexpected logical address mapped"); 535bf2e2eb0SNikolay Borisov goto out; 536bf2e2eb0SNikolay Borisov } 537bf2e2eb0SNikolay Borisov } 538bf2e2eb0SNikolay Borisov 539bf2e2eb0SNikolay Borisov ret = 0; 540bf2e2eb0SNikolay Borisov out: 541bf2e2eb0SNikolay Borisov write_lock(&fs_info->mapping_tree.lock); 542bf2e2eb0SNikolay Borisov remove_extent_mapping(&fs_info->mapping_tree, em); 543bf2e2eb0SNikolay Borisov write_unlock(&fs_info->mapping_tree.lock); 544bf2e2eb0SNikolay Borisov /* For us */ 545bf2e2eb0SNikolay Borisov free_extent_map(em); 546bf2e2eb0SNikolay Borisov out_free: 547bf2e2eb0SNikolay Borisov /* For the tree */ 548bf2e2eb0SNikolay Borisov free_extent_map(em); 549bf2e2eb0SNikolay Borisov kfree(logical); 550bf2e2eb0SNikolay Borisov return ret; 551bf2e2eb0SNikolay Borisov } 552bf2e2eb0SNikolay Borisov 55397dc231eSColin Ian King int btrfs_test_extent_map(void) 55472b28077SLiu Bo { 5550e08eb9bSDavid Sterba struct btrfs_fs_info *fs_info = NULL; 55672b28077SLiu Bo struct extent_map_tree *em_tree; 557bf2e2eb0SNikolay Borisov int ret = 0, i; 558bf2e2eb0SNikolay Borisov struct rmap_test_vector rmap_tests[] = { 559bf2e2eb0SNikolay Borisov { 560bf2e2eb0SNikolay Borisov /* 561bf2e2eb0SNikolay Borisov * Test a chunk with 2 data stripes one of which 5621a9fd417SDavid Sterba * intersects the physical address of the super block 563bf2e2eb0SNikolay Borisov * is correctly recognised. 564bf2e2eb0SNikolay Borisov */ 565bf2e2eb0SNikolay Borisov .raid_type = BTRFS_BLOCK_GROUP_RAID1, 566bf2e2eb0SNikolay Borisov .physical_start = SZ_64M - SZ_4M, 567bf2e2eb0SNikolay Borisov .data_stripe_size = SZ_256M, 568bf2e2eb0SNikolay Borisov .num_data_stripes = 2, 569bf2e2eb0SNikolay Borisov .num_stripes = 2, 570bf2e2eb0SNikolay Borisov .data_stripe_phys_start = 571bf2e2eb0SNikolay Borisov {SZ_64M - SZ_4M, SZ_64M - SZ_4M + SZ_256M}, 572bf2e2eb0SNikolay Borisov .expected_mapped_addr = true, 573bf2e2eb0SNikolay Borisov .mapped_logical= {SZ_4G + SZ_4M} 574bf2e2eb0SNikolay Borisov }, 575bf2e2eb0SNikolay Borisov { 576bf2e2eb0SNikolay Borisov /* 577bf2e2eb0SNikolay Borisov * Test that out-of-range physical addresses are 578bf2e2eb0SNikolay Borisov * ignored 579bf2e2eb0SNikolay Borisov */ 580bf2e2eb0SNikolay Borisov 581bf2e2eb0SNikolay Borisov /* SINGLE chunk type */ 582bf2e2eb0SNikolay Borisov .raid_type = 0, 583bf2e2eb0SNikolay Borisov .physical_start = SZ_4G, 584bf2e2eb0SNikolay Borisov .data_stripe_size = SZ_256M, 585bf2e2eb0SNikolay Borisov .num_data_stripes = 1, 586bf2e2eb0SNikolay Borisov .num_stripes = 1, 587bf2e2eb0SNikolay Borisov .data_stripe_phys_start = {SZ_256M}, 588bf2e2eb0SNikolay Borisov .expected_mapped_addr = false, 589bf2e2eb0SNikolay Borisov .mapped_logical = {0} 590bf2e2eb0SNikolay Borisov } 591bf2e2eb0SNikolay Borisov }; 59272b28077SLiu Bo 593315b76b4SDavid Sterba test_msg("running extent_map tests"); 59472b28077SLiu Bo 5950e08eb9bSDavid Sterba /* 5960e08eb9bSDavid Sterba * Note: the fs_info is not set up completely, we only need 5970e08eb9bSDavid Sterba * fs_info::fsid for the tracepoint. 5980e08eb9bSDavid Sterba */ 5990e08eb9bSDavid Sterba fs_info = btrfs_alloc_dummy_fs_info(PAGE_SIZE, PAGE_SIZE); 6000e08eb9bSDavid Sterba if (!fs_info) { 60137b2a7bcSDavid Sterba test_std_err(TEST_ALLOC_FS_INFO); 6020e08eb9bSDavid Sterba return -ENOMEM; 6030e08eb9bSDavid Sterba } 6040e08eb9bSDavid Sterba 60572b28077SLiu Bo em_tree = kzalloc(sizeof(*em_tree), GFP_KERNEL); 606488f6730SDavid Sterba if (!em_tree) { 607488f6730SDavid Sterba ret = -ENOMEM; 6080e08eb9bSDavid Sterba goto out; 609488f6730SDavid Sterba } 61072b28077SLiu Bo 61172b28077SLiu Bo extent_map_tree_init(em_tree); 61272b28077SLiu Bo 613ccfada1fSDavid Sterba ret = test_case_1(fs_info, em_tree); 614ccfada1fSDavid Sterba if (ret) 615ccfada1fSDavid Sterba goto out; 616ccfada1fSDavid Sterba ret = test_case_2(fs_info, em_tree); 617ccfada1fSDavid Sterba if (ret) 618ccfada1fSDavid Sterba goto out; 619ccfada1fSDavid Sterba ret = test_case_3(fs_info, em_tree); 620ccfada1fSDavid Sterba if (ret) 621ccfada1fSDavid Sterba goto out; 622ccfada1fSDavid Sterba ret = test_case_4(fs_info, em_tree); 62372b28077SLiu Bo 624bf2e2eb0SNikolay Borisov test_msg("running rmap tests"); 625bf2e2eb0SNikolay Borisov for (i = 0; i < ARRAY_SIZE(rmap_tests); i++) { 626bf2e2eb0SNikolay Borisov ret = test_rmap_block(fs_info, &rmap_tests[i]); 627bf2e2eb0SNikolay Borisov if (ret) 628bf2e2eb0SNikolay Borisov goto out; 629bf2e2eb0SNikolay Borisov } 630bf2e2eb0SNikolay Borisov 6310e08eb9bSDavid Sterba out: 632ccfada1fSDavid Sterba kfree(em_tree); 6330e08eb9bSDavid Sterba btrfs_free_dummy_fs_info(fs_info); 6340e08eb9bSDavid Sterba 635488f6730SDavid Sterba return ret; 63672b28077SLiu Bo } 637