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