// SPDX-License-Identifier: GPL-2.0 /* * Copyright (C) 2017 Oracle. All rights reserved. */ #include <linux/types.h> #include "btrfs-tests.h" #include "../ctree.h" #include "../btrfs_inode.h" #include "../volumes.h" #include "../disk-io.h" #include "../block-group.h" static int free_extent_map_tree(struct btrfs_inode *inode) { … } /* * Test scenario: * * Suppose that no extent map has been loaded into memory yet, there is a file * extent [0, 16K), followed by another file extent [16K, 20K), two dio reads * are entering btrfs_get_extent() concurrently, t1 is reading [8K, 16K), t2 is * reading [0, 8K) * * t1 t2 * btrfs_get_extent() btrfs_get_extent() * -> lookup_extent_mapping() ->lookup_extent_mapping() * -> add_extent_mapping(0, 16K) * -> return em * ->add_extent_mapping(0, 16K) * -> #handle -EEXIST */ static int test_case_1(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } /* * Test scenario: * * Reading the inline ending up with EEXIST, ie. read an inline * extent and discard page cache and read it again. */ static int test_case_2(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } static int __test_case_3(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode, u64 start) { … } /* * Test scenario: * * Suppose that no extent map has been loaded into memory yet. * There is a file extent [0, 16K), two jobs are running concurrently * against it, t1 is buffered writing to [4K, 8K) and t2 is doing dio * read from [0, 4K) or [8K, 12K) or [12K, 16K). * * t1 goes ahead of t2 and adds em [4K, 8K) into tree. * * t1 t2 * cow_file_range() btrfs_get_extent() * -> lookup_extent_mapping() * -> add_extent_mapping() * -> add_extent_mapping() */ static int test_case_3(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } static int __test_case_4(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode, u64 start) { … } /* * Test scenario: * * Suppose that no extent map has been loaded into memory yet. * There is a file extent [0, 32K), two jobs are running concurrently * against it, t1 is doing dio write to [8K, 32K) and t2 is doing dio * read from [0, 4K) or [4K, 8K). * * t1 goes ahead of t2 and splits em [0, 32K) to em [0K, 8K) and [8K 32K). * * t1 t2 * btrfs_get_blocks_direct() btrfs_get_blocks_direct() * -> btrfs_get_extent() -> btrfs_get_extent() * -> lookup_extent_mapping() * -> add_extent_mapping() -> lookup_extent_mapping() * # load [0, 32K) * -> btrfs_new_extent_direct() * -> btrfs_drop_extent_cache() * # split [0, 32K) * -> add_extent_mapping() * # add [8K, 32K) * -> add_extent_mapping() * # handle -EEXIST when adding * # [0, 32K) */ static int test_case_4(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } static int add_compressed_extent(struct btrfs_inode *inode, u64 start, u64 len, u64 block_start) { … } struct extent_range { … }; /* The valid states of the tree after every drop, as described below. */ struct extent_range valid_ranges[][7] = …; static int validate_range(struct extent_map_tree *em_tree, int index) { … } /* * Test scenario: * * Test the various edge cases of btrfs_drop_extent_map_range, create the * following ranges * * [0, 12k)[12k, 24k)[24k, 36k)[36k, 40k)[40k,64k) * * And then we'll drop: * * [8k, 12k) - test the single front split * [12k, 20k) - test the single back split * [28k, 32k) - test the double split * [32k, 64k) - test whole em dropping * * They'll have the EXTENT_FLAG_COMPRESSED flag set to keep the em tree from * merging the em's. */ static int test_case_5(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } /* * Test the btrfs_add_extent_mapping helper which will attempt to create an em * for areas between two existing ems. Validate it doesn't do this when there * are two unmerged em's side by side. */ static int test_case_6(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } /* * Regression test for btrfs_drop_extent_map_range. Calling with skip_pinned == * true would mess up the start/end calculations and subsequent splits would be * incorrect. */ static int test_case_7(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } /* * Test a regression for compressed extent map adjustment when we attempt to * add an extent map that is partially overlapped by another existing extent * map. The resulting extent map offset was left unchanged despite having * incremented its start offset. */ static int test_case_8(struct btrfs_fs_info *fs_info, struct btrfs_inode *inode) { … } struct rmap_test_vector { … }; static int test_rmap_block(struct btrfs_fs_info *fs_info, struct rmap_test_vector *test) { … } int btrfs_test_extent_map(void) { … }