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" 972b28077SLiu Bo 1072b28077SLiu Bo static void free_extent_map_tree(struct extent_map_tree *em_tree) 1172b28077SLiu Bo { 1272b28077SLiu Bo struct extent_map *em; 1372b28077SLiu Bo struct rb_node *node; 1472b28077SLiu Bo 1507e1ce09SLiu Bo while (!RB_EMPTY_ROOT(&em_tree->map.rb_root)) { 1607e1ce09SLiu Bo node = rb_first_cached(&em_tree->map); 1772b28077SLiu Bo em = rb_entry(node, struct extent_map, rb_node); 1872b28077SLiu Bo remove_extent_mapping(em_tree, em); 1972b28077SLiu Bo 2072b28077SLiu Bo #ifdef CONFIG_BTRFS_DEBUG 2172b28077SLiu Bo if (refcount_read(&em->refs) != 1) { 223c7251f2SDavid Sterba test_err( 233c7251f2SDavid Sterba "em leak: em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx) refs %d", 2472b28077SLiu Bo em->start, em->len, em->block_start, 2572b28077SLiu Bo em->block_len, refcount_read(&em->refs)); 2672b28077SLiu Bo 2772b28077SLiu Bo refcount_set(&em->refs, 1); 2872b28077SLiu Bo } 2972b28077SLiu Bo #endif 3072b28077SLiu Bo free_extent_map(em); 3172b28077SLiu Bo } 3272b28077SLiu Bo } 3372b28077SLiu Bo 3472b28077SLiu Bo /* 3572b28077SLiu Bo * Test scenario: 3672b28077SLiu Bo * 3772b28077SLiu Bo * Suppose that no extent map has been loaded into memory yet, there is a file 3872b28077SLiu Bo * extent [0, 16K), followed by another file extent [16K, 20K), two dio reads 3972b28077SLiu Bo * are entering btrfs_get_extent() concurrently, t1 is reading [8K, 16K), t2 is 4072b28077SLiu Bo * reading [0, 8K) 4172b28077SLiu Bo * 4272b28077SLiu Bo * t1 t2 4372b28077SLiu Bo * btrfs_get_extent() btrfs_get_extent() 4472b28077SLiu Bo * -> lookup_extent_mapping() ->lookup_extent_mapping() 4572b28077SLiu Bo * -> add_extent_mapping(0, 16K) 4672b28077SLiu Bo * -> return em 4772b28077SLiu Bo * ->add_extent_mapping(0, 16K) 4872b28077SLiu Bo * -> #handle -EEXIST 4972b28077SLiu Bo */ 50488f6730SDavid Sterba static int test_case_1(struct btrfs_fs_info *fs_info, 510e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 5272b28077SLiu Bo { 5372b28077SLiu Bo struct extent_map *em; 5472b28077SLiu Bo u64 start = 0; 5572b28077SLiu Bo u64 len = SZ_8K; 5672b28077SLiu Bo int ret; 5772b28077SLiu Bo 5872b28077SLiu Bo em = alloc_extent_map(); 596c304746SDavid Sterba if (!em) { 606c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 61488f6730SDavid Sterba return -ENOMEM; 626c304746SDavid Sterba } 6372b28077SLiu Bo 6472b28077SLiu Bo /* Add [0, 16K) */ 6572b28077SLiu Bo em->start = 0; 6672b28077SLiu Bo em->len = SZ_16K; 6772b28077SLiu Bo em->block_start = 0; 6872b28077SLiu Bo em->block_len = SZ_16K; 69*93ead46bSDavid Sterba write_lock(&em_tree->lock); 7072b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 71*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 72d7de4b08SDavid Sterba if (ret < 0) { 73d7de4b08SDavid Sterba test_err("cannot add extent range [0, 16K)"); 74d7de4b08SDavid Sterba goto out; 75d7de4b08SDavid Sterba } 7672b28077SLiu Bo free_extent_map(em); 7772b28077SLiu Bo 7872b28077SLiu Bo /* Add [16K, 20K) following [0, 16K) */ 7972b28077SLiu Bo em = alloc_extent_map(); 80488f6730SDavid Sterba if (!em) { 816c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 82488f6730SDavid Sterba ret = -ENOMEM; 8372b28077SLiu Bo goto out; 84488f6730SDavid Sterba } 8572b28077SLiu Bo 8672b28077SLiu Bo em->start = SZ_16K; 8772b28077SLiu Bo em->len = SZ_4K; 8872b28077SLiu Bo em->block_start = SZ_32K; /* avoid merging */ 8972b28077SLiu Bo em->block_len = SZ_4K; 90*93ead46bSDavid Sterba write_lock(&em_tree->lock); 9172b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 92*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 93d7de4b08SDavid Sterba if (ret < 0) { 94d7de4b08SDavid Sterba test_err("cannot add extent range [16K, 20K)"); 95d7de4b08SDavid Sterba goto out; 96d7de4b08SDavid Sterba } 9772b28077SLiu Bo free_extent_map(em); 9872b28077SLiu Bo 9972b28077SLiu Bo em = alloc_extent_map(); 100488f6730SDavid Sterba if (!em) { 1016c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 102488f6730SDavid Sterba ret = -ENOMEM; 10372b28077SLiu Bo goto out; 104488f6730SDavid Sterba } 10572b28077SLiu Bo 10672b28077SLiu Bo /* Add [0, 8K), should return [0, 16K) instead. */ 10772b28077SLiu Bo em->start = start; 10872b28077SLiu Bo em->len = len; 10972b28077SLiu Bo em->block_start = start; 11072b28077SLiu Bo em->block_len = len; 111*93ead46bSDavid Sterba write_lock(&em_tree->lock); 112f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len); 113*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 114d7de4b08SDavid Sterba if (ret) { 1153c7251f2SDavid Sterba test_err("case1 [%llu %llu]: ret %d", start, start + len, ret); 116d7de4b08SDavid Sterba goto out; 117d7de4b08SDavid Sterba } 11872b28077SLiu Bo if (em && 11972b28077SLiu Bo (em->start != 0 || extent_map_end(em) != SZ_16K || 120d7de4b08SDavid Sterba em->block_start != 0 || em->block_len != SZ_16K)) { 1213c7251f2SDavid Sterba test_err( 1223c7251f2SDavid Sterba "case1 [%llu %llu]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu", 12372b28077SLiu Bo start, start + len, ret, em->start, em->len, 12472b28077SLiu Bo em->block_start, em->block_len); 125d7de4b08SDavid Sterba ret = -EINVAL; 126d7de4b08SDavid Sterba } 12772b28077SLiu Bo free_extent_map(em); 12872b28077SLiu Bo out: 12972b28077SLiu Bo free_extent_map_tree(em_tree); 130488f6730SDavid Sterba 131488f6730SDavid Sterba return ret; 13272b28077SLiu Bo } 13372b28077SLiu Bo 13472b28077SLiu Bo /* 13572b28077SLiu Bo * Test scenario: 13672b28077SLiu Bo * 13772b28077SLiu Bo * Reading the inline ending up with EEXIST, ie. read an inline 13872b28077SLiu Bo * extent and discard page cache and read it again. 13972b28077SLiu Bo */ 140488f6730SDavid Sterba static int test_case_2(struct btrfs_fs_info *fs_info, 1410e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 14272b28077SLiu Bo { 14372b28077SLiu Bo struct extent_map *em; 14472b28077SLiu Bo int ret; 14572b28077SLiu Bo 14672b28077SLiu Bo em = alloc_extent_map(); 1476c304746SDavid Sterba if (!em) { 1486c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 149488f6730SDavid Sterba return -ENOMEM; 1506c304746SDavid Sterba } 15172b28077SLiu Bo 15272b28077SLiu Bo /* Add [0, 1K) */ 15372b28077SLiu Bo em->start = 0; 15472b28077SLiu Bo em->len = SZ_1K; 15572b28077SLiu Bo em->block_start = EXTENT_MAP_INLINE; 15672b28077SLiu Bo em->block_len = (u64)-1; 157*93ead46bSDavid Sterba write_lock(&em_tree->lock); 15872b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 159*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 160e71f2e17SDavid Sterba if (ret < 0) { 161e71f2e17SDavid Sterba test_err("cannot add extent range [0, 1K)"); 162e71f2e17SDavid Sterba goto out; 163e71f2e17SDavid Sterba } 16472b28077SLiu Bo free_extent_map(em); 16572b28077SLiu Bo 1663173fd92SDavid Sterba /* Add [4K, 8K) following [0, 1K) */ 16772b28077SLiu Bo em = alloc_extent_map(); 168488f6730SDavid Sterba if (!em) { 1696c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 170488f6730SDavid Sterba ret = -ENOMEM; 17172b28077SLiu Bo goto out; 172488f6730SDavid Sterba } 17372b28077SLiu Bo 17472b28077SLiu Bo em->start = SZ_4K; 17572b28077SLiu Bo em->len = SZ_4K; 17672b28077SLiu Bo em->block_start = SZ_4K; 17772b28077SLiu Bo em->block_len = SZ_4K; 178*93ead46bSDavid Sterba write_lock(&em_tree->lock); 17972b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 180*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 181e71f2e17SDavid Sterba if (ret < 0) { 182e71f2e17SDavid Sterba test_err("cannot add extent range [4K, 8K)"); 183e71f2e17SDavid Sterba goto out; 184e71f2e17SDavid Sterba } 18572b28077SLiu Bo free_extent_map(em); 18672b28077SLiu Bo 18772b28077SLiu Bo em = alloc_extent_map(); 188488f6730SDavid Sterba if (!em) { 1896c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 190488f6730SDavid Sterba ret = -ENOMEM; 19172b28077SLiu Bo goto out; 192488f6730SDavid Sterba } 19372b28077SLiu Bo 19472b28077SLiu Bo /* Add [0, 1K) */ 19572b28077SLiu Bo em->start = 0; 19672b28077SLiu Bo em->len = SZ_1K; 19772b28077SLiu Bo em->block_start = EXTENT_MAP_INLINE; 19872b28077SLiu Bo em->block_len = (u64)-1; 199*93ead46bSDavid Sterba write_lock(&em_tree->lock); 200f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, em->start, em->len); 201*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 202e71f2e17SDavid Sterba if (ret) { 2033c7251f2SDavid Sterba test_err("case2 [0 1K]: ret %d", ret); 204e71f2e17SDavid Sterba goto out; 205e71f2e17SDavid Sterba } 20672b28077SLiu Bo if (em && 20772b28077SLiu Bo (em->start != 0 || extent_map_end(em) != SZ_1K || 208e71f2e17SDavid Sterba em->block_start != EXTENT_MAP_INLINE || em->block_len != (u64)-1)) { 2093c7251f2SDavid Sterba test_err( 2103c7251f2SDavid Sterba "case2 [0 1K]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu", 21172b28077SLiu Bo ret, em->start, em->len, em->block_start, 21272b28077SLiu Bo em->block_len); 213e71f2e17SDavid Sterba ret = -EINVAL; 214e71f2e17SDavid Sterba } 21572b28077SLiu Bo free_extent_map(em); 21672b28077SLiu Bo out: 21772b28077SLiu Bo free_extent_map_tree(em_tree); 218488f6730SDavid Sterba 219488f6730SDavid Sterba return ret; 22072b28077SLiu Bo } 22172b28077SLiu Bo 222488f6730SDavid Sterba static int __test_case_3(struct btrfs_fs_info *fs_info, 2230e08eb9bSDavid Sterba struct extent_map_tree *em_tree, u64 start) 224fd87526fSLiu Bo { 225fd87526fSLiu Bo struct extent_map *em; 226fd87526fSLiu Bo u64 len = SZ_4K; 227fd87526fSLiu Bo int ret; 228fd87526fSLiu Bo 229fd87526fSLiu Bo em = alloc_extent_map(); 2306c304746SDavid Sterba if (!em) { 2316c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 232488f6730SDavid Sterba return -ENOMEM; 2336c304746SDavid Sterba } 234fd87526fSLiu Bo 235fd87526fSLiu Bo /* Add [4K, 8K) */ 236fd87526fSLiu Bo em->start = SZ_4K; 237fd87526fSLiu Bo em->len = SZ_4K; 238fd87526fSLiu Bo em->block_start = SZ_4K; 239fd87526fSLiu Bo em->block_len = SZ_4K; 240*93ead46bSDavid Sterba write_lock(&em_tree->lock); 241fd87526fSLiu Bo ret = add_extent_mapping(em_tree, em, 0); 242*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 243992dce74SDavid Sterba if (ret < 0) { 244992dce74SDavid Sterba test_err("cannot add extent range [4K, 8K)"); 245992dce74SDavid Sterba goto out; 246992dce74SDavid Sterba } 247fd87526fSLiu Bo free_extent_map(em); 248fd87526fSLiu Bo 249fd87526fSLiu Bo em = alloc_extent_map(); 250488f6730SDavid Sterba if (!em) { 2516c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 252488f6730SDavid Sterba ret = -ENOMEM; 253fd87526fSLiu Bo goto out; 254488f6730SDavid Sterba } 255fd87526fSLiu Bo 256fd87526fSLiu Bo /* Add [0, 16K) */ 257fd87526fSLiu Bo em->start = 0; 258fd87526fSLiu Bo em->len = SZ_16K; 259fd87526fSLiu Bo em->block_start = 0; 260fd87526fSLiu Bo em->block_len = SZ_16K; 261*93ead46bSDavid Sterba write_lock(&em_tree->lock); 262f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len); 263*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 264992dce74SDavid Sterba if (ret) { 2653c7251f2SDavid Sterba test_err("case3 [0x%llx 0x%llx): ret %d", 266fd87526fSLiu Bo start, start + len, ret); 267992dce74SDavid Sterba goto out; 268992dce74SDavid Sterba } 269fd87526fSLiu Bo /* 270fd87526fSLiu Bo * Since bytes within em are contiguous, em->block_start is identical to 271fd87526fSLiu Bo * em->start. 272fd87526fSLiu Bo */ 273fd87526fSLiu Bo if (em && 274fd87526fSLiu Bo (start < em->start || start + len > extent_map_end(em) || 275992dce74SDavid Sterba em->start != em->block_start || em->len != em->block_len)) { 2763c7251f2SDavid Sterba test_err( 2773c7251f2SDavid Sterba "case3 [0x%llx 0x%llx): ret %d em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)", 278fd87526fSLiu Bo start, start + len, ret, em->start, em->len, 279fd87526fSLiu Bo em->block_start, em->block_len); 280992dce74SDavid Sterba ret = -EINVAL; 281992dce74SDavid Sterba } 282fd87526fSLiu Bo free_extent_map(em); 283fd87526fSLiu Bo out: 284fd87526fSLiu Bo free_extent_map_tree(em_tree); 285488f6730SDavid Sterba 286488f6730SDavid Sterba return ret; 287fd87526fSLiu Bo } 288fd87526fSLiu Bo 289fd87526fSLiu Bo /* 290fd87526fSLiu Bo * Test scenario: 291fd87526fSLiu Bo * 292fd87526fSLiu Bo * Suppose that no extent map has been loaded into memory yet. 293fd87526fSLiu Bo * There is a file extent [0, 16K), two jobs are running concurrently 294fd87526fSLiu Bo * against it, t1 is buffered writing to [4K, 8K) and t2 is doing dio 295fd87526fSLiu Bo * read from [0, 4K) or [8K, 12K) or [12K, 16K). 296fd87526fSLiu Bo * 297fd87526fSLiu Bo * t1 goes ahead of t2 and adds em [4K, 8K) into tree. 298fd87526fSLiu Bo * 299fd87526fSLiu Bo * t1 t2 300fd87526fSLiu Bo * cow_file_range() btrfs_get_extent() 301fd87526fSLiu Bo * -> lookup_extent_mapping() 302fd87526fSLiu Bo * -> add_extent_mapping() 303fd87526fSLiu Bo * -> add_extent_mapping() 304fd87526fSLiu Bo */ 305ccfada1fSDavid Sterba static int test_case_3(struct btrfs_fs_info *fs_info, 3060e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 307fd87526fSLiu Bo { 308ccfada1fSDavid Sterba int ret; 309ccfada1fSDavid Sterba 310ccfada1fSDavid Sterba ret = __test_case_3(fs_info, em_tree, 0); 311ccfada1fSDavid Sterba if (ret) 312ccfada1fSDavid Sterba return ret; 313ccfada1fSDavid Sterba ret = __test_case_3(fs_info, em_tree, SZ_8K); 314ccfada1fSDavid Sterba if (ret) 315ccfada1fSDavid Sterba return ret; 31643f7cddcSDavid Sterba ret = __test_case_3(fs_info, em_tree, (12 * SZ_1K)); 317ccfada1fSDavid Sterba 318ccfada1fSDavid Sterba return ret; 319fd87526fSLiu Bo } 320fd87526fSLiu Bo 321488f6730SDavid Sterba static int __test_case_4(struct btrfs_fs_info *fs_info, 3220e08eb9bSDavid Sterba struct extent_map_tree *em_tree, u64 start) 323cd77f4f8SLiu Bo { 324cd77f4f8SLiu Bo struct extent_map *em; 325cd77f4f8SLiu Bo u64 len = SZ_4K; 326cd77f4f8SLiu Bo int ret; 327cd77f4f8SLiu Bo 328cd77f4f8SLiu Bo em = alloc_extent_map(); 3296c304746SDavid Sterba if (!em) { 3306c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 331488f6730SDavid Sterba return -ENOMEM; 3326c304746SDavid Sterba } 333cd77f4f8SLiu Bo 334cd77f4f8SLiu Bo /* Add [0K, 8K) */ 335cd77f4f8SLiu Bo em->start = 0; 336cd77f4f8SLiu Bo em->len = SZ_8K; 337cd77f4f8SLiu Bo em->block_start = 0; 338cd77f4f8SLiu Bo em->block_len = SZ_8K; 339*93ead46bSDavid Sterba write_lock(&em_tree->lock); 340cd77f4f8SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 341*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 3427c6f6700SDavid Sterba if (ret < 0) { 3437c6f6700SDavid Sterba test_err("cannot add extent range [0, 8K)"); 3447c6f6700SDavid Sterba goto out; 3457c6f6700SDavid Sterba } 346cd77f4f8SLiu Bo free_extent_map(em); 347cd77f4f8SLiu Bo 348cd77f4f8SLiu Bo em = alloc_extent_map(); 349488f6730SDavid Sterba if (!em) { 3506c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 351488f6730SDavid Sterba ret = -ENOMEM; 352cd77f4f8SLiu Bo goto out; 353488f6730SDavid Sterba } 354cd77f4f8SLiu Bo 3553173fd92SDavid Sterba /* Add [8K, 32K) */ 356cd77f4f8SLiu Bo em->start = SZ_8K; 35743f7cddcSDavid Sterba em->len = 24 * SZ_1K; 358cd77f4f8SLiu Bo em->block_start = SZ_16K; /* avoid merging */ 35943f7cddcSDavid Sterba em->block_len = 24 * SZ_1K; 360*93ead46bSDavid Sterba write_lock(&em_tree->lock); 361cd77f4f8SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 362*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 3637c6f6700SDavid Sterba if (ret < 0) { 3647c6f6700SDavid Sterba test_err("cannot add extent range [8K, 32K)"); 3657c6f6700SDavid Sterba goto out; 3667c6f6700SDavid Sterba } 367cd77f4f8SLiu Bo free_extent_map(em); 368cd77f4f8SLiu Bo 369cd77f4f8SLiu Bo em = alloc_extent_map(); 370488f6730SDavid Sterba if (!em) { 3716c304746SDavid Sterba test_std_err(TEST_ALLOC_EXTENT_MAP); 372488f6730SDavid Sterba ret = -ENOMEM; 373cd77f4f8SLiu Bo goto out; 374488f6730SDavid Sterba } 375cd77f4f8SLiu Bo /* Add [0K, 32K) */ 376cd77f4f8SLiu Bo em->start = 0; 377cd77f4f8SLiu Bo em->len = SZ_32K; 378cd77f4f8SLiu Bo em->block_start = 0; 379cd77f4f8SLiu Bo em->block_len = SZ_32K; 380*93ead46bSDavid Sterba write_lock(&em_tree->lock); 381f46b24c9SDavid Sterba ret = btrfs_add_extent_mapping(fs_info, em_tree, &em, start, len); 382*93ead46bSDavid Sterba write_unlock(&em_tree->lock); 3837c6f6700SDavid Sterba if (ret) { 3843c7251f2SDavid Sterba test_err("case4 [0x%llx 0x%llx): ret %d", 385cd77f4f8SLiu Bo start, len, ret); 3867c6f6700SDavid Sterba goto out; 3877c6f6700SDavid Sterba } 3887c6f6700SDavid Sterba if (em && (start < em->start || start + len > extent_map_end(em))) { 3893c7251f2SDavid Sterba test_err( 3903c7251f2SDavid 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)", 391cd77f4f8SLiu Bo start, len, ret, em->start, em->len, em->block_start, 392cd77f4f8SLiu Bo em->block_len); 3937c6f6700SDavid Sterba ret = -EINVAL; 3947c6f6700SDavid Sterba } 395cd77f4f8SLiu Bo free_extent_map(em); 396cd77f4f8SLiu Bo out: 397cd77f4f8SLiu Bo free_extent_map_tree(em_tree); 398488f6730SDavid Sterba 399488f6730SDavid Sterba return ret; 400cd77f4f8SLiu Bo } 401cd77f4f8SLiu Bo 402cd77f4f8SLiu Bo /* 403cd77f4f8SLiu Bo * Test scenario: 404cd77f4f8SLiu Bo * 405cd77f4f8SLiu Bo * Suppose that no extent map has been loaded into memory yet. 406cd77f4f8SLiu Bo * There is a file extent [0, 32K), two jobs are running concurrently 407cd77f4f8SLiu Bo * against it, t1 is doing dio write to [8K, 32K) and t2 is doing dio 408cd77f4f8SLiu Bo * read from [0, 4K) or [4K, 8K). 409cd77f4f8SLiu Bo * 410cd77f4f8SLiu Bo * t1 goes ahead of t2 and splits em [0, 32K) to em [0K, 8K) and [8K 32K). 411cd77f4f8SLiu Bo * 412cd77f4f8SLiu Bo * t1 t2 413cd77f4f8SLiu Bo * btrfs_get_blocks_direct() btrfs_get_blocks_direct() 414cd77f4f8SLiu Bo * -> btrfs_get_extent() -> btrfs_get_extent() 415cd77f4f8SLiu Bo * -> lookup_extent_mapping() 416cd77f4f8SLiu Bo * -> add_extent_mapping() -> lookup_extent_mapping() 417cd77f4f8SLiu Bo * # load [0, 32K) 418cd77f4f8SLiu Bo * -> btrfs_new_extent_direct() 419cd77f4f8SLiu Bo * -> btrfs_drop_extent_cache() 420cd77f4f8SLiu Bo * # split [0, 32K) 421cd77f4f8SLiu Bo * -> add_extent_mapping() 422cd77f4f8SLiu Bo * # add [8K, 32K) 423cd77f4f8SLiu Bo * -> add_extent_mapping() 424cd77f4f8SLiu Bo * # handle -EEXIST when adding 425cd77f4f8SLiu Bo * # [0, 32K) 426cd77f4f8SLiu Bo */ 427ccfada1fSDavid Sterba static int test_case_4(struct btrfs_fs_info *fs_info, 4280e08eb9bSDavid Sterba struct extent_map_tree *em_tree) 429cd77f4f8SLiu Bo { 430ccfada1fSDavid Sterba int ret; 431ccfada1fSDavid Sterba 432ccfada1fSDavid Sterba ret = __test_case_4(fs_info, em_tree, 0); 433ccfada1fSDavid Sterba if (ret) 434ccfada1fSDavid Sterba return ret; 435ccfada1fSDavid Sterba ret = __test_case_4(fs_info, em_tree, SZ_4K); 436ccfada1fSDavid Sterba 437ccfada1fSDavid Sterba return ret; 438cd77f4f8SLiu Bo } 439cd77f4f8SLiu Bo 44097dc231eSColin Ian King int btrfs_test_extent_map(void) 44172b28077SLiu Bo { 4420e08eb9bSDavid Sterba struct btrfs_fs_info *fs_info = NULL; 44372b28077SLiu Bo struct extent_map_tree *em_tree; 444488f6730SDavid Sterba int ret = 0; 44572b28077SLiu Bo 446315b76b4SDavid Sterba test_msg("running extent_map tests"); 44772b28077SLiu Bo 4480e08eb9bSDavid Sterba /* 4490e08eb9bSDavid Sterba * Note: the fs_info is not set up completely, we only need 4500e08eb9bSDavid Sterba * fs_info::fsid for the tracepoint. 4510e08eb9bSDavid Sterba */ 4520e08eb9bSDavid Sterba fs_info = btrfs_alloc_dummy_fs_info(PAGE_SIZE, PAGE_SIZE); 4530e08eb9bSDavid Sterba if (!fs_info) { 45437b2a7bcSDavid Sterba test_std_err(TEST_ALLOC_FS_INFO); 4550e08eb9bSDavid Sterba return -ENOMEM; 4560e08eb9bSDavid Sterba } 4570e08eb9bSDavid Sterba 45872b28077SLiu Bo em_tree = kzalloc(sizeof(*em_tree), GFP_KERNEL); 459488f6730SDavid Sterba if (!em_tree) { 460488f6730SDavid Sterba ret = -ENOMEM; 4610e08eb9bSDavid Sterba goto out; 462488f6730SDavid Sterba } 46372b28077SLiu Bo 46472b28077SLiu Bo extent_map_tree_init(em_tree); 46572b28077SLiu Bo 466ccfada1fSDavid Sterba ret = test_case_1(fs_info, em_tree); 467ccfada1fSDavid Sterba if (ret) 468ccfada1fSDavid Sterba goto out; 469ccfada1fSDavid Sterba ret = test_case_2(fs_info, em_tree); 470ccfada1fSDavid Sterba if (ret) 471ccfada1fSDavid Sterba goto out; 472ccfada1fSDavid Sterba ret = test_case_3(fs_info, em_tree); 473ccfada1fSDavid Sterba if (ret) 474ccfada1fSDavid Sterba goto out; 475ccfada1fSDavid Sterba ret = test_case_4(fs_info, em_tree); 47672b28077SLiu Bo 4770e08eb9bSDavid Sterba out: 478ccfada1fSDavid Sterba kfree(em_tree); 4790e08eb9bSDavid Sterba btrfs_free_dummy_fs_info(fs_info); 4800e08eb9bSDavid Sterba 481488f6730SDavid Sterba return ret; 48272b28077SLiu Bo } 483