Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Btrfs: add sanity tests for new qgroup accounting code

This exercises the various parts of the new qgroup accounting code. We do some
basic stuff and do some things with the shared refs to make sure all that code
works. I had to add a bunch of infrastructure because I needed to be able to
insert items into a fake tree without having to do all the hard work myself,
hopefully this will be usefull in the future. Thanks,

Signed-off-by: Josef Bacik <jbacik@fb.com>
Signed-off-by: Chris Mason <clm@fb.com>

authored by

Josef Bacik and committed by
Chris Mason
faa2dbf0 fcebe456

+700 -37
+1 -1
fs/btrfs/Makefile
··· 16 16 17 17 btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \ 18 18 tests/extent-buffer-tests.o tests/btrfs-tests.o \ 19 - tests/extent-io-tests.o tests/inode-tests.o 19 + tests/extent-io-tests.o tests/inode-tests.o tests/qgroup-tests.o
+4
fs/btrfs/backref.c
··· 900 900 goto out; 901 901 BUG_ON(ret == 0); 902 902 903 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 904 + if (trans && likely(trans->type != __TRANS_DUMMY)) { 905 + #else 903 906 if (trans) { 907 + #endif 904 908 /* 905 909 * look if there are updates for this ref queued and lock the 906 910 * head
+4
fs/btrfs/ctree.c
··· 1506 1506 struct btrfs_root *root, 1507 1507 struct extent_buffer *buf) 1508 1508 { 1509 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 1510 + if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) 1511 + return 0; 1512 + #endif 1509 1513 /* ensure we can see the force_cow */ 1510 1514 smp_rmb(); 1511 1515
+6
fs/btrfs/ctree.h
··· 1798 1798 1799 1799 u64 highest_objectid; 1800 1800 1801 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 1802 + u64 alloc_bytenr; 1803 + #endif 1804 + 1801 1805 u64 defrag_trans_start; 1802 1806 struct btrfs_key defrag_progress; 1803 1807 struct btrfs_key defrag_max; ··· 4115 4111 /* Sanity test specific functions */ 4116 4112 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 4117 4113 void btrfs_test_destroy_inode(struct inode *inode); 4114 + int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, 4115 + u64 rfer, u64 excl); 4118 4116 #endif 4119 4117 4120 4118 #endif
+13 -5
fs/btrfs/disk-io.c
··· 1110 1110 struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, 1111 1111 u64 bytenr, u32 blocksize) 1112 1112 { 1113 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 1114 + if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) 1115 + return alloc_test_extent_buffer(root->fs_info, bytenr, 1116 + blocksize); 1117 + #endif 1113 1118 return alloc_extent_buffer(root->fs_info, bytenr, blocksize); 1114 1119 } 1115 1120 ··· 1293 1288 return ERR_PTR(-ENOMEM); 1294 1289 __setup_root(4096, 4096, 4096, 4096, root, NULL, 1); 1295 1290 set_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state); 1291 + root->alloc_bytenr = 0; 1296 1292 1297 1293 return root; 1298 1294 } ··· 2095 2089 free_root_extent_buffers(info->chunk_root); 2096 2090 } 2097 2091 2098 - static void del_fs_roots(struct btrfs_fs_info *fs_info) 2092 + void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info) 2099 2093 { 2100 2094 int ret; 2101 2095 struct btrfs_root *gang[8]; ··· 2975 2969 fail_trans_kthread: 2976 2970 kthread_stop(fs_info->transaction_kthread); 2977 2971 btrfs_cleanup_transaction(fs_info->tree_root); 2978 - del_fs_roots(fs_info); 2972 + btrfs_free_fs_roots(fs_info); 2979 2973 fail_cleaner: 2980 2974 kthread_stop(fs_info->cleaner_kthread); 2981 2975 ··· 3510 3504 if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) 3511 3505 btrfs_free_log(NULL, root); 3512 3506 3513 - __btrfs_remove_free_space_cache(root->free_ino_pinned); 3514 - __btrfs_remove_free_space_cache(root->free_ino_ctl); 3507 + if (root->free_ino_pinned) 3508 + __btrfs_remove_free_space_cache(root->free_ino_pinned); 3509 + if (root->free_ino_ctl) 3510 + __btrfs_remove_free_space_cache(root->free_ino_ctl); 3515 3511 free_fs_root(root); 3516 3512 } 3517 3513 ··· 3663 3655 3664 3656 btrfs_sysfs_remove_one(fs_info); 3665 3657 3666 - del_fs_roots(fs_info); 3658 + btrfs_free_fs_roots(fs_info); 3667 3659 3668 3660 btrfs_put_block_group_cache(fs_info); 3669 3661
+1
fs/btrfs/disk-io.h
··· 68 68 int btrfs_init_fs_root(struct btrfs_root *root); 69 69 int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, 70 70 struct btrfs_root *root); 71 + void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info); 71 72 72 73 struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, 73 74 struct btrfs_key *key,
+17
fs/btrfs/extent-tree.c
··· 2992 2992 int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *, 2993 2993 u64, u64, u64, u64, u64, u64, int); 2994 2994 2995 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 2996 + if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) 2997 + return 0; 2998 + #endif 2995 2999 ref_root = btrfs_header_owner(buf); 2996 3000 nritems = btrfs_header_nritems(buf); 2997 3001 level = btrfs_header_level(buf); ··· 6155 6151 int ret; 6156 6152 struct btrfs_fs_info *fs_info = root->fs_info; 6157 6153 6154 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 6155 + if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) 6156 + return 0; 6157 + #endif 6158 6158 add_pinned_bytes(root->fs_info, num_bytes, owner, root_objectid); 6159 6159 6160 6160 /* ··· 7165 7157 bool skinny_metadata = btrfs_fs_incompat(root->fs_info, 7166 7158 SKINNY_METADATA); 7167 7159 7160 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 7161 + if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) { 7162 + buf = btrfs_init_new_buffer(trans, root, root->alloc_bytenr, 7163 + blocksize, level); 7164 + if (!IS_ERR(buf)) 7165 + root->alloc_bytenr += blocksize; 7166 + return buf; 7167 + } 7168 + #endif 7168 7169 block_rsv = use_block_rsv(trans, root, blocksize); 7169 7170 if (IS_ERR(block_rsv)) 7170 7171 return ERR_CAST(block_rsv);
+47
fs/btrfs/extent_io.c
··· 4549 4549 return NULL; 4550 4550 } 4551 4551 4552 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 4553 + struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, 4554 + u64 start, unsigned long len) 4555 + { 4556 + struct extent_buffer *eb, *exists = NULL; 4557 + int ret; 4558 + 4559 + eb = find_extent_buffer(fs_info, start); 4560 + if (eb) 4561 + return eb; 4562 + eb = alloc_dummy_extent_buffer(start, len); 4563 + if (!eb) 4564 + return NULL; 4565 + eb->fs_info = fs_info; 4566 + again: 4567 + ret = radix_tree_preload(GFP_NOFS & ~__GFP_HIGHMEM); 4568 + if (ret) 4569 + goto free_eb; 4570 + spin_lock(&fs_info->buffer_lock); 4571 + ret = radix_tree_insert(&fs_info->buffer_radix, 4572 + start >> PAGE_CACHE_SHIFT, eb); 4573 + spin_unlock(&fs_info->buffer_lock); 4574 + radix_tree_preload_end(); 4575 + if (ret == -EEXIST) { 4576 + exists = find_extent_buffer(fs_info, start); 4577 + if (exists) 4578 + goto free_eb; 4579 + else 4580 + goto again; 4581 + } 4582 + check_buffer_tree_ref(eb); 4583 + set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags); 4584 + 4585 + /* 4586 + * We will free dummy extent buffer's if they come into 4587 + * free_extent_buffer with a ref count of 2, but if we are using this we 4588 + * want the buffers to stay in memory until we're done with them, so 4589 + * bump the ref count again. 4590 + */ 4591 + atomic_inc(&eb->refs); 4592 + return eb; 4593 + free_eb: 4594 + btrfs_release_extent_buffer(eb); 4595 + return exists; 4596 + } 4597 + #endif 4598 + 4552 4599 struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, 4553 4600 u64 start, unsigned long len) 4554 4601 {
+2
fs/btrfs/extent_io.h
··· 350 350 struct extent_io_tree *tree, 351 351 struct page *locked_page, u64 *start, 352 352 u64 *end, u64 max_bytes); 353 + struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info, 354 + u64 start, unsigned long len); 353 355 #endif 354 356 #endif
+23
fs/btrfs/qgroup.c
··· 246 246 return -ENOENT; 247 247 } 248 248 249 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 250 + int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid, 251 + u64 rfer, u64 excl) 252 + { 253 + struct btrfs_qgroup *qgroup; 254 + 255 + qgroup = find_qgroup_rb(fs_info, qgroupid); 256 + if (!qgroup) 257 + return -EINVAL; 258 + if (qgroup->rfer != rfer || qgroup->excl != excl) 259 + return -EINVAL; 260 + return 0; 261 + } 262 + #endif 263 + 249 264 /* 250 265 * The full config is read in one go, only called from open_ctree() 251 266 * It doesn't use any locking, as at this point we're still single-threaded ··· 539 524 struct extent_buffer *leaf; 540 525 struct btrfs_key key; 541 526 527 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 528 + if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &quota_root->state))) 529 + return 0; 530 + #endif 542 531 path = btrfs_alloc_path(); 543 532 if (!path) 544 533 return -ENOMEM; ··· 692 673 int ret; 693 674 int slot; 694 675 676 + #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 677 + if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) 678 + return 0; 679 + #endif 695 680 key.objectid = 0; 696 681 key.type = BTRFS_QGROUP_INFO_KEY; 697 682 key.offset = qgroup->qgroupid;
+3
fs/btrfs/super.c
··· 1895 1895 if (ret) 1896 1896 goto out; 1897 1897 ret = btrfs_test_inodes(); 1898 + if (ret) 1899 + goto out; 1900 + ret = btrfs_test_qgroups(); 1898 1901 out: 1899 1902 btrfs_destroy_test_fs(); 1900 1903 return ret;
+97
fs/btrfs/tests/btrfs-tests.c
··· 21 21 #include <linux/magic.h> 22 22 #include "btrfs-tests.h" 23 23 #include "../ctree.h" 24 + #include "../volumes.h" 25 + #include "../disk-io.h" 26 + #include "../qgroup.h" 24 27 25 28 static struct vfsmount *test_mnt = NULL; 26 29 ··· 75 72 kern_unmount(test_mnt); 76 73 unregister_filesystem(&test_type); 77 74 } 75 + 76 + struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void) 77 + { 78 + struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info), 79 + GFP_NOFS); 80 + 81 + if (!fs_info) 82 + return fs_info; 83 + fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices), 84 + GFP_NOFS); 85 + if (!fs_info->fs_devices) { 86 + kfree(fs_info); 87 + return NULL; 88 + } 89 + fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block), 90 + GFP_NOFS); 91 + if (!fs_info->super_copy) { 92 + kfree(fs_info->fs_devices); 93 + kfree(fs_info); 94 + return NULL; 95 + } 96 + 97 + if (init_srcu_struct(&fs_info->subvol_srcu)) { 98 + kfree(fs_info->fs_devices); 99 + kfree(fs_info->super_copy); 100 + kfree(fs_info); 101 + return NULL; 102 + } 103 + 104 + spin_lock_init(&fs_info->buffer_lock); 105 + spin_lock_init(&fs_info->qgroup_lock); 106 + spin_lock_init(&fs_info->qgroup_op_lock); 107 + spin_lock_init(&fs_info->super_lock); 108 + spin_lock_init(&fs_info->fs_roots_radix_lock); 109 + spin_lock_init(&fs_info->tree_mod_seq_lock); 110 + mutex_init(&fs_info->qgroup_ioctl_lock); 111 + mutex_init(&fs_info->qgroup_rescan_lock); 112 + rwlock_init(&fs_info->tree_mod_log_lock); 113 + fs_info->running_transaction = NULL; 114 + fs_info->qgroup_tree = RB_ROOT; 115 + fs_info->qgroup_ulist = NULL; 116 + atomic64_set(&fs_info->tree_mod_seq, 0); 117 + INIT_LIST_HEAD(&fs_info->dirty_qgroups); 118 + INIT_LIST_HEAD(&fs_info->dead_roots); 119 + INIT_LIST_HEAD(&fs_info->tree_mod_seq_list); 120 + INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC); 121 + INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); 122 + return fs_info; 123 + } 124 + 125 + static void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info) 126 + { 127 + struct radix_tree_iter iter; 128 + void **slot; 129 + 130 + spin_lock(&fs_info->buffer_lock); 131 + restart: 132 + radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) { 133 + struct extent_buffer *eb; 134 + 135 + eb = radix_tree_deref_slot(slot); 136 + if (!eb) 137 + continue; 138 + /* Shouldn't happen but that kind of thinking creates CVE's */ 139 + if (radix_tree_exception(eb)) { 140 + if (radix_tree_deref_retry(eb)) 141 + goto restart; 142 + continue; 143 + } 144 + spin_unlock(&fs_info->buffer_lock); 145 + free_extent_buffer_stale(eb); 146 + spin_lock(&fs_info->buffer_lock); 147 + } 148 + spin_unlock(&fs_info->buffer_lock); 149 + 150 + btrfs_free_qgroup_config(fs_info); 151 + btrfs_free_fs_roots(fs_info); 152 + cleanup_srcu_struct(&fs_info->subvol_srcu); 153 + kfree(fs_info->super_copy); 154 + kfree(fs_info->fs_devices); 155 + kfree(fs_info); 156 + } 157 + 158 + void btrfs_free_dummy_root(struct btrfs_root *root) 159 + { 160 + if (!root) 161 + return; 162 + if (root->node) 163 + free_extent_buffer(root->node); 164 + if (root->fs_info) 165 + btrfs_free_dummy_fs_info(root->fs_info); 166 + kfree(root); 167 + } 168 +
+9
fs/btrfs/tests/btrfs-tests.h
··· 23 23 24 24 #define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__) 25 25 26 + struct btrfs_root; 27 + 26 28 int btrfs_test_free_space_cache(void); 27 29 int btrfs_test_extent_buffer_operations(void); 28 30 int btrfs_test_extent_io(void); 29 31 int btrfs_test_inodes(void); 32 + int btrfs_test_qgroups(void); 30 33 int btrfs_init_test_fs(void); 31 34 void btrfs_destroy_test_fs(void); 32 35 struct inode *btrfs_new_test_inode(void); 36 + struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void); 37 + void btrfs_free_dummy_root(struct btrfs_root *root); 33 38 #else 34 39 static inline int btrfs_test_free_space_cache(void) 35 40 { ··· 56 51 return 0; 57 52 } 58 53 static inline int btrfs_test_inodes(void) 54 + { 55 + return 0; 56 + } 57 + static inline int btrfs_test_qgroups(void) 59 58 { 60 59 return 0; 61 60 }
+4 -31
fs/btrfs/tests/inode-tests.c
··· 23 23 #include "../extent_io.h" 24 24 #include "../volumes.h" 25 25 26 - static struct btrfs_fs_info *alloc_dummy_fs_info(void) 27 - { 28 - struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info), 29 - GFP_NOFS); 30 - if (!fs_info) 31 - return fs_info; 32 - fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices), 33 - GFP_NOFS); 34 - if (!fs_info->fs_devices) { 35 - kfree(fs_info); 36 - return NULL; 37 - } 38 - return fs_info; 39 - } 40 - static void free_dummy_root(struct btrfs_root *root) 41 - { 42 - if (!root) 43 - return; 44 - if (root->fs_info) { 45 - kfree(root->fs_info->fs_devices); 46 - kfree(root->fs_info); 47 - } 48 - if (root->node) 49 - free_extent_buffer(root->node); 50 - kfree(root); 51 - } 52 - 53 26 static void insert_extent(struct btrfs_root *root, u64 start, u64 len, 54 27 u64 ram_bytes, u64 offset, u64 disk_bytenr, 55 28 u64 disk_len, u32 type, u8 compression, int slot) ··· 249 276 * We do this since btrfs_get_extent wants to assign em->bdev to 250 277 * root->fs_info->fs_devices->latest_bdev. 251 278 */ 252 - root->fs_info = alloc_dummy_fs_info(); 279 + root->fs_info = btrfs_alloc_dummy_fs_info(); 253 280 if (!root->fs_info) { 254 281 test_msg("Couldn't allocate dummy fs info\n"); 255 282 goto out; ··· 810 837 if (!IS_ERR(em)) 811 838 free_extent_map(em); 812 839 iput(inode); 813 - free_dummy_root(root); 840 + btrfs_free_dummy_root(root); 814 841 return ret; 815 842 } 816 843 ··· 837 864 goto out; 838 865 } 839 866 840 - root->fs_info = alloc_dummy_fs_info(); 867 + root->fs_info = btrfs_alloc_dummy_fs_info(); 841 868 if (!root->fs_info) { 842 869 test_msg("Couldn't allocate dummy fs info\n"); 843 870 goto out; ··· 907 934 if (!IS_ERR(em)) 908 935 free_extent_map(em); 909 936 iput(inode); 910 - free_dummy_root(root); 937 + btrfs_free_dummy_root(root); 911 938 return ret; 912 939 } 913 940
+468
fs/btrfs/tests/qgroup-tests.c
··· 1 + /* 2 + * Copyright (C) 2013 Facebook. All rights reserved. 3 + * 4 + * This program is free software; you can redistribute it and/or 5 + * modify it under the terms of the GNU General Public 6 + * License v2 as published by the Free Software Foundation. 7 + * 8 + * This program is distributed in the hope that it will be useful, 9 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 + * General Public License for more details. 12 + * 13 + * You should have received a copy of the GNU General Public 14 + * License along with this program; if not, write to the 15 + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 + * Boston, MA 021110-1307, USA. 17 + */ 18 + 19 + #include "btrfs-tests.h" 20 + #include "../ctree.h" 21 + #include "../transaction.h" 22 + #include "../disk-io.h" 23 + #include "../qgroup.h" 24 + 25 + static void init_dummy_trans(struct btrfs_trans_handle *trans) 26 + { 27 + memset(trans, 0, sizeof(*trans)); 28 + trans->transid = 1; 29 + INIT_LIST_HEAD(&trans->qgroup_ref_list); 30 + trans->type = __TRANS_DUMMY; 31 + } 32 + 33 + static int insert_normal_tree_ref(struct btrfs_root *root, u64 bytenr, 34 + u64 num_bytes, u64 parent, u64 root_objectid) 35 + { 36 + struct btrfs_trans_handle trans; 37 + struct btrfs_extent_item *item; 38 + struct btrfs_extent_inline_ref *iref; 39 + struct btrfs_tree_block_info *block_info; 40 + struct btrfs_path *path; 41 + struct extent_buffer *leaf; 42 + struct btrfs_key ins; 43 + u32 size = sizeof(*item) + sizeof(*iref) + sizeof(*block_info); 44 + int ret; 45 + 46 + init_dummy_trans(&trans); 47 + 48 + ins.objectid = bytenr; 49 + ins.type = BTRFS_EXTENT_ITEM_KEY; 50 + ins.offset = num_bytes; 51 + 52 + path = btrfs_alloc_path(); 53 + if (!path) { 54 + test_msg("Couldn't allocate path\n"); 55 + return -ENOMEM; 56 + } 57 + 58 + path->leave_spinning = 1; 59 + ret = btrfs_insert_empty_item(&trans, root, path, &ins, size); 60 + if (ret) { 61 + test_msg("Couldn't insert ref %d\n", ret); 62 + btrfs_free_path(path); 63 + return ret; 64 + } 65 + 66 + leaf = path->nodes[0]; 67 + item = btrfs_item_ptr(leaf, path->slots[0], struct btrfs_extent_item); 68 + btrfs_set_extent_refs(leaf, item, 1); 69 + btrfs_set_extent_generation(leaf, item, 1); 70 + btrfs_set_extent_flags(leaf, item, BTRFS_EXTENT_FLAG_TREE_BLOCK); 71 + block_info = (struct btrfs_tree_block_info *)(item + 1); 72 + btrfs_set_tree_block_level(leaf, block_info, 1); 73 + iref = (struct btrfs_extent_inline_ref *)(block_info + 1); 74 + if (parent > 0) { 75 + btrfs_set_extent_inline_ref_type(leaf, iref, 76 + BTRFS_SHARED_BLOCK_REF_KEY); 77 + btrfs_set_extent_inline_ref_offset(leaf, iref, parent); 78 + } else { 79 + btrfs_set_extent_inline_ref_type(leaf, iref, BTRFS_TREE_BLOCK_REF_KEY); 80 + btrfs_set_extent_inline_ref_offset(leaf, iref, root_objectid); 81 + } 82 + btrfs_free_path(path); 83 + return 0; 84 + } 85 + 86 + static int add_tree_ref(struct btrfs_root *root, u64 bytenr, u64 num_bytes, 87 + u64 parent, u64 root_objectid) 88 + { 89 + struct btrfs_trans_handle trans; 90 + struct btrfs_extent_item *item; 91 + struct btrfs_path *path; 92 + struct btrfs_key key; 93 + u64 refs; 94 + int ret; 95 + 96 + init_dummy_trans(&trans); 97 + 98 + key.objectid = bytenr; 99 + key.type = BTRFS_EXTENT_ITEM_KEY; 100 + key.offset = num_bytes; 101 + 102 + path = btrfs_alloc_path(); 103 + if (!path) { 104 + test_msg("Couldn't allocate path\n"); 105 + return -ENOMEM; 106 + } 107 + 108 + path->leave_spinning = 1; 109 + ret = btrfs_search_slot(&trans, root, &key, path, 0, 1); 110 + if (ret) { 111 + test_msg("Couldn't find extent ref\n"); 112 + btrfs_free_path(path); 113 + return ret; 114 + } 115 + 116 + item = btrfs_item_ptr(path->nodes[0], path->slots[0], 117 + struct btrfs_extent_item); 118 + refs = btrfs_extent_refs(path->nodes[0], item); 119 + btrfs_set_extent_refs(path->nodes[0], item, refs + 1); 120 + btrfs_release_path(path); 121 + 122 + key.objectid = bytenr; 123 + if (parent) { 124 + key.type = BTRFS_SHARED_BLOCK_REF_KEY; 125 + key.offset = parent; 126 + } else { 127 + key.type = BTRFS_TREE_BLOCK_REF_KEY; 128 + key.offset = root_objectid; 129 + } 130 + 131 + ret = btrfs_insert_empty_item(&trans, root, path, &key, 0); 132 + if (ret) 133 + test_msg("Failed to insert backref\n"); 134 + btrfs_free_path(path); 135 + return ret; 136 + } 137 + 138 + static int remove_extent_item(struct btrfs_root *root, u64 bytenr, 139 + u64 num_bytes) 140 + { 141 + struct btrfs_trans_handle trans; 142 + struct btrfs_key key; 143 + struct btrfs_path *path; 144 + int ret; 145 + 146 + init_dummy_trans(&trans); 147 + 148 + key.objectid = bytenr; 149 + key.type = BTRFS_EXTENT_ITEM_KEY; 150 + key.offset = num_bytes; 151 + 152 + path = btrfs_alloc_path(); 153 + if (!path) { 154 + test_msg("Couldn't allocate path\n"); 155 + return -ENOMEM; 156 + } 157 + path->leave_spinning = 1; 158 + 159 + ret = btrfs_search_slot(&trans, root, &key, path, -1, 1); 160 + if (ret) { 161 + test_msg("Didn't find our key %d\n", ret); 162 + btrfs_free_path(path); 163 + return ret; 164 + } 165 + btrfs_del_item(&trans, root, path); 166 + btrfs_free_path(path); 167 + return 0; 168 + } 169 + 170 + static int remove_extent_ref(struct btrfs_root *root, u64 bytenr, 171 + u64 num_bytes, u64 parent, u64 root_objectid) 172 + { 173 + struct btrfs_trans_handle trans; 174 + struct btrfs_extent_item *item; 175 + struct btrfs_path *path; 176 + struct btrfs_key key; 177 + u64 refs; 178 + int ret; 179 + 180 + init_dummy_trans(&trans); 181 + 182 + key.objectid = bytenr; 183 + key.type = BTRFS_EXTENT_ITEM_KEY; 184 + key.offset = num_bytes; 185 + 186 + path = btrfs_alloc_path(); 187 + if (!path) { 188 + test_msg("Couldn't allocate path\n"); 189 + return -ENOMEM; 190 + } 191 + 192 + path->leave_spinning = 1; 193 + ret = btrfs_search_slot(&trans, root, &key, path, 0, 1); 194 + if (ret) { 195 + test_msg("Couldn't find extent ref\n"); 196 + btrfs_free_path(path); 197 + return ret; 198 + } 199 + 200 + item = btrfs_item_ptr(path->nodes[0], path->slots[0], 201 + struct btrfs_extent_item); 202 + refs = btrfs_extent_refs(path->nodes[0], item); 203 + btrfs_set_extent_refs(path->nodes[0], item, refs - 1); 204 + btrfs_release_path(path); 205 + 206 + key.objectid = bytenr; 207 + if (parent) { 208 + key.type = BTRFS_SHARED_BLOCK_REF_KEY; 209 + key.offset = parent; 210 + } else { 211 + key.type = BTRFS_TREE_BLOCK_REF_KEY; 212 + key.offset = root_objectid; 213 + } 214 + 215 + ret = btrfs_search_slot(&trans, root, &key, path, -1, 1); 216 + if (ret) { 217 + test_msg("Couldn't find backref %d\n", ret); 218 + btrfs_free_path(path); 219 + return ret; 220 + } 221 + btrfs_del_item(&trans, root, path); 222 + btrfs_free_path(path); 223 + return ret; 224 + } 225 + 226 + static int test_no_shared_qgroup(struct btrfs_root *root) 227 + { 228 + struct btrfs_trans_handle trans; 229 + struct btrfs_fs_info *fs_info = root->fs_info; 230 + int ret; 231 + 232 + init_dummy_trans(&trans); 233 + 234 + test_msg("Qgroup basic add\n"); 235 + ret = btrfs_create_qgroup(NULL, fs_info, 5, NULL); 236 + if (ret) { 237 + test_msg("Couldn't create a qgroup %d\n", ret); 238 + return ret; 239 + } 240 + 241 + ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096, 242 + BTRFS_QGROUP_OPER_ADD_EXCL, 0); 243 + if (ret) { 244 + test_msg("Couldn't add space to a qgroup %d\n", ret); 245 + return ret; 246 + } 247 + 248 + ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5); 249 + if (ret) 250 + return ret; 251 + 252 + ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 253 + if (ret) { 254 + test_msg("Delayed qgroup accounting failed %d\n", ret); 255 + return ret; 256 + } 257 + 258 + if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) { 259 + test_msg("Qgroup counts didn't match expected values\n"); 260 + return -EINVAL; 261 + } 262 + 263 + ret = remove_extent_item(root, 4096, 4096); 264 + if (ret) 265 + return -EINVAL; 266 + 267 + ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096, 268 + BTRFS_QGROUP_OPER_SUB_EXCL, 0); 269 + if (ret) { 270 + test_msg("Couldn't remove space from the qgroup %d\n", ret); 271 + return -EINVAL; 272 + } 273 + 274 + ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 275 + if (ret) { 276 + test_msg("Qgroup accounting failed %d\n", ret); 277 + return -EINVAL; 278 + } 279 + 280 + if (btrfs_verify_qgroup_counts(fs_info, 5, 0, 0)) { 281 + test_msg("Qgroup counts didn't match expected values\n"); 282 + return -EINVAL; 283 + } 284 + 285 + return 0; 286 + } 287 + 288 + /* 289 + * Add a ref for two different roots to make sure the shared value comes out 290 + * right, also remove one of the roots and make sure the exclusive count is 291 + * adjusted properly. 292 + */ 293 + static int test_multiple_refs(struct btrfs_root *root) 294 + { 295 + struct btrfs_trans_handle trans; 296 + struct btrfs_fs_info *fs_info = root->fs_info; 297 + int ret; 298 + 299 + init_dummy_trans(&trans); 300 + 301 + test_msg("Qgroup multiple refs test\n"); 302 + 303 + /* We have 5 created already from the previous test */ 304 + ret = btrfs_create_qgroup(NULL, fs_info, 256, NULL); 305 + if (ret) { 306 + test_msg("Couldn't create a qgroup %d\n", ret); 307 + return ret; 308 + } 309 + 310 + ret = insert_normal_tree_ref(root, 4096, 4096, 0, 5); 311 + if (ret) 312 + return ret; 313 + 314 + ret = btrfs_qgroup_record_ref(&trans, fs_info, 5, 4096, 4096, 315 + BTRFS_QGROUP_OPER_ADD_EXCL, 0); 316 + if (ret) { 317 + test_msg("Couldn't add space to a qgroup %d\n", ret); 318 + return ret; 319 + } 320 + 321 + ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 322 + if (ret) { 323 + test_msg("Delayed qgroup accounting failed %d\n", ret); 324 + return ret; 325 + } 326 + 327 + if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) { 328 + test_msg("Qgroup counts didn't match expected values\n"); 329 + return -EINVAL; 330 + } 331 + 332 + ret = add_tree_ref(root, 4096, 4096, 0, 256); 333 + if (ret) 334 + return ret; 335 + 336 + ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096, 337 + BTRFS_QGROUP_OPER_ADD_SHARED, 0); 338 + if (ret) { 339 + test_msg("Qgroup record ref failed %d\n", ret); 340 + return ret; 341 + } 342 + 343 + ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 344 + if (ret) { 345 + test_msg("Qgroup accounting failed %d\n", ret); 346 + return ret; 347 + } 348 + 349 + if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 0)) { 350 + test_msg("Qgroup counts didn't match expected values\n"); 351 + return -EINVAL; 352 + } 353 + 354 + if (btrfs_verify_qgroup_counts(fs_info, 256, 4096, 0)) { 355 + test_msg("Qgroup counts didn't match expected values\n"); 356 + return -EINVAL; 357 + } 358 + 359 + ret = remove_extent_ref(root, 4096, 4096, 0, 256); 360 + if (ret) 361 + return ret; 362 + 363 + ret = btrfs_qgroup_record_ref(&trans, fs_info, 256, 4096, 4096, 364 + BTRFS_QGROUP_OPER_SUB_SHARED, 0); 365 + if (ret) { 366 + test_msg("Qgroup record ref failed %d\n", ret); 367 + return ret; 368 + } 369 + 370 + ret = btrfs_delayed_qgroup_accounting(&trans, fs_info); 371 + if (ret) { 372 + test_msg("Qgroup accounting failed %d\n", ret); 373 + return ret; 374 + } 375 + 376 + if (btrfs_verify_qgroup_counts(fs_info, 256, 0, 0)) { 377 + test_msg("Qgroup counts didn't match expected values\n"); 378 + return -EINVAL; 379 + } 380 + 381 + if (btrfs_verify_qgroup_counts(fs_info, 5, 4096, 4096)) { 382 + test_msg("Qgroup counts didn't match expected values\n"); 383 + return -EINVAL; 384 + } 385 + 386 + return 0; 387 + } 388 + 389 + int btrfs_test_qgroups(void) 390 + { 391 + struct btrfs_root *root; 392 + struct btrfs_root *tmp_root; 393 + int ret = 0; 394 + 395 + root = btrfs_alloc_dummy_root(); 396 + if (IS_ERR(root)) { 397 + test_msg("Couldn't allocate root\n"); 398 + return PTR_ERR(root); 399 + } 400 + 401 + root->fs_info = btrfs_alloc_dummy_fs_info(); 402 + if (!root->fs_info) { 403 + test_msg("Couldn't allocate dummy fs info\n"); 404 + ret = -ENOMEM; 405 + goto out; 406 + } 407 + 408 + /* 409 + * Can't use bytenr 0, some things freak out 410 + * *cough*backref walking code*cough* 411 + */ 412 + root->node = alloc_test_extent_buffer(root->fs_info, 4096, 4096); 413 + if (!root->node) { 414 + test_msg("Couldn't allocate dummy buffer\n"); 415 + ret = -ENOMEM; 416 + goto out; 417 + } 418 + root->alloc_bytenr += 8192; 419 + 420 + tmp_root = btrfs_alloc_dummy_root(); 421 + if (IS_ERR(tmp_root)) { 422 + test_msg("Couldn't allocate a fs root\n"); 423 + ret = PTR_ERR(tmp_root); 424 + goto out; 425 + } 426 + 427 + tmp_root->root_key.objectid = 5; 428 + root->fs_info->fs_root = tmp_root; 429 + ret = btrfs_insert_fs_root(root->fs_info, tmp_root); 430 + if (ret) { 431 + test_msg("Couldn't insert fs root %d\n", ret); 432 + goto out; 433 + } 434 + 435 + tmp_root = btrfs_alloc_dummy_root(); 436 + if (IS_ERR(tmp_root)) { 437 + test_msg("Couldn't allocate a fs root\n"); 438 + ret = PTR_ERR(tmp_root); 439 + goto out; 440 + } 441 + 442 + tmp_root->root_key.objectid = 256; 443 + ret = btrfs_insert_fs_root(root->fs_info, tmp_root); 444 + if (ret) { 445 + test_msg("Couldn't insert fs root %d\n", ret); 446 + goto out; 447 + } 448 + 449 + /* We are using this root as our extent root */ 450 + root->fs_info->extent_root = root; 451 + 452 + /* 453 + * Some of the paths we test assume we have a filled out fs_info, so we 454 + * just need to addt he root in there so we don't panic. 455 + */ 456 + root->fs_info->tree_root = root; 457 + root->fs_info->quota_root = root; 458 + root->fs_info->quota_enabled = 1; 459 + 460 + test_msg("Running qgroup tests\n"); 461 + ret = test_no_shared_qgroup(root); 462 + if (ret) 463 + goto out; 464 + ret = test_multiple_refs(root); 465 + out: 466 + btrfs_free_dummy_root(root); 467 + return ret; 468 + }
+1
fs/btrfs/transaction.h
··· 69 69 #define __TRANS_ATTACH (1U << 10) 70 70 #define __TRANS_JOIN (1U << 11) 71 71 #define __TRANS_JOIN_NOLOCK (1U << 12) 72 + #define __TRANS_DUMMY (1U << 13) 72 73 73 74 #define TRANS_USERSPACE (__TRANS_USERSPACE | __TRANS_FREEZABLE) 74 75 #define TRANS_START (__TRANS_START | __TRANS_FREEZABLE)