1*c1d7c514SDavid 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 1572b28077SLiu Bo while (!RB_EMPTY_ROOT(&em_tree->map)) { 1672b28077SLiu Bo node = rb_first(&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) { 2272b28077SLiu Bo test_msg( 2372b28077SLiu Bo "em leak: em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx) refs %d\n", 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 */ 5072b28077SLiu Bo static void test_case_1(struct extent_map_tree *em_tree) 5172b28077SLiu Bo { 5272b28077SLiu Bo struct extent_map *em; 5372b28077SLiu Bo u64 start = 0; 5472b28077SLiu Bo u64 len = SZ_8K; 5572b28077SLiu Bo int ret; 5672b28077SLiu Bo 5772b28077SLiu Bo em = alloc_extent_map(); 5872b28077SLiu Bo if (!em) 5972b28077SLiu Bo /* Skip the test on error. */ 6072b28077SLiu Bo return; 6172b28077SLiu Bo 6272b28077SLiu Bo /* Add [0, 16K) */ 6372b28077SLiu Bo em->start = 0; 6472b28077SLiu Bo em->len = SZ_16K; 6572b28077SLiu Bo em->block_start = 0; 6672b28077SLiu Bo em->block_len = SZ_16K; 6772b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 6872b28077SLiu Bo ASSERT(ret == 0); 6972b28077SLiu Bo free_extent_map(em); 7072b28077SLiu Bo 7172b28077SLiu Bo /* Add [16K, 20K) following [0, 16K) */ 7272b28077SLiu Bo em = alloc_extent_map(); 7372b28077SLiu Bo if (!em) 7472b28077SLiu Bo goto out; 7572b28077SLiu Bo 7672b28077SLiu Bo em->start = SZ_16K; 7772b28077SLiu Bo em->len = SZ_4K; 7872b28077SLiu Bo em->block_start = SZ_32K; /* avoid merging */ 7972b28077SLiu Bo em->block_len = SZ_4K; 8072b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 8172b28077SLiu Bo ASSERT(ret == 0); 8272b28077SLiu Bo free_extent_map(em); 8372b28077SLiu Bo 8472b28077SLiu Bo em = alloc_extent_map(); 8572b28077SLiu Bo if (!em) 8672b28077SLiu Bo goto out; 8772b28077SLiu Bo 8872b28077SLiu Bo /* Add [0, 8K), should return [0, 16K) instead. */ 8972b28077SLiu Bo em->start = start; 9072b28077SLiu Bo em->len = len; 9172b28077SLiu Bo em->block_start = start; 9272b28077SLiu Bo em->block_len = len; 9372b28077SLiu Bo ret = btrfs_add_extent_mapping(em_tree, &em, em->start, em->len); 9472b28077SLiu Bo if (ret) 9572b28077SLiu Bo test_msg("case1 [%llu %llu]: ret %d\n", start, start + len, ret); 9672b28077SLiu Bo if (em && 9772b28077SLiu Bo (em->start != 0 || extent_map_end(em) != SZ_16K || 9872b28077SLiu Bo em->block_start != 0 || em->block_len != SZ_16K)) 9972b28077SLiu Bo test_msg( 10072b28077SLiu Bo "case1 [%llu %llu]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu\n", 10172b28077SLiu Bo start, start + len, ret, em->start, em->len, 10272b28077SLiu Bo em->block_start, em->block_len); 10372b28077SLiu Bo free_extent_map(em); 10472b28077SLiu Bo out: 10572b28077SLiu Bo /* free memory */ 10672b28077SLiu Bo free_extent_map_tree(em_tree); 10772b28077SLiu Bo } 10872b28077SLiu Bo 10972b28077SLiu Bo /* 11072b28077SLiu Bo * Test scenario: 11172b28077SLiu Bo * 11272b28077SLiu Bo * Reading the inline ending up with EEXIST, ie. read an inline 11372b28077SLiu Bo * extent and discard page cache and read it again. 11472b28077SLiu Bo */ 11572b28077SLiu Bo static void test_case_2(struct extent_map_tree *em_tree) 11672b28077SLiu Bo { 11772b28077SLiu Bo struct extent_map *em; 11872b28077SLiu Bo int ret; 11972b28077SLiu Bo 12072b28077SLiu Bo em = alloc_extent_map(); 12172b28077SLiu Bo if (!em) 12272b28077SLiu Bo /* Skip the test on error. */ 12372b28077SLiu Bo return; 12472b28077SLiu Bo 12572b28077SLiu Bo /* Add [0, 1K) */ 12672b28077SLiu Bo em->start = 0; 12772b28077SLiu Bo em->len = SZ_1K; 12872b28077SLiu Bo em->block_start = EXTENT_MAP_INLINE; 12972b28077SLiu Bo em->block_len = (u64)-1; 13072b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 13172b28077SLiu Bo ASSERT(ret == 0); 13272b28077SLiu Bo free_extent_map(em); 13372b28077SLiu Bo 13472b28077SLiu Bo /* Add [4K, 4K) following [0, 1K) */ 13572b28077SLiu Bo em = alloc_extent_map(); 13672b28077SLiu Bo if (!em) 13772b28077SLiu Bo goto out; 13872b28077SLiu Bo 13972b28077SLiu Bo em->start = SZ_4K; 14072b28077SLiu Bo em->len = SZ_4K; 14172b28077SLiu Bo em->block_start = SZ_4K; 14272b28077SLiu Bo em->block_len = SZ_4K; 14372b28077SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 14472b28077SLiu Bo ASSERT(ret == 0); 14572b28077SLiu Bo free_extent_map(em); 14672b28077SLiu Bo 14772b28077SLiu Bo em = alloc_extent_map(); 14872b28077SLiu Bo if (!em) 14972b28077SLiu Bo goto out; 15072b28077SLiu Bo 15172b28077SLiu Bo /* Add [0, 1K) */ 15272b28077SLiu Bo em->start = 0; 15372b28077SLiu Bo em->len = SZ_1K; 15472b28077SLiu Bo em->block_start = EXTENT_MAP_INLINE; 15572b28077SLiu Bo em->block_len = (u64)-1; 15672b28077SLiu Bo ret = btrfs_add_extent_mapping(em_tree, &em, em->start, em->len); 15772b28077SLiu Bo if (ret) 15872b28077SLiu Bo test_msg("case2 [0 1K]: ret %d\n", ret); 15972b28077SLiu Bo if (em && 16072b28077SLiu Bo (em->start != 0 || extent_map_end(em) != SZ_1K || 16172b28077SLiu Bo em->block_start != EXTENT_MAP_INLINE || em->block_len != (u64)-1)) 16272b28077SLiu Bo test_msg( 16372b28077SLiu Bo "case2 [0 1K]: ret %d return a wrong em (start %llu len %llu block_start %llu block_len %llu\n", 16472b28077SLiu Bo ret, em->start, em->len, em->block_start, 16572b28077SLiu Bo em->block_len); 16672b28077SLiu Bo free_extent_map(em); 16772b28077SLiu Bo out: 16872b28077SLiu Bo /* free memory */ 16972b28077SLiu Bo free_extent_map_tree(em_tree); 17072b28077SLiu Bo } 17172b28077SLiu Bo 172fd87526fSLiu Bo static void __test_case_3(struct extent_map_tree *em_tree, u64 start) 173fd87526fSLiu Bo { 174fd87526fSLiu Bo struct extent_map *em; 175fd87526fSLiu Bo u64 len = SZ_4K; 176fd87526fSLiu Bo int ret; 177fd87526fSLiu Bo 178fd87526fSLiu Bo em = alloc_extent_map(); 179fd87526fSLiu Bo if (!em) 180fd87526fSLiu Bo /* Skip this test on error. */ 181fd87526fSLiu Bo return; 182fd87526fSLiu Bo 183fd87526fSLiu Bo /* Add [4K, 8K) */ 184fd87526fSLiu Bo em->start = SZ_4K; 185fd87526fSLiu Bo em->len = SZ_4K; 186fd87526fSLiu Bo em->block_start = SZ_4K; 187fd87526fSLiu Bo em->block_len = SZ_4K; 188fd87526fSLiu Bo ret = add_extent_mapping(em_tree, em, 0); 189fd87526fSLiu Bo ASSERT(ret == 0); 190fd87526fSLiu Bo free_extent_map(em); 191fd87526fSLiu Bo 192fd87526fSLiu Bo em = alloc_extent_map(); 193fd87526fSLiu Bo if (!em) 194fd87526fSLiu Bo goto out; 195fd87526fSLiu Bo 196fd87526fSLiu Bo /* Add [0, 16K) */ 197fd87526fSLiu Bo em->start = 0; 198fd87526fSLiu Bo em->len = SZ_16K; 199fd87526fSLiu Bo em->block_start = 0; 200fd87526fSLiu Bo em->block_len = SZ_16K; 201fd87526fSLiu Bo ret = btrfs_add_extent_mapping(em_tree, &em, start, len); 202fd87526fSLiu Bo if (ret) 203fd87526fSLiu Bo test_msg("case3 [0x%llx 0x%llx): ret %d\n", 204fd87526fSLiu Bo start, start + len, ret); 205fd87526fSLiu Bo /* 206fd87526fSLiu Bo * Since bytes within em are contiguous, em->block_start is identical to 207fd87526fSLiu Bo * em->start. 208fd87526fSLiu Bo */ 209fd87526fSLiu Bo if (em && 210fd87526fSLiu Bo (start < em->start || start + len > extent_map_end(em) || 211fd87526fSLiu Bo em->start != em->block_start || em->len != em->block_len)) 212fd87526fSLiu Bo test_msg( 213fd87526fSLiu Bo "case3 [0x%llx 0x%llx): ret %d em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)\n", 214fd87526fSLiu Bo start, start + len, ret, em->start, em->len, 215fd87526fSLiu Bo em->block_start, em->block_len); 216fd87526fSLiu Bo free_extent_map(em); 217fd87526fSLiu Bo out: 218fd87526fSLiu Bo /* free memory */ 219fd87526fSLiu Bo free_extent_map_tree(em_tree); 220fd87526fSLiu Bo } 221fd87526fSLiu Bo 222fd87526fSLiu Bo /* 223fd87526fSLiu Bo * Test scenario: 224fd87526fSLiu Bo * 225fd87526fSLiu Bo * Suppose that no extent map has been loaded into memory yet. 226fd87526fSLiu Bo * There is a file extent [0, 16K), two jobs are running concurrently 227fd87526fSLiu Bo * against it, t1 is buffered writing to [4K, 8K) and t2 is doing dio 228fd87526fSLiu Bo * read from [0, 4K) or [8K, 12K) or [12K, 16K). 229fd87526fSLiu Bo * 230fd87526fSLiu Bo * t1 goes ahead of t2 and adds em [4K, 8K) into tree. 231fd87526fSLiu Bo * 232fd87526fSLiu Bo * t1 t2 233fd87526fSLiu Bo * cow_file_range() btrfs_get_extent() 234fd87526fSLiu Bo * -> lookup_extent_mapping() 235fd87526fSLiu Bo * -> add_extent_mapping() 236fd87526fSLiu Bo * -> add_extent_mapping() 237fd87526fSLiu Bo */ 238fd87526fSLiu Bo static void test_case_3(struct extent_map_tree *em_tree) 239fd87526fSLiu Bo { 240fd87526fSLiu Bo __test_case_3(em_tree, 0); 241fd87526fSLiu Bo __test_case_3(em_tree, SZ_8K); 242fd87526fSLiu Bo __test_case_3(em_tree, (12 * 1024ULL)); 243fd87526fSLiu Bo } 244fd87526fSLiu Bo 245cd77f4f8SLiu Bo static void __test_case_4(struct extent_map_tree *em_tree, u64 start) 246cd77f4f8SLiu Bo { 247cd77f4f8SLiu Bo struct extent_map *em; 248cd77f4f8SLiu Bo u64 len = SZ_4K; 249cd77f4f8SLiu Bo int ret; 250cd77f4f8SLiu Bo 251cd77f4f8SLiu Bo em = alloc_extent_map(); 252cd77f4f8SLiu Bo if (!em) 253cd77f4f8SLiu Bo /* Skip this test on error. */ 254cd77f4f8SLiu Bo return; 255cd77f4f8SLiu Bo 256cd77f4f8SLiu Bo /* Add [0K, 8K) */ 257cd77f4f8SLiu Bo em->start = 0; 258cd77f4f8SLiu Bo em->len = SZ_8K; 259cd77f4f8SLiu Bo em->block_start = 0; 260cd77f4f8SLiu Bo em->block_len = SZ_8K; 261cd77f4f8SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 262cd77f4f8SLiu Bo ASSERT(ret == 0); 263cd77f4f8SLiu Bo free_extent_map(em); 264cd77f4f8SLiu Bo 265cd77f4f8SLiu Bo em = alloc_extent_map(); 266cd77f4f8SLiu Bo if (!em) 267cd77f4f8SLiu Bo goto out; 268cd77f4f8SLiu Bo 269cd77f4f8SLiu Bo /* Add [8K, 24K) */ 270cd77f4f8SLiu Bo em->start = SZ_8K; 271cd77f4f8SLiu Bo em->len = 24 * 1024ULL; 272cd77f4f8SLiu Bo em->block_start = SZ_16K; /* avoid merging */ 273cd77f4f8SLiu Bo em->block_len = 24 * 1024ULL; 274cd77f4f8SLiu Bo ret = add_extent_mapping(em_tree, em, 0); 275cd77f4f8SLiu Bo ASSERT(ret == 0); 276cd77f4f8SLiu Bo free_extent_map(em); 277cd77f4f8SLiu Bo 278cd77f4f8SLiu Bo em = alloc_extent_map(); 279cd77f4f8SLiu Bo if (!em) 280cd77f4f8SLiu Bo goto out; 281cd77f4f8SLiu Bo /* Add [0K, 32K) */ 282cd77f4f8SLiu Bo em->start = 0; 283cd77f4f8SLiu Bo em->len = SZ_32K; 284cd77f4f8SLiu Bo em->block_start = 0; 285cd77f4f8SLiu Bo em->block_len = SZ_32K; 286cd77f4f8SLiu Bo ret = btrfs_add_extent_mapping(em_tree, &em, start, len); 287cd77f4f8SLiu Bo if (ret) 288cd77f4f8SLiu Bo test_msg("case4 [0x%llx 0x%llx): ret %d\n", 289cd77f4f8SLiu Bo start, len, ret); 290cd77f4f8SLiu Bo if (em && 291cd77f4f8SLiu Bo (start < em->start || start + len > extent_map_end(em))) 292cd77f4f8SLiu Bo test_msg( 293cd77f4f8SLiu Bo "case4 [0x%llx 0x%llx): ret %d, added wrong em (start 0x%llx len 0x%llx block_start 0x%llx block_len 0x%llx)\n", 294cd77f4f8SLiu Bo start, len, ret, em->start, em->len, em->block_start, 295cd77f4f8SLiu Bo em->block_len); 296cd77f4f8SLiu Bo free_extent_map(em); 297cd77f4f8SLiu Bo out: 298cd77f4f8SLiu Bo /* free memory */ 299cd77f4f8SLiu Bo free_extent_map_tree(em_tree); 300cd77f4f8SLiu Bo } 301cd77f4f8SLiu Bo 302cd77f4f8SLiu Bo /* 303cd77f4f8SLiu Bo * Test scenario: 304cd77f4f8SLiu Bo * 305cd77f4f8SLiu Bo * Suppose that no extent map has been loaded into memory yet. 306cd77f4f8SLiu Bo * There is a file extent [0, 32K), two jobs are running concurrently 307cd77f4f8SLiu Bo * against it, t1 is doing dio write to [8K, 32K) and t2 is doing dio 308cd77f4f8SLiu Bo * read from [0, 4K) or [4K, 8K). 309cd77f4f8SLiu Bo * 310cd77f4f8SLiu Bo * t1 goes ahead of t2 and splits em [0, 32K) to em [0K, 8K) and [8K 32K). 311cd77f4f8SLiu Bo * 312cd77f4f8SLiu Bo * t1 t2 313cd77f4f8SLiu Bo * btrfs_get_blocks_direct() btrfs_get_blocks_direct() 314cd77f4f8SLiu Bo * -> btrfs_get_extent() -> btrfs_get_extent() 315cd77f4f8SLiu Bo * -> lookup_extent_mapping() 316cd77f4f8SLiu Bo * -> add_extent_mapping() -> lookup_extent_mapping() 317cd77f4f8SLiu Bo * # load [0, 32K) 318cd77f4f8SLiu Bo * -> btrfs_new_extent_direct() 319cd77f4f8SLiu Bo * -> btrfs_drop_extent_cache() 320cd77f4f8SLiu Bo * # split [0, 32K) 321cd77f4f8SLiu Bo * -> add_extent_mapping() 322cd77f4f8SLiu Bo * # add [8K, 32K) 323cd77f4f8SLiu Bo * -> add_extent_mapping() 324cd77f4f8SLiu Bo * # handle -EEXIST when adding 325cd77f4f8SLiu Bo * # [0, 32K) 326cd77f4f8SLiu Bo */ 327cd77f4f8SLiu Bo static void test_case_4(struct extent_map_tree *em_tree) 328cd77f4f8SLiu Bo { 329cd77f4f8SLiu Bo __test_case_4(em_tree, 0); 330cd77f4f8SLiu Bo __test_case_4(em_tree, SZ_4K); 331cd77f4f8SLiu Bo } 332cd77f4f8SLiu Bo 33397dc231eSColin Ian King int btrfs_test_extent_map(void) 33472b28077SLiu Bo { 33572b28077SLiu Bo struct extent_map_tree *em_tree; 33672b28077SLiu Bo 33772b28077SLiu Bo test_msg("Running extent_map tests\n"); 33872b28077SLiu Bo 33972b28077SLiu Bo em_tree = kzalloc(sizeof(*em_tree), GFP_KERNEL); 34072b28077SLiu Bo if (!em_tree) 34172b28077SLiu Bo /* Skip the test on error. */ 34272b28077SLiu Bo return 0; 34372b28077SLiu Bo 34472b28077SLiu Bo extent_map_tree_init(em_tree); 34572b28077SLiu Bo 34672b28077SLiu Bo test_case_1(em_tree); 34772b28077SLiu Bo test_case_2(em_tree); 348fd87526fSLiu Bo test_case_3(em_tree); 349cd77f4f8SLiu Bo test_case_4(em_tree); 35072b28077SLiu Bo 35172b28077SLiu Bo kfree(em_tree); 35272b28077SLiu Bo return 0; 35372b28077SLiu Bo } 354