aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosef Bacik <jbacik@fb.com>2014-05-07 17:06:09 -0400
committerChris Mason <clm@fb.com>2014-06-09 20:20:49 -0400
commitfaa2dbf004e89e8f7ccd28fbe6f07c308417b8ae (patch)
treeb700876fe08b8830d4e8686c039f4241cc9cb5e2
parentfcebe4562dec83b3f8d3088d77584727b09130b2 (diff)
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>
-rw-r--r--fs/btrfs/Makefile2
-rw-r--r--fs/btrfs/backref.c4
-rw-r--r--fs/btrfs/ctree.c4
-rw-r--r--fs/btrfs/ctree.h6
-rw-r--r--fs/btrfs/disk-io.c18
-rw-r--r--fs/btrfs/disk-io.h1
-rw-r--r--fs/btrfs/extent-tree.c17
-rw-r--r--fs/btrfs/extent_io.c47
-rw-r--r--fs/btrfs/extent_io.h2
-rw-r--r--fs/btrfs/qgroup.c23
-rw-r--r--fs/btrfs/super.c3
-rw-r--r--fs/btrfs/tests/btrfs-tests.c97
-rw-r--r--fs/btrfs/tests/btrfs-tests.h9
-rw-r--r--fs/btrfs/tests/inode-tests.c35
-rw-r--r--fs/btrfs/tests/qgroup-tests.c468
-rw-r--r--fs/btrfs/transaction.h1
16 files changed, 700 insertions, 37 deletions
diff --git a/fs/btrfs/Makefile b/fs/btrfs/Makefile
index f341a98031d2..6d1d0b93b1aa 100644
--- a/fs/btrfs/Makefile
+++ b/fs/btrfs/Makefile
@@ -16,4 +16,4 @@ btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
16 16
17btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \ 17btrfs-$(CONFIG_BTRFS_FS_RUN_SANITY_TESTS) += tests/free-space-tests.o \
18 tests/extent-buffer-tests.o tests/btrfs-tests.o \ 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
diff --git a/fs/btrfs/backref.c b/fs/btrfs/backref.c
index 10db21fa0926..f09aa18ab710 100644
--- a/fs/btrfs/backref.c
+++ b/fs/btrfs/backref.c
@@ -900,7 +900,11 @@ again:
900 goto out; 900 goto out;
901 BUG_ON(ret == 0); 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 if (trans) { 906 if (trans) {
907#endif
904 /* 908 /*
905 * look if there are updates for this ref queued and lock the 909 * look if there are updates for this ref queued and lock the
906 * head 910 * head
diff --git a/fs/btrfs/ctree.c b/fs/btrfs/ctree.c
index bbbe4f1c5086..d99d9651dd58 100644
--- a/fs/btrfs/ctree.c
+++ b/fs/btrfs/ctree.c
@@ -1506,6 +1506,10 @@ static inline int should_cow_block(struct btrfs_trans_handle *trans,
1506 struct btrfs_root *root, 1506 struct btrfs_root *root,
1507 struct extent_buffer *buf) 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 /* ensure we can see the force_cow */ 1513 /* ensure we can see the force_cow */
1510 smp_rmb(); 1514 smp_rmb();
1511 1515
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 06cc384933cc..4896d7a947eb 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -1798,6 +1798,10 @@ struct btrfs_root {
1798 1798
1799 u64 highest_objectid; 1799 u64 highest_objectid;
1800 1800
1801#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
1802 u64 alloc_bytenr;
1803#endif
1804
1801 u64 defrag_trans_start; 1805 u64 defrag_trans_start;
1802 struct btrfs_key defrag_progress; 1806 struct btrfs_key defrag_progress;
1803 struct btrfs_key defrag_max; 1807 struct btrfs_key defrag_max;
@@ -4111,6 +4115,8 @@ static inline int btrfs_defrag_cancelled(struct btrfs_fs_info *fs_info)
4111/* Sanity test specific functions */ 4115/* Sanity test specific functions */
4112#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS 4116#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
4113void btrfs_test_destroy_inode(struct inode *inode); 4117void btrfs_test_destroy_inode(struct inode *inode);
4118int btrfs_verify_qgroup_counts(struct btrfs_fs_info *fs_info, u64 qgroupid,
4119 u64 rfer, u64 excl);
4114#endif 4120#endif
4115 4121
4116#endif 4122#endif
diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 77f92a32e230..0c0fa78ef452 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -1110,6 +1110,11 @@ struct extent_buffer *btrfs_find_tree_block(struct btrfs_root *root,
1110struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root, 1110struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
1111 u64 bytenr, u32 blocksize) 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 return alloc_extent_buffer(root->fs_info, bytenr, blocksize); 1118 return alloc_extent_buffer(root->fs_info, bytenr, blocksize);
1114} 1119}
1115 1120
@@ -1288,6 +1293,7 @@ struct btrfs_root *btrfs_alloc_dummy_root(void)
1288 return ERR_PTR(-ENOMEM); 1293 return ERR_PTR(-ENOMEM);
1289 __setup_root(4096, 4096, 4096, 4096, root, NULL, 1); 1294 __setup_root(4096, 4096, 4096, 4096, root, NULL, 1);
1290 set_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state); 1295 set_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state);
1296 root->alloc_bytenr = 0;
1291 1297
1292 return root; 1298 return root;
1293} 1299}
@@ -2089,7 +2095,7 @@ static void free_root_pointers(struct btrfs_fs_info *info, int chunk_root)
2089 free_root_extent_buffers(info->chunk_root); 2095 free_root_extent_buffers(info->chunk_root);
2090} 2096}
2091 2097
2092static void del_fs_roots(struct btrfs_fs_info *fs_info) 2098void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info)
2093{ 2099{
2094 int ret; 2100 int ret;
2095 struct btrfs_root *gang[8]; 2101 struct btrfs_root *gang[8];
@@ -2969,7 +2975,7 @@ fail_qgroup:
2969fail_trans_kthread: 2975fail_trans_kthread:
2970 kthread_stop(fs_info->transaction_kthread); 2976 kthread_stop(fs_info->transaction_kthread);
2971 btrfs_cleanup_transaction(fs_info->tree_root); 2977 btrfs_cleanup_transaction(fs_info->tree_root);
2972 del_fs_roots(fs_info); 2978 btrfs_free_fs_roots(fs_info);
2973fail_cleaner: 2979fail_cleaner:
2974 kthread_stop(fs_info->cleaner_kthread); 2980 kthread_stop(fs_info->cleaner_kthread);
2975 2981
@@ -3504,8 +3510,10 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
3504 if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) 3510 if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
3505 btrfs_free_log(NULL, root); 3511 btrfs_free_log(NULL, root);
3506 3512
3507 __btrfs_remove_free_space_cache(root->free_ino_pinned); 3513 if (root->free_ino_pinned)
3508 __btrfs_remove_free_space_cache(root->free_ino_ctl); 3514 __btrfs_remove_free_space_cache(root->free_ino_pinned);
3515 if (root->free_ino_ctl)
3516 __btrfs_remove_free_space_cache(root->free_ino_ctl);
3509 free_fs_root(root); 3517 free_fs_root(root);
3510} 3518}
3511 3519
@@ -3655,7 +3663,7 @@ int close_ctree(struct btrfs_root *root)
3655 3663
3656 btrfs_sysfs_remove_one(fs_info); 3664 btrfs_sysfs_remove_one(fs_info);
3657 3665
3658 del_fs_roots(fs_info); 3666 btrfs_free_fs_roots(fs_info);
3659 3667
3660 btrfs_put_block_group_cache(fs_info); 3668 btrfs_put_block_group_cache(fs_info);
3661 3669
diff --git a/fs/btrfs/disk-io.h b/fs/btrfs/disk-io.h
index 53059df350f8..23ce3ceba0a9 100644
--- a/fs/btrfs/disk-io.h
+++ b/fs/btrfs/disk-io.h
@@ -68,6 +68,7 @@ struct btrfs_root *btrfs_read_fs_root(struct btrfs_root *tree_root,
68int btrfs_init_fs_root(struct btrfs_root *root); 68int btrfs_init_fs_root(struct btrfs_root *root);
69int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info, 69int btrfs_insert_fs_root(struct btrfs_fs_info *fs_info,
70 struct btrfs_root *root); 70 struct btrfs_root *root);
71void btrfs_free_fs_roots(struct btrfs_fs_info *fs_info);
71 72
72struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info, 73struct btrfs_root *btrfs_get_fs_root(struct btrfs_fs_info *fs_info,
73 struct btrfs_key *key, 74 struct btrfs_key *key,
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c
index 343eb10230a1..ddf16bfb9270 100644
--- a/fs/btrfs/extent-tree.c
+++ b/fs/btrfs/extent-tree.c
@@ -2992,6 +2992,10 @@ static int __btrfs_mod_ref(struct btrfs_trans_handle *trans,
2992 int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *, 2992 int (*process_func)(struct btrfs_trans_handle *, struct btrfs_root *,
2993 u64, u64, u64, u64, u64, u64, int); 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 ref_root = btrfs_header_owner(buf); 2999 ref_root = btrfs_header_owner(buf);
2996 nritems = btrfs_header_nritems(buf); 3000 nritems = btrfs_header_nritems(buf);
2997 level = btrfs_header_level(buf); 3001 level = btrfs_header_level(buf);
@@ -6151,6 +6155,10 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root *root,
6151 int ret; 6155 int ret;
6152 struct btrfs_fs_info *fs_info = root->fs_info; 6156 struct btrfs_fs_info *fs_info = root->fs_info;
6153 6157
6158#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
6159 if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
6160 return 0;
6161#endif
6154 add_pinned_bytes(root->fs_info, num_bytes, owner, root_objectid); 6162 add_pinned_bytes(root->fs_info, num_bytes, owner, root_objectid);
6155 6163
6156 /* 6164 /*
@@ -7157,6 +7165,15 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
7157 bool skinny_metadata = btrfs_fs_incompat(root->fs_info, 7165 bool skinny_metadata = btrfs_fs_incompat(root->fs_info,
7158 SKINNY_METADATA); 7166 SKINNY_METADATA);
7159 7167
7168#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
7169 if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state))) {
7170 buf = btrfs_init_new_buffer(trans, root, root->alloc_bytenr,
7171 blocksize, level);
7172 if (!IS_ERR(buf))
7173 root->alloc_bytenr += blocksize;
7174 return buf;
7175 }
7176#endif
7160 block_rsv = use_block_rsv(trans, root, blocksize); 7177 block_rsv = use_block_rsv(trans, root, blocksize);
7161 if (IS_ERR(block_rsv)) 7178 if (IS_ERR(block_rsv))
7162 return ERR_CAST(block_rsv); 7179 return ERR_CAST(block_rsv);
diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index a55580f4e611..8285ed0464fa 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -4549,6 +4549,53 @@ struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
4549 return NULL; 4549 return NULL;
4550} 4550}
4551 4551
4552#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
4553struct 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;
4566again:
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;
4593free_eb:
4594 btrfs_release_extent_buffer(eb);
4595 return exists;
4596}
4597#endif
4598
4552struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info, 4599struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
4553 u64 start, unsigned long len) 4600 u64 start, unsigned long len)
4554{ 4601{
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index c488b45237bf..8b63f2d46518 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -350,5 +350,7 @@ noinline u64 find_lock_delalloc_range(struct inode *inode,
350 struct extent_io_tree *tree, 350 struct extent_io_tree *tree,
351 struct page *locked_page, u64 *start, 351 struct page *locked_page, u64 *start,
352 u64 *end, u64 max_bytes); 352 u64 *end, u64 max_bytes);
353struct extent_buffer *alloc_test_extent_buffer(struct btrfs_fs_info *fs_info,
354 u64 start, unsigned long len);
353#endif 355#endif
354#endif 356#endif
diff --git a/fs/btrfs/qgroup.c b/fs/btrfs/qgroup.c
index 09b8cc83965c..73f706c9a342 100644
--- a/fs/btrfs/qgroup.c
+++ b/fs/btrfs/qgroup.c
@@ -246,6 +246,21 @@ static int del_relation_rb(struct btrfs_fs_info *fs_info,
246 return -ENOENT; 246 return -ENOENT;
247} 247}
248 248
249#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
250int 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 * The full config is read in one go, only called from open_ctree() 265 * The full config is read in one go, only called from open_ctree()
251 * It doesn't use any locking, as at this point we're still single-threaded 266 * It doesn't use any locking, as at this point we're still single-threaded
@@ -524,6 +539,10 @@ static int add_qgroup_item(struct btrfs_trans_handle *trans,
524 struct extent_buffer *leaf; 539 struct extent_buffer *leaf;
525 struct btrfs_key key; 540 struct btrfs_key key;
526 541
542#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
543 if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &quota_root->state)))
544 return 0;
545#endif
527 path = btrfs_alloc_path(); 546 path = btrfs_alloc_path();
528 if (!path) 547 if (!path)
529 return -ENOMEM; 548 return -ENOMEM;
@@ -673,6 +692,10 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
673 int ret; 692 int ret;
674 int slot; 693 int slot;
675 694
695#ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
696 if (unlikely(test_bit(BTRFS_ROOT_DUMMY_ROOT, &root->state)))
697 return 0;
698#endif
676 key.objectid = 0; 699 key.objectid = 0;
677 key.type = BTRFS_QGROUP_INFO_KEY; 700 key.type = BTRFS_QGROUP_INFO_KEY;
678 key.offset = qgroup->qgroupid; 701 key.offset = qgroup->qgroupid;
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c
index 8f7c03db1f8d..d80a2786f563 100644
--- a/fs/btrfs/super.c
+++ b/fs/btrfs/super.c
@@ -1895,6 +1895,9 @@ static int btrfs_run_sanity_tests(void)
1895 if (ret) 1895 if (ret)
1896 goto out; 1896 goto out;
1897 ret = btrfs_test_inodes(); 1897 ret = btrfs_test_inodes();
1898 if (ret)
1899 goto out;
1900 ret = btrfs_test_qgroups();
1898out: 1901out:
1899 btrfs_destroy_test_fs(); 1902 btrfs_destroy_test_fs();
1900 return ret; 1903 return ret;
diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
index 757ef00a75a4..a5dcacb5df9c 100644
--- a/fs/btrfs/tests/btrfs-tests.c
+++ b/fs/btrfs/tests/btrfs-tests.c
@@ -21,6 +21,9 @@
21#include <linux/magic.h> 21#include <linux/magic.h>
22#include "btrfs-tests.h" 22#include "btrfs-tests.h"
23#include "../ctree.h" 23#include "../ctree.h"
24#include "../volumes.h"
25#include "../disk-io.h"
26#include "../qgroup.h"
24 27
25static struct vfsmount *test_mnt = NULL; 28static struct vfsmount *test_mnt = NULL;
26 29
@@ -72,3 +75,97 @@ void btrfs_destroy_test_fs(void)
72 kern_unmount(test_mnt); 75 kern_unmount(test_mnt);
73 unregister_filesystem(&test_type); 76 unregister_filesystem(&test_type);
74} 77}
78
79struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void)
80{
81 struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info),
82 GFP_NOFS);
83
84 if (!fs_info)
85 return fs_info;
86 fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices),
87 GFP_NOFS);
88 if (!fs_info->fs_devices) {
89 kfree(fs_info);
90 return NULL;
91 }
92 fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block),
93 GFP_NOFS);
94 if (!fs_info->super_copy) {
95 kfree(fs_info->fs_devices);
96 kfree(fs_info);
97 return NULL;
98 }
99
100 if (init_srcu_struct(&fs_info->subvol_srcu)) {
101 kfree(fs_info->fs_devices);
102 kfree(fs_info->super_copy);
103 kfree(fs_info);
104 return NULL;
105 }
106
107 spin_lock_init(&fs_info->buffer_lock);
108 spin_lock_init(&fs_info->qgroup_lock);
109 spin_lock_init(&fs_info->qgroup_op_lock);
110 spin_lock_init(&fs_info->super_lock);
111 spin_lock_init(&fs_info->fs_roots_radix_lock);
112 spin_lock_init(&fs_info->tree_mod_seq_lock);
113 mutex_init(&fs_info->qgroup_ioctl_lock);
114 mutex_init(&fs_info->qgroup_rescan_lock);
115 rwlock_init(&fs_info->tree_mod_log_lock);
116 fs_info->running_transaction = NULL;
117 fs_info->qgroup_tree = RB_ROOT;
118 fs_info->qgroup_ulist = NULL;
119 atomic64_set(&fs_info->tree_mod_seq, 0);
120 INIT_LIST_HEAD(&fs_info->dirty_qgroups);
121 INIT_LIST_HEAD(&fs_info->dead_roots);
122 INIT_LIST_HEAD(&fs_info->tree_mod_seq_list);
123 INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
124 INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
125 return fs_info;
126}
127
128static void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
129{
130 struct radix_tree_iter iter;
131 void **slot;
132
133 spin_lock(&fs_info->buffer_lock);
134restart:
135 radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) {
136 struct extent_buffer *eb;
137
138 eb = radix_tree_deref_slot(slot);
139 if (!eb)
140 continue;
141 /* Shouldn't happen but that kind of thinking creates CVE's */
142 if (radix_tree_exception(eb)) {
143 if (radix_tree_deref_retry(eb))
144 goto restart;
145 continue;
146 }
147 spin_unlock(&fs_info->buffer_lock);
148 free_extent_buffer_stale(eb);
149 spin_lock(&fs_info->buffer_lock);
150 }
151 spin_unlock(&fs_info->buffer_lock);
152
153 btrfs_free_qgroup_config(fs_info);
154 btrfs_free_fs_roots(fs_info);
155 cleanup_srcu_struct(&fs_info->subvol_srcu);
156 kfree(fs_info->super_copy);
157 kfree(fs_info->fs_devices);
158 kfree(fs_info);
159}
160
161void btrfs_free_dummy_root(struct btrfs_root *root)
162{
163 if (!root)
164 return;
165 if (root->node)
166 free_extent_buffer(root->node);
167 if (root->fs_info)
168 btrfs_free_dummy_fs_info(root->fs_info);
169 kfree(root);
170}
171
diff --git a/fs/btrfs/tests/btrfs-tests.h b/fs/btrfs/tests/btrfs-tests.h
index 312560a9123d..fd3954224480 100644
--- a/fs/btrfs/tests/btrfs-tests.h
+++ b/fs/btrfs/tests/btrfs-tests.h
@@ -23,13 +23,18 @@
23 23
24#define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__) 24#define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__)
25 25
26struct btrfs_root;
27
26int btrfs_test_free_space_cache(void); 28int btrfs_test_free_space_cache(void);
27int btrfs_test_extent_buffer_operations(void); 29int btrfs_test_extent_buffer_operations(void);
28int btrfs_test_extent_io(void); 30int btrfs_test_extent_io(void);
29int btrfs_test_inodes(void); 31int btrfs_test_inodes(void);
32int btrfs_test_qgroups(void);
30int btrfs_init_test_fs(void); 33int btrfs_init_test_fs(void);
31void btrfs_destroy_test_fs(void); 34void btrfs_destroy_test_fs(void);
32struct inode *btrfs_new_test_inode(void); 35struct inode *btrfs_new_test_inode(void);
36struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void);
37void btrfs_free_dummy_root(struct btrfs_root *root);
33#else 38#else
34static inline int btrfs_test_free_space_cache(void) 39static inline int btrfs_test_free_space_cache(void)
35{ 40{
@@ -54,6 +59,10 @@ static inline int btrfs_test_inodes(void)
54{ 59{
55 return 0; 60 return 0;
56} 61}
62static inline int btrfs_test_qgroups(void)
63{
64 return 0;
65}
57#endif 66#endif
58 67
59#endif 68#endif
diff --git a/fs/btrfs/tests/inode-tests.c b/fs/btrfs/tests/inode-tests.c
index 397d1f99a8eb..3ae0f5b8bb80 100644
--- a/fs/btrfs/tests/inode-tests.c
+++ b/fs/btrfs/tests/inode-tests.c
@@ -23,33 +23,6 @@
23#include "../extent_io.h" 23#include "../extent_io.h"
24#include "../volumes.h" 24#include "../volumes.h"
25 25
26static 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}
40static 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
53static void insert_extent(struct btrfs_root *root, u64 start, u64 len, 26static void insert_extent(struct btrfs_root *root, u64 start, u64 len,
54 u64 ram_bytes, u64 offset, u64 disk_bytenr, 27 u64 ram_bytes, u64 offset, u64 disk_bytenr,
55 u64 disk_len, u32 type, u8 compression, int slot) 28 u64 disk_len, u32 type, u8 compression, int slot)
@@ -276,7 +249,7 @@ static noinline int test_btrfs_get_extent(void)
276 * We do this since btrfs_get_extent wants to assign em->bdev to 249 * We do this since btrfs_get_extent wants to assign em->bdev to
277 * root->fs_info->fs_devices->latest_bdev. 250 * root->fs_info->fs_devices->latest_bdev.
278 */ 251 */
279 root->fs_info = alloc_dummy_fs_info(); 252 root->fs_info = btrfs_alloc_dummy_fs_info();
280 if (!root->fs_info) { 253 if (!root->fs_info) {
281 test_msg("Couldn't allocate dummy fs info\n"); 254 test_msg("Couldn't allocate dummy fs info\n");
282 goto out; 255 goto out;
@@ -837,7 +810,7 @@ out:
837 if (!IS_ERR(em)) 810 if (!IS_ERR(em))
838 free_extent_map(em); 811 free_extent_map(em);
839 iput(inode); 812 iput(inode);
840 free_dummy_root(root); 813 btrfs_free_dummy_root(root);
841 return ret; 814 return ret;
842} 815}
843 816
@@ -864,7 +837,7 @@ static int test_hole_first(void)
864 goto out; 837 goto out;
865 } 838 }
866 839
867 root->fs_info = alloc_dummy_fs_info(); 840 root->fs_info = btrfs_alloc_dummy_fs_info();
868 if (!root->fs_info) { 841 if (!root->fs_info) {
869 test_msg("Couldn't allocate dummy fs info\n"); 842 test_msg("Couldn't allocate dummy fs info\n");
870 goto out; 843 goto out;
@@ -934,7 +907,7 @@ out:
934 if (!IS_ERR(em)) 907 if (!IS_ERR(em))
935 free_extent_map(em); 908 free_extent_map(em);
936 iput(inode); 909 iput(inode);
937 free_dummy_root(root); 910 btrfs_free_dummy_root(root);
938 return ret; 911 return ret;
939} 912}
940 913
diff --git a/fs/btrfs/tests/qgroup-tests.c b/fs/btrfs/tests/qgroup-tests.c
new file mode 100644
index 000000000000..fa691b754aaf
--- /dev/null
+++ b/fs/btrfs/tests/qgroup-tests.c
@@ -0,0 +1,468 @@
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
25static 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
33static 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
86static 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
138static 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
170static 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
226static 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 */
293static 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
389int 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);
465out:
466 btrfs_free_dummy_root(root);
467 return ret;
468}
diff --git a/fs/btrfs/transaction.h b/fs/btrfs/transaction.h
index b57b924e8e03..7dd558ed0716 100644
--- a/fs/btrfs/transaction.h
+++ b/fs/btrfs/transaction.h
@@ -69,6 +69,7 @@ struct btrfs_transaction {
69#define __TRANS_ATTACH (1U << 10) 69#define __TRANS_ATTACH (1U << 10)
70#define __TRANS_JOIN (1U << 11) 70#define __TRANS_JOIN (1U << 11)
71#define __TRANS_JOIN_NOLOCK (1U << 12) 71#define __TRANS_JOIN_NOLOCK (1U << 12)
72#define __TRANS_DUMMY (1U << 13)
72 73
73#define TRANS_USERSPACE (__TRANS_USERSPACE | __TRANS_FREEZABLE) 74#define TRANS_USERSPACE (__TRANS_USERSPACE | __TRANS_FREEZABLE)
74#define TRANS_START (__TRANS_START | __TRANS_FREEZABLE) 75#define TRANS_START (__TRANS_START | __TRANS_FREEZABLE)