Commit | Line | Data |
---|---|---|
c1d7c514 | 1 | // SPDX-License-Identifier: GPL-2.0 |
294e30fe JB |
2 | /* |
3 | * Copyright (C) 2013 Fusion IO. All rights reserved. | |
294e30fe JB |
4 | */ |
5 | ||
6 | #include <linux/fs.h> | |
7 | #include <linux/mount.h> | |
389e22fb | 8 | #include <linux/pseudo_fs.h> |
294e30fe JB |
9 | #include <linux/magic.h> |
10 | #include "btrfs-tests.h" | |
11 | #include "../ctree.h" | |
7c55ee0c OS |
12 | #include "../free-space-cache.h" |
13 | #include "../free-space-tree.h" | |
14 | #include "../transaction.h" | |
faa2dbf0 JB |
15 | #include "../volumes.h" |
16 | #include "../disk-io.h" | |
17 | #include "../qgroup.h" | |
aac0023c | 18 | #include "../block-group.h" |
294e30fe JB |
19 | |
20 | static struct vfsmount *test_mnt = NULL; | |
21 | ||
703de426 DS |
22 | const char *test_error[] = { |
23 | [TEST_ALLOC_FS_INFO] = "cannot allocate fs_info", | |
24 | [TEST_ALLOC_ROOT] = "cannot allocate root", | |
25 | [TEST_ALLOC_EXTENT_BUFFER] = "cannot extent buffer", | |
26 | [TEST_ALLOC_PATH] = "cannot allocate path", | |
27 | [TEST_ALLOC_INODE] = "cannot allocate inode", | |
28 | [TEST_ALLOC_BLOCK_GROUP] = "cannot allocate block group", | |
29 | [TEST_ALLOC_EXTENT_MAP] = "cannot allocate extent map", | |
30 | }; | |
31 | ||
aaedb55b JB |
32 | static const struct super_operations btrfs_test_super_ops = { |
33 | .alloc_inode = btrfs_alloc_inode, | |
34 | .destroy_inode = btrfs_test_destroy_inode, | |
35 | }; | |
36 | ||
389e22fb DH |
37 | |
38 | static int btrfs_test_init_fs_context(struct fs_context *fc) | |
294e30fe | 39 | { |
389e22fb DH |
40 | struct pseudo_fs_context *ctx = init_pseudo(fc, BTRFS_TEST_MAGIC); |
41 | if (!ctx) | |
42 | return -ENOMEM; | |
43 | ctx->ops = &btrfs_test_super_ops; | |
44 | return 0; | |
294e30fe JB |
45 | } |
46 | ||
47 | static struct file_system_type test_type = { | |
48 | .name = "btrfs_test_fs", | |
389e22fb | 49 | .init_fs_context = btrfs_test_init_fs_context, |
294e30fe JB |
50 | .kill_sb = kill_anon_super, |
51 | }; | |
52 | ||
53 | struct inode *btrfs_new_test_inode(void) | |
54 | { | |
9f7fec0b FM |
55 | struct inode *inode; |
56 | ||
57 | inode = new_inode(test_mnt->mnt_sb); | |
58 | if (inode) | |
59 | inode_init_owner(inode, NULL, S_IFREG); | |
60 | ||
61 | return inode; | |
294e30fe JB |
62 | } |
63 | ||
8632daae | 64 | static int btrfs_init_test_fs(void) |
294e30fe JB |
65 | { |
66 | int ret; | |
67 | ||
68 | ret = register_filesystem(&test_type); | |
69 | if (ret) { | |
70 | printk(KERN_ERR "btrfs: cannot register test file system\n"); | |
71 | return ret; | |
72 | } | |
73 | ||
74 | test_mnt = kern_mount(&test_type); | |
75 | if (IS_ERR(test_mnt)) { | |
76 | printk(KERN_ERR "btrfs: cannot mount test file system\n"); | |
77 | unregister_filesystem(&test_type); | |
04e1b65a | 78 | return PTR_ERR(test_mnt); |
294e30fe JB |
79 | } |
80 | return 0; | |
81 | } | |
82 | ||
8632daae | 83 | static void btrfs_destroy_test_fs(void) |
294e30fe JB |
84 | { |
85 | kern_unmount(test_mnt); | |
86 | unregister_filesystem(&test_type); | |
87 | } | |
faa2dbf0 | 88 | |
b3ad2c17 NB |
89 | struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info) |
90 | { | |
91 | struct btrfs_device *dev; | |
92 | ||
93 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | |
94 | if (!dev) | |
95 | return ERR_PTR(-ENOMEM); | |
96 | ||
97 | extent_io_tree_init(NULL, &dev->alloc_state, 0, NULL); | |
98 | INIT_LIST_HEAD(&dev->dev_list); | |
99 | list_add(&dev->dev_list, &fs_info->fs_devices->devices); | |
100 | ||
101 | return dev; | |
102 | } | |
103 | ||
104 | static void btrfs_free_dummy_device(struct btrfs_device *dev) | |
105 | { | |
106 | extent_io_tree_release(&dev->alloc_state); | |
107 | kfree(dev); | |
108 | } | |
109 | ||
da17066c | 110 | struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize) |
faa2dbf0 JB |
111 | { |
112 | struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info), | |
8cce83ba | 113 | GFP_KERNEL); |
faa2dbf0 JB |
114 | |
115 | if (!fs_info) | |
116 | return fs_info; | |
117 | fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices), | |
8cce83ba | 118 | GFP_KERNEL); |
faa2dbf0 JB |
119 | if (!fs_info->fs_devices) { |
120 | kfree(fs_info); | |
121 | return NULL; | |
122 | } | |
8260edba JB |
123 | INIT_LIST_HEAD(&fs_info->fs_devices->devices); |
124 | ||
faa2dbf0 | 125 | fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block), |
8cce83ba | 126 | GFP_KERNEL); |
faa2dbf0 JB |
127 | if (!fs_info->super_copy) { |
128 | kfree(fs_info->fs_devices); | |
129 | kfree(fs_info); | |
130 | return NULL; | |
131 | } | |
132 | ||
8260edba JB |
133 | btrfs_init_fs_info(fs_info); |
134 | ||
da17066c JM |
135 | fs_info->nodesize = nodesize; |
136 | fs_info->sectorsize = sectorsize; | |
ab108d99 | 137 | fs_info->sectorsize_bits = ilog2(sectorsize); |
7c0260ee JM |
138 | set_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state); |
139 | ||
140 | test_mnt->mnt_sb->s_fs_info = fs_info; | |
141 | ||
faa2dbf0 JB |
142 | return fs_info; |
143 | } | |
144 | ||
7c0260ee | 145 | void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info) |
faa2dbf0 JB |
146 | { |
147 | struct radix_tree_iter iter; | |
148 | void **slot; | |
b3ad2c17 | 149 | struct btrfs_device *dev, *tmp; |
faa2dbf0 | 150 | |
7c0260ee JM |
151 | if (!fs_info) |
152 | return; | |
153 | ||
154 | if (WARN_ON(!test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, | |
155 | &fs_info->fs_state))) | |
156 | return; | |
157 | ||
158 | test_mnt->mnt_sb->s_fs_info = NULL; | |
159 | ||
faa2dbf0 | 160 | spin_lock(&fs_info->buffer_lock); |
faa2dbf0 JB |
161 | radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) { |
162 | struct extent_buffer *eb; | |
163 | ||
f1e3c289 | 164 | eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock); |
faa2dbf0 JB |
165 | if (!eb) |
166 | continue; | |
167 | /* Shouldn't happen but that kind of thinking creates CVE's */ | |
168 | if (radix_tree_exception(eb)) { | |
169 | if (radix_tree_deref_retry(eb)) | |
c28f2420 | 170 | slot = radix_tree_iter_retry(&iter); |
faa2dbf0 JB |
171 | continue; |
172 | } | |
148deab2 | 173 | slot = radix_tree_iter_resume(slot, &iter); |
faa2dbf0 JB |
174 | spin_unlock(&fs_info->buffer_lock); |
175 | free_extent_buffer_stale(eb); | |
176 | spin_lock(&fs_info->buffer_lock); | |
177 | } | |
178 | spin_unlock(&fs_info->buffer_lock); | |
179 | ||
b3ad2c17 NB |
180 | btrfs_mapping_tree_free(&fs_info->mapping_tree); |
181 | list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices, | |
182 | dev_list) { | |
183 | btrfs_free_dummy_device(dev); | |
184 | } | |
faa2dbf0 JB |
185 | btrfs_free_qgroup_config(fs_info); |
186 | btrfs_free_fs_roots(fs_info); | |
faa2dbf0 | 187 | kfree(fs_info->super_copy); |
bd647ce3 | 188 | btrfs_check_leaked_roots(fs_info); |
8c38938c | 189 | btrfs_extent_buffer_leak_debug_check(fs_info); |
faa2dbf0 JB |
190 | kfree(fs_info->fs_devices); |
191 | kfree(fs_info); | |
192 | } | |
193 | ||
194 | void btrfs_free_dummy_root(struct btrfs_root *root) | |
195 | { | |
196 | if (!root) | |
197 | return; | |
7c0260ee JM |
198 | /* Will be freed by btrfs_free_fs_roots */ |
199 | if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state))) | |
200 | return; | |
00246528 | 201 | btrfs_put_root(root); |
faa2dbf0 JB |
202 | } |
203 | ||
32da5386 | 204 | struct btrfs_block_group * |
da17066c JM |
205 | btrfs_alloc_dummy_block_group(struct btrfs_fs_info *fs_info, |
206 | unsigned long length) | |
7c55ee0c | 207 | { |
32da5386 | 208 | struct btrfs_block_group *cache; |
7c55ee0c | 209 | |
8cce83ba | 210 | cache = kzalloc(sizeof(*cache), GFP_KERNEL); |
7c55ee0c OS |
211 | if (!cache) |
212 | return NULL; | |
213 | cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl), | |
8cce83ba | 214 | GFP_KERNEL); |
7c55ee0c OS |
215 | if (!cache->free_space_ctl) { |
216 | kfree(cache); | |
217 | return NULL; | |
218 | } | |
219 | ||
b3470b5d DS |
220 | cache->start = 0; |
221 | cache->length = length; | |
da17066c JM |
222 | cache->full_stripe_len = fs_info->sectorsize; |
223 | cache->fs_info = fs_info; | |
7c55ee0c OS |
224 | |
225 | INIT_LIST_HEAD(&cache->list); | |
226 | INIT_LIST_HEAD(&cache->cluster_list); | |
227 | INIT_LIST_HEAD(&cache->bg_list); | |
cd79909b | 228 | btrfs_init_free_space_ctl(cache, cache->free_space_ctl); |
7c55ee0c OS |
229 | mutex_init(&cache->free_space_lock); |
230 | ||
231 | return cache; | |
232 | } | |
233 | ||
32da5386 | 234 | void btrfs_free_dummy_block_group(struct btrfs_block_group *cache) |
7c55ee0c OS |
235 | { |
236 | if (!cache) | |
237 | return; | |
238 | __btrfs_remove_free_space_cache(cache->free_space_ctl); | |
239 | kfree(cache->free_space_ctl); | |
240 | kfree(cache); | |
241 | } | |
242 | ||
483bce06 NB |
243 | void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans, |
244 | struct btrfs_fs_info *fs_info) | |
7c55ee0c OS |
245 | { |
246 | memset(trans, 0, sizeof(*trans)); | |
247 | trans->transid = 1; | |
7c55ee0c | 248 | trans->type = __TRANS_DUMMY; |
483bce06 | 249 | trans->fs_info = fs_info; |
7c55ee0c | 250 | } |
8632daae JM |
251 | |
252 | int btrfs_run_sanity_tests(void) | |
253 | { | |
254 | int ret, i; | |
255 | u32 sectorsize, nodesize; | |
256 | u32 test_sectorsize[] = { | |
257 | PAGE_SIZE, | |
258 | }; | |
259 | ret = btrfs_init_test_fs(); | |
260 | if (ret) | |
261 | return ret; | |
262 | for (i = 0; i < ARRAY_SIZE(test_sectorsize); i++) { | |
263 | sectorsize = test_sectorsize[i]; | |
264 | for (nodesize = sectorsize; | |
265 | nodesize <= BTRFS_MAX_METADATA_BLOCKSIZE; | |
266 | nodesize <<= 1) { | |
267 | pr_info("BTRFS: selftest: sectorsize: %u nodesize: %u\n", | |
268 | sectorsize, nodesize); | |
269 | ret = btrfs_test_free_space_cache(sectorsize, nodesize); | |
270 | if (ret) | |
271 | goto out; | |
272 | ret = btrfs_test_extent_buffer_operations(sectorsize, | |
273 | nodesize); | |
274 | if (ret) | |
275 | goto out; | |
276 | ret = btrfs_test_extent_io(sectorsize, nodesize); | |
277 | if (ret) | |
278 | goto out; | |
279 | ret = btrfs_test_inodes(sectorsize, nodesize); | |
280 | if (ret) | |
281 | goto out; | |
282 | ret = btrfs_test_qgroups(sectorsize, nodesize); | |
283 | if (ret) | |
284 | goto out; | |
285 | ret = btrfs_test_free_space_tree(sectorsize, nodesize); | |
286 | if (ret) | |
287 | goto out; | |
288 | } | |
289 | } | |
72b28077 | 290 | ret = btrfs_test_extent_map(); |
7a61f880 | 291 | |
8632daae JM |
292 | out: |
293 | btrfs_destroy_test_fs(); | |
294 | return ret; | |
295 | } |