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); | |
675a4fc8 JB |
58 | if (!inode) |
59 | return NULL; | |
60 | ||
61 | inode->i_mode = S_IFREG; | |
62 | BTRFS_I(inode)->location.type = BTRFS_INODE_ITEM_KEY; | |
63 | BTRFS_I(inode)->location.objectid = BTRFS_FIRST_FREE_OBJECTID; | |
64 | BTRFS_I(inode)->location.offset = 0; | |
21cb47be | 65 | inode_init_owner(&init_user_ns, inode, NULL, S_IFREG); |
9f7fec0b FM |
66 | |
67 | return inode; | |
294e30fe JB |
68 | } |
69 | ||
8632daae | 70 | static int btrfs_init_test_fs(void) |
294e30fe JB |
71 | { |
72 | int ret; | |
73 | ||
74 | ret = register_filesystem(&test_type); | |
75 | if (ret) { | |
76 | printk(KERN_ERR "btrfs: cannot register test file system\n"); | |
77 | return ret; | |
78 | } | |
79 | ||
80 | test_mnt = kern_mount(&test_type); | |
81 | if (IS_ERR(test_mnt)) { | |
82 | printk(KERN_ERR "btrfs: cannot mount test file system\n"); | |
83 | unregister_filesystem(&test_type); | |
04e1b65a | 84 | return PTR_ERR(test_mnt); |
294e30fe JB |
85 | } |
86 | return 0; | |
87 | } | |
88 | ||
8632daae | 89 | static void btrfs_destroy_test_fs(void) |
294e30fe JB |
90 | { |
91 | kern_unmount(test_mnt); | |
92 | unregister_filesystem(&test_type); | |
93 | } | |
faa2dbf0 | 94 | |
b3ad2c17 NB |
95 | struct btrfs_device *btrfs_alloc_dummy_device(struct btrfs_fs_info *fs_info) |
96 | { | |
97 | struct btrfs_device *dev; | |
98 | ||
99 | dev = kzalloc(sizeof(*dev), GFP_KERNEL); | |
100 | if (!dev) | |
101 | return ERR_PTR(-ENOMEM); | |
102 | ||
103 | extent_io_tree_init(NULL, &dev->alloc_state, 0, NULL); | |
104 | INIT_LIST_HEAD(&dev->dev_list); | |
105 | list_add(&dev->dev_list, &fs_info->fs_devices->devices); | |
106 | ||
107 | return dev; | |
108 | } | |
109 | ||
110 | static void btrfs_free_dummy_device(struct btrfs_device *dev) | |
111 | { | |
112 | extent_io_tree_release(&dev->alloc_state); | |
113 | kfree(dev); | |
114 | } | |
115 | ||
da17066c | 116 | struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(u32 nodesize, u32 sectorsize) |
faa2dbf0 JB |
117 | { |
118 | struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info), | |
8cce83ba | 119 | GFP_KERNEL); |
faa2dbf0 JB |
120 | |
121 | if (!fs_info) | |
122 | return fs_info; | |
123 | fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices), | |
8cce83ba | 124 | GFP_KERNEL); |
faa2dbf0 JB |
125 | if (!fs_info->fs_devices) { |
126 | kfree(fs_info); | |
127 | return NULL; | |
128 | } | |
8260edba JB |
129 | INIT_LIST_HEAD(&fs_info->fs_devices->devices); |
130 | ||
faa2dbf0 | 131 | fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block), |
8cce83ba | 132 | GFP_KERNEL); |
faa2dbf0 JB |
133 | if (!fs_info->super_copy) { |
134 | kfree(fs_info->fs_devices); | |
135 | kfree(fs_info); | |
136 | return NULL; | |
137 | } | |
138 | ||
8260edba JB |
139 | btrfs_init_fs_info(fs_info); |
140 | ||
da17066c JM |
141 | fs_info->nodesize = nodesize; |
142 | fs_info->sectorsize = sectorsize; | |
ab108d99 | 143 | fs_info->sectorsize_bits = ilog2(sectorsize); |
7c0260ee JM |
144 | set_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, &fs_info->fs_state); |
145 | ||
146 | test_mnt->mnt_sb->s_fs_info = fs_info; | |
147 | ||
faa2dbf0 JB |
148 | return fs_info; |
149 | } | |
150 | ||
7c0260ee | 151 | void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info) |
faa2dbf0 | 152 | { |
01cd3909 DS |
153 | struct radix_tree_iter iter; |
154 | void **slot; | |
b3ad2c17 | 155 | struct btrfs_device *dev, *tmp; |
faa2dbf0 | 156 | |
7c0260ee JM |
157 | if (!fs_info) |
158 | return; | |
159 | ||
160 | if (WARN_ON(!test_bit(BTRFS_FS_STATE_DUMMY_FS_INFO, | |
161 | &fs_info->fs_state))) | |
162 | return; | |
163 | ||
164 | test_mnt->mnt_sb->s_fs_info = NULL; | |
165 | ||
01cd3909 DS |
166 | spin_lock(&fs_info->buffer_lock); |
167 | radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) { | |
168 | struct extent_buffer *eb; | |
169 | ||
170 | eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock); | |
171 | if (!eb) | |
172 | continue; | |
173 | /* Shouldn't happen but that kind of thinking creates CVE's */ | |
174 | if (radix_tree_exception(eb)) { | |
175 | if (radix_tree_deref_retry(eb)) | |
176 | slot = radix_tree_iter_retry(&iter); | |
177 | continue; | |
178 | } | |
179 | slot = radix_tree_iter_resume(slot, &iter); | |
180 | spin_unlock(&fs_info->buffer_lock); | |
faa2dbf0 | 181 | free_extent_buffer_stale(eb); |
01cd3909 | 182 | spin_lock(&fs_info->buffer_lock); |
faa2dbf0 | 183 | } |
01cd3909 | 184 | spin_unlock(&fs_info->buffer_lock); |
faa2dbf0 | 185 | |
b3ad2c17 NB |
186 | btrfs_mapping_tree_free(&fs_info->mapping_tree); |
187 | list_for_each_entry_safe(dev, tmp, &fs_info->fs_devices->devices, | |
188 | dev_list) { | |
189 | btrfs_free_dummy_device(dev); | |
190 | } | |
faa2dbf0 JB |
191 | btrfs_free_qgroup_config(fs_info); |
192 | btrfs_free_fs_roots(fs_info); | |
faa2dbf0 | 193 | kfree(fs_info->super_copy); |
bd647ce3 | 194 | btrfs_check_leaked_roots(fs_info); |
8c38938c | 195 | btrfs_extent_buffer_leak_debug_check(fs_info); |
faa2dbf0 JB |
196 | kfree(fs_info->fs_devices); |
197 | kfree(fs_info); | |
198 | } | |
199 | ||
200 | void btrfs_free_dummy_root(struct btrfs_root *root) | |
201 | { | |
202 | if (!root) | |
203 | return; | |
7c0260ee | 204 | /* Will be freed by btrfs_free_fs_roots */ |
fc7cbcd4 | 205 | if (WARN_ON(test_bit(BTRFS_ROOT_IN_RADIX, &root->state))) |
7c0260ee | 206 | return; |
abed4aaa | 207 | btrfs_global_root_delete(root); |
00246528 | 208 | btrfs_put_root(root); |
faa2dbf0 JB |
209 | } |
210 | ||
32da5386 | 211 | struct btrfs_block_group * |
da17066c JM |
212 | btrfs_alloc_dummy_block_group(struct btrfs_fs_info *fs_info, |
213 | unsigned long length) | |
7c55ee0c | 214 | { |
32da5386 | 215 | struct btrfs_block_group *cache; |
7c55ee0c | 216 | |
8cce83ba | 217 | cache = kzalloc(sizeof(*cache), GFP_KERNEL); |
7c55ee0c OS |
218 | if (!cache) |
219 | return NULL; | |
220 | cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl), | |
8cce83ba | 221 | GFP_KERNEL); |
7c55ee0c OS |
222 | if (!cache->free_space_ctl) { |
223 | kfree(cache); | |
224 | return NULL; | |
225 | } | |
226 | ||
b3470b5d DS |
227 | cache->start = 0; |
228 | cache->length = length; | |
da17066c JM |
229 | cache->full_stripe_len = fs_info->sectorsize; |
230 | cache->fs_info = fs_info; | |
7c55ee0c OS |
231 | |
232 | INIT_LIST_HEAD(&cache->list); | |
233 | INIT_LIST_HEAD(&cache->cluster_list); | |
234 | INIT_LIST_HEAD(&cache->bg_list); | |
cd79909b | 235 | btrfs_init_free_space_ctl(cache, cache->free_space_ctl); |
7c55ee0c OS |
236 | mutex_init(&cache->free_space_lock); |
237 | ||
238 | return cache; | |
239 | } | |
240 | ||
32da5386 | 241 | void btrfs_free_dummy_block_group(struct btrfs_block_group *cache) |
7c55ee0c OS |
242 | { |
243 | if (!cache) | |
244 | return; | |
245 | __btrfs_remove_free_space_cache(cache->free_space_ctl); | |
246 | kfree(cache->free_space_ctl); | |
247 | kfree(cache); | |
248 | } | |
249 | ||
483bce06 NB |
250 | void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans, |
251 | struct btrfs_fs_info *fs_info) | |
7c55ee0c OS |
252 | { |
253 | memset(trans, 0, sizeof(*trans)); | |
254 | trans->transid = 1; | |
7c55ee0c | 255 | trans->type = __TRANS_DUMMY; |
483bce06 | 256 | trans->fs_info = fs_info; |
7c55ee0c | 257 | } |
8632daae JM |
258 | |
259 | int btrfs_run_sanity_tests(void) | |
260 | { | |
261 | int ret, i; | |
262 | u32 sectorsize, nodesize; | |
263 | u32 test_sectorsize[] = { | |
264 | PAGE_SIZE, | |
265 | }; | |
266 | ret = btrfs_init_test_fs(); | |
267 | if (ret) | |
268 | return ret; | |
269 | for (i = 0; i < ARRAY_SIZE(test_sectorsize); i++) { | |
270 | sectorsize = test_sectorsize[i]; | |
271 | for (nodesize = sectorsize; | |
272 | nodesize <= BTRFS_MAX_METADATA_BLOCKSIZE; | |
273 | nodesize <<= 1) { | |
274 | pr_info("BTRFS: selftest: sectorsize: %u nodesize: %u\n", | |
275 | sectorsize, nodesize); | |
276 | ret = btrfs_test_free_space_cache(sectorsize, nodesize); | |
277 | if (ret) | |
278 | goto out; | |
279 | ret = btrfs_test_extent_buffer_operations(sectorsize, | |
280 | nodesize); | |
281 | if (ret) | |
282 | goto out; | |
283 | ret = btrfs_test_extent_io(sectorsize, nodesize); | |
284 | if (ret) | |
285 | goto out; | |
286 | ret = btrfs_test_inodes(sectorsize, nodesize); | |
287 | if (ret) | |
288 | goto out; | |
289 | ret = btrfs_test_qgroups(sectorsize, nodesize); | |
290 | if (ret) | |
291 | goto out; | |
292 | ret = btrfs_test_free_space_tree(sectorsize, nodesize); | |
293 | if (ret) | |
294 | goto out; | |
295 | } | |
296 | } | |
72b28077 | 297 | ret = btrfs_test_extent_map(); |
7a61f880 | 298 | |
8632daae JM |
299 | out: |
300 | btrfs_destroy_test_fs(); | |
301 | return ret; | |
302 | } |