Commit | Line | Data |
---|---|---|
294e30fe JB |
1 | /* |
2 | * Copyright (C) 2013 Fusion IO. 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 <linux/fs.h> | |
20 | #include <linux/mount.h> | |
21 | #include <linux/magic.h> | |
22 | #include "btrfs-tests.h" | |
23 | #include "../ctree.h" | |
7c55ee0c OS |
24 | #include "../free-space-cache.h" |
25 | #include "../free-space-tree.h" | |
26 | #include "../transaction.h" | |
faa2dbf0 JB |
27 | #include "../volumes.h" |
28 | #include "../disk-io.h" | |
29 | #include "../qgroup.h" | |
294e30fe JB |
30 | |
31 | static struct vfsmount *test_mnt = NULL; | |
32 | ||
aaedb55b JB |
33 | static const struct super_operations btrfs_test_super_ops = { |
34 | .alloc_inode = btrfs_alloc_inode, | |
35 | .destroy_inode = btrfs_test_destroy_inode, | |
36 | }; | |
37 | ||
294e30fe JB |
38 | static struct dentry *btrfs_test_mount(struct file_system_type *fs_type, |
39 | int flags, const char *dev_name, | |
40 | void *data) | |
41 | { | |
aaedb55b JB |
42 | return mount_pseudo(fs_type, "btrfs_test:", &btrfs_test_super_ops, |
43 | NULL, BTRFS_TEST_MAGIC); | |
294e30fe JB |
44 | } |
45 | ||
46 | static struct file_system_type test_type = { | |
47 | .name = "btrfs_test_fs", | |
48 | .mount = btrfs_test_mount, | |
49 | .kill_sb = kill_anon_super, | |
50 | }; | |
51 | ||
52 | struct inode *btrfs_new_test_inode(void) | |
53 | { | |
54 | return new_inode(test_mnt->mnt_sb); | |
55 | } | |
56 | ||
57 | int btrfs_init_test_fs(void) | |
58 | { | |
59 | int ret; | |
60 | ||
61 | ret = register_filesystem(&test_type); | |
62 | if (ret) { | |
63 | printk(KERN_ERR "btrfs: cannot register test file system\n"); | |
64 | return ret; | |
65 | } | |
66 | ||
67 | test_mnt = kern_mount(&test_type); | |
68 | if (IS_ERR(test_mnt)) { | |
69 | printk(KERN_ERR "btrfs: cannot mount test file system\n"); | |
70 | unregister_filesystem(&test_type); | |
04e1b65a | 71 | return PTR_ERR(test_mnt); |
294e30fe JB |
72 | } |
73 | return 0; | |
74 | } | |
75 | ||
76 | void btrfs_destroy_test_fs(void) | |
77 | { | |
78 | kern_unmount(test_mnt); | |
79 | unregister_filesystem(&test_type); | |
80 | } | |
faa2dbf0 JB |
81 | |
82 | struct btrfs_fs_info *btrfs_alloc_dummy_fs_info(void) | |
83 | { | |
84 | struct btrfs_fs_info *fs_info = kzalloc(sizeof(struct btrfs_fs_info), | |
8cce83ba | 85 | GFP_KERNEL); |
faa2dbf0 JB |
86 | |
87 | if (!fs_info) | |
88 | return fs_info; | |
89 | fs_info->fs_devices = kzalloc(sizeof(struct btrfs_fs_devices), | |
8cce83ba | 90 | GFP_KERNEL); |
faa2dbf0 JB |
91 | if (!fs_info->fs_devices) { |
92 | kfree(fs_info); | |
93 | return NULL; | |
94 | } | |
95 | fs_info->super_copy = kzalloc(sizeof(struct btrfs_super_block), | |
8cce83ba | 96 | GFP_KERNEL); |
faa2dbf0 JB |
97 | if (!fs_info->super_copy) { |
98 | kfree(fs_info->fs_devices); | |
99 | kfree(fs_info); | |
100 | return NULL; | |
101 | } | |
102 | ||
103 | if (init_srcu_struct(&fs_info->subvol_srcu)) { | |
104 | kfree(fs_info->fs_devices); | |
105 | kfree(fs_info->super_copy); | |
106 | kfree(fs_info); | |
107 | return NULL; | |
108 | } | |
109 | ||
110 | spin_lock_init(&fs_info->buffer_lock); | |
111 | spin_lock_init(&fs_info->qgroup_lock); | |
112 | spin_lock_init(&fs_info->qgroup_op_lock); | |
113 | spin_lock_init(&fs_info->super_lock); | |
114 | spin_lock_init(&fs_info->fs_roots_radix_lock); | |
115 | spin_lock_init(&fs_info->tree_mod_seq_lock); | |
116 | mutex_init(&fs_info->qgroup_ioctl_lock); | |
117 | mutex_init(&fs_info->qgroup_rescan_lock); | |
118 | rwlock_init(&fs_info->tree_mod_log_lock); | |
119 | fs_info->running_transaction = NULL; | |
120 | fs_info->qgroup_tree = RB_ROOT; | |
121 | fs_info->qgroup_ulist = NULL; | |
122 | atomic64_set(&fs_info->tree_mod_seq, 0); | |
123 | INIT_LIST_HEAD(&fs_info->dirty_qgroups); | |
124 | INIT_LIST_HEAD(&fs_info->dead_roots); | |
125 | INIT_LIST_HEAD(&fs_info->tree_mod_seq_list); | |
126 | INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC); | |
127 | INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC); | |
7c55ee0c OS |
128 | extent_io_tree_init(&fs_info->freed_extents[0], NULL); |
129 | extent_io_tree_init(&fs_info->freed_extents[1], NULL); | |
130 | fs_info->pinned_extents = &fs_info->freed_extents[0]; | |
faa2dbf0 JB |
131 | return fs_info; |
132 | } | |
133 | ||
134 | static void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info) | |
135 | { | |
136 | struct radix_tree_iter iter; | |
137 | void **slot; | |
138 | ||
139 | spin_lock(&fs_info->buffer_lock); | |
faa2dbf0 JB |
140 | radix_tree_for_each_slot(slot, &fs_info->buffer_radix, &iter, 0) { |
141 | struct extent_buffer *eb; | |
142 | ||
f1e3c289 | 143 | eb = radix_tree_deref_slot_protected(slot, &fs_info->buffer_lock); |
faa2dbf0 JB |
144 | if (!eb) |
145 | continue; | |
146 | /* Shouldn't happen but that kind of thinking creates CVE's */ | |
147 | if (radix_tree_exception(eb)) { | |
148 | if (radix_tree_deref_retry(eb)) | |
c28f2420 | 149 | slot = radix_tree_iter_retry(&iter); |
faa2dbf0 JB |
150 | continue; |
151 | } | |
152 | spin_unlock(&fs_info->buffer_lock); | |
153 | free_extent_buffer_stale(eb); | |
154 | spin_lock(&fs_info->buffer_lock); | |
155 | } | |
156 | spin_unlock(&fs_info->buffer_lock); | |
157 | ||
158 | btrfs_free_qgroup_config(fs_info); | |
159 | btrfs_free_fs_roots(fs_info); | |
160 | cleanup_srcu_struct(&fs_info->subvol_srcu); | |
161 | kfree(fs_info->super_copy); | |
162 | kfree(fs_info->fs_devices); | |
163 | kfree(fs_info); | |
164 | } | |
165 | ||
166 | void btrfs_free_dummy_root(struct btrfs_root *root) | |
167 | { | |
168 | if (!root) | |
169 | return; | |
170 | if (root->node) | |
171 | free_extent_buffer(root->node); | |
172 | if (root->fs_info) | |
173 | btrfs_free_dummy_fs_info(root->fs_info); | |
174 | kfree(root); | |
175 | } | |
176 | ||
7c55ee0c | 177 | struct btrfs_block_group_cache * |
b9ef22de | 178 | btrfs_alloc_dummy_block_group(unsigned long length, u32 sectorsize) |
7c55ee0c OS |
179 | { |
180 | struct btrfs_block_group_cache *cache; | |
181 | ||
8cce83ba | 182 | cache = kzalloc(sizeof(*cache), GFP_KERNEL); |
7c55ee0c OS |
183 | if (!cache) |
184 | return NULL; | |
185 | cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl), | |
8cce83ba | 186 | GFP_KERNEL); |
7c55ee0c OS |
187 | if (!cache->free_space_ctl) { |
188 | kfree(cache); | |
189 | return NULL; | |
190 | } | |
191 | ||
192 | cache->key.objectid = 0; | |
193 | cache->key.offset = length; | |
194 | cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY; | |
b9ef22de FX |
195 | cache->sectorsize = sectorsize; |
196 | cache->full_stripe_len = sectorsize; | |
7c55ee0c OS |
197 | |
198 | INIT_LIST_HEAD(&cache->list); | |
199 | INIT_LIST_HEAD(&cache->cluster_list); | |
200 | INIT_LIST_HEAD(&cache->bg_list); | |
201 | btrfs_init_free_space_ctl(cache); | |
202 | mutex_init(&cache->free_space_lock); | |
203 | ||
204 | return cache; | |
205 | } | |
206 | ||
207 | void btrfs_free_dummy_block_group(struct btrfs_block_group_cache *cache) | |
208 | { | |
209 | if (!cache) | |
210 | return; | |
211 | __btrfs_remove_free_space_cache(cache->free_space_ctl); | |
212 | kfree(cache->free_space_ctl); | |
213 | kfree(cache); | |
214 | } | |
215 | ||
216 | void btrfs_init_dummy_trans(struct btrfs_trans_handle *trans) | |
217 | { | |
218 | memset(trans, 0, sizeof(*trans)); | |
219 | trans->transid = 1; | |
220 | INIT_LIST_HEAD(&trans->qgroup_ref_list); | |
221 | trans->type = __TRANS_DUMMY; | |
222 | } |