xref: /openbmc/linux/fs/btrfs/tests/free-space-tree-tests.c (revision 7c55ee0c4afba4434d973117234577ae6ff77a1c)
1*7c55ee0cSOmar Sandoval /*
2*7c55ee0cSOmar Sandoval  * Copyright (C) 2015 Facebook.  All rights reserved.
3*7c55ee0cSOmar Sandoval  *
4*7c55ee0cSOmar Sandoval  * This program is free software; you can redistribute it and/or
5*7c55ee0cSOmar Sandoval  * modify it under the terms of the GNU General Public
6*7c55ee0cSOmar Sandoval  * License v2 as published by the Free Software Foundation.
7*7c55ee0cSOmar Sandoval  *
8*7c55ee0cSOmar Sandoval  * This program is distributed in the hope that it will be useful,
9*7c55ee0cSOmar Sandoval  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10*7c55ee0cSOmar Sandoval  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11*7c55ee0cSOmar Sandoval  * General Public License for more details.
12*7c55ee0cSOmar Sandoval  *
13*7c55ee0cSOmar Sandoval  * You should have received a copy of the GNU General Public
14*7c55ee0cSOmar Sandoval  * License along with this program; if not, write to the
15*7c55ee0cSOmar Sandoval  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
16*7c55ee0cSOmar Sandoval  * Boston, MA 021110-1307, USA.
17*7c55ee0cSOmar Sandoval  */
18*7c55ee0cSOmar Sandoval 
19*7c55ee0cSOmar Sandoval #include "btrfs-tests.h"
20*7c55ee0cSOmar Sandoval #include "../ctree.h"
21*7c55ee0cSOmar Sandoval #include "../disk-io.h"
22*7c55ee0cSOmar Sandoval #include "../free-space-tree.h"
23*7c55ee0cSOmar Sandoval #include "../transaction.h"
24*7c55ee0cSOmar Sandoval 
25*7c55ee0cSOmar Sandoval struct free_space_extent {
26*7c55ee0cSOmar Sandoval 	u64 start, length;
27*7c55ee0cSOmar Sandoval };
28*7c55ee0cSOmar Sandoval 
29*7c55ee0cSOmar Sandoval /*
30*7c55ee0cSOmar Sandoval  * The test cases align their operations to this in order to hit some of the
31*7c55ee0cSOmar Sandoval  * edge cases in the bitmap code.
32*7c55ee0cSOmar Sandoval  */
33*7c55ee0cSOmar Sandoval #define BITMAP_RANGE (BTRFS_FREE_SPACE_BITMAP_BITS * 4096)
34*7c55ee0cSOmar Sandoval 
35*7c55ee0cSOmar Sandoval static int __check_free_space_extents(struct btrfs_trans_handle *trans,
36*7c55ee0cSOmar Sandoval 				      struct btrfs_fs_info *fs_info,
37*7c55ee0cSOmar Sandoval 				      struct btrfs_block_group_cache *cache,
38*7c55ee0cSOmar Sandoval 				      struct btrfs_path *path,
39*7c55ee0cSOmar Sandoval 				      struct free_space_extent *extents,
40*7c55ee0cSOmar Sandoval 				      unsigned int num_extents)
41*7c55ee0cSOmar Sandoval {
42*7c55ee0cSOmar Sandoval 	struct btrfs_free_space_info *info;
43*7c55ee0cSOmar Sandoval 	struct btrfs_key key;
44*7c55ee0cSOmar Sandoval 	int prev_bit = 0, bit;
45*7c55ee0cSOmar Sandoval 	u64 extent_start = 0, offset, end;
46*7c55ee0cSOmar Sandoval 	u32 flags, extent_count;
47*7c55ee0cSOmar Sandoval 	unsigned int i;
48*7c55ee0cSOmar Sandoval 	int ret;
49*7c55ee0cSOmar Sandoval 
50*7c55ee0cSOmar Sandoval 	info = search_free_space_info(trans, fs_info, cache, path, 0);
51*7c55ee0cSOmar Sandoval 	if (IS_ERR(info)) {
52*7c55ee0cSOmar Sandoval 		test_msg("Could not find free space info\n");
53*7c55ee0cSOmar Sandoval 		ret = PTR_ERR(info);
54*7c55ee0cSOmar Sandoval 		goto out;
55*7c55ee0cSOmar Sandoval 	}
56*7c55ee0cSOmar Sandoval 	flags = btrfs_free_space_flags(path->nodes[0], info);
57*7c55ee0cSOmar Sandoval 	extent_count = btrfs_free_space_extent_count(path->nodes[0], info);
58*7c55ee0cSOmar Sandoval 
59*7c55ee0cSOmar Sandoval 	if (extent_count != num_extents) {
60*7c55ee0cSOmar Sandoval 		test_msg("Extent count is wrong\n");
61*7c55ee0cSOmar Sandoval 		ret = -EINVAL;
62*7c55ee0cSOmar Sandoval 		goto out;
63*7c55ee0cSOmar Sandoval 	}
64*7c55ee0cSOmar Sandoval 	if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
65*7c55ee0cSOmar Sandoval 		if (path->slots[0] != 0)
66*7c55ee0cSOmar Sandoval 			goto invalid;
67*7c55ee0cSOmar Sandoval 		end = cache->key.objectid + cache->key.offset;
68*7c55ee0cSOmar Sandoval 		i = 0;
69*7c55ee0cSOmar Sandoval 		while (++path->slots[0] < btrfs_header_nritems(path->nodes[0])) {
70*7c55ee0cSOmar Sandoval 			btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
71*7c55ee0cSOmar Sandoval 			if (key.type != BTRFS_FREE_SPACE_BITMAP_KEY)
72*7c55ee0cSOmar Sandoval 				goto invalid;
73*7c55ee0cSOmar Sandoval 			offset = key.objectid;
74*7c55ee0cSOmar Sandoval 			while (offset < key.objectid + key.offset) {
75*7c55ee0cSOmar Sandoval 				bit = free_space_test_bit(cache, path, offset);
76*7c55ee0cSOmar Sandoval 				if (prev_bit == 0 && bit == 1) {
77*7c55ee0cSOmar Sandoval 					extent_start = offset;
78*7c55ee0cSOmar Sandoval 				} else if (prev_bit == 1 && bit == 0) {
79*7c55ee0cSOmar Sandoval 					if (i >= num_extents)
80*7c55ee0cSOmar Sandoval 						goto invalid;
81*7c55ee0cSOmar Sandoval 					if (i >= num_extents ||
82*7c55ee0cSOmar Sandoval 					    extent_start != extents[i].start ||
83*7c55ee0cSOmar Sandoval 					    offset - extent_start != extents[i].length)
84*7c55ee0cSOmar Sandoval 						goto invalid;
85*7c55ee0cSOmar Sandoval 					i++;
86*7c55ee0cSOmar Sandoval 				}
87*7c55ee0cSOmar Sandoval 				prev_bit = bit;
88*7c55ee0cSOmar Sandoval 				offset += cache->sectorsize;
89*7c55ee0cSOmar Sandoval 			}
90*7c55ee0cSOmar Sandoval 		}
91*7c55ee0cSOmar Sandoval 		if (prev_bit == 1) {
92*7c55ee0cSOmar Sandoval 			if (i >= num_extents ||
93*7c55ee0cSOmar Sandoval 			    extent_start != extents[i].start ||
94*7c55ee0cSOmar Sandoval 			    end - extent_start != extents[i].length)
95*7c55ee0cSOmar Sandoval 				goto invalid;
96*7c55ee0cSOmar Sandoval 			i++;
97*7c55ee0cSOmar Sandoval 		}
98*7c55ee0cSOmar Sandoval 		if (i != num_extents)
99*7c55ee0cSOmar Sandoval 			goto invalid;
100*7c55ee0cSOmar Sandoval 	} else {
101*7c55ee0cSOmar Sandoval 		if (btrfs_header_nritems(path->nodes[0]) != num_extents + 1 ||
102*7c55ee0cSOmar Sandoval 		    path->slots[0] != 0)
103*7c55ee0cSOmar Sandoval 			goto invalid;
104*7c55ee0cSOmar Sandoval 		for (i = 0; i < num_extents; i++) {
105*7c55ee0cSOmar Sandoval 			path->slots[0]++;
106*7c55ee0cSOmar Sandoval 			btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
107*7c55ee0cSOmar Sandoval 			if (key.type != BTRFS_FREE_SPACE_EXTENT_KEY ||
108*7c55ee0cSOmar Sandoval 			    key.objectid != extents[i].start ||
109*7c55ee0cSOmar Sandoval 			    key.offset != extents[i].length)
110*7c55ee0cSOmar Sandoval 				goto invalid;
111*7c55ee0cSOmar Sandoval 		}
112*7c55ee0cSOmar Sandoval 	}
113*7c55ee0cSOmar Sandoval 
114*7c55ee0cSOmar Sandoval 	ret = 0;
115*7c55ee0cSOmar Sandoval out:
116*7c55ee0cSOmar Sandoval 	btrfs_release_path(path);
117*7c55ee0cSOmar Sandoval 	return ret;
118*7c55ee0cSOmar Sandoval invalid:
119*7c55ee0cSOmar Sandoval 	test_msg("Free space tree is invalid\n");
120*7c55ee0cSOmar Sandoval 	ret = -EINVAL;
121*7c55ee0cSOmar Sandoval 	goto out;
122*7c55ee0cSOmar Sandoval }
123*7c55ee0cSOmar Sandoval 
124*7c55ee0cSOmar Sandoval static int check_free_space_extents(struct btrfs_trans_handle *trans,
125*7c55ee0cSOmar Sandoval 				    struct btrfs_fs_info *fs_info,
126*7c55ee0cSOmar Sandoval 				    struct btrfs_block_group_cache *cache,
127*7c55ee0cSOmar Sandoval 				    struct btrfs_path *path,
128*7c55ee0cSOmar Sandoval 				    struct free_space_extent *extents,
129*7c55ee0cSOmar Sandoval 				    unsigned int num_extents)
130*7c55ee0cSOmar Sandoval {
131*7c55ee0cSOmar Sandoval 	struct btrfs_free_space_info *info;
132*7c55ee0cSOmar Sandoval 	u32 flags;
133*7c55ee0cSOmar Sandoval 	int ret;
134*7c55ee0cSOmar Sandoval 
135*7c55ee0cSOmar Sandoval 	info = search_free_space_info(trans, fs_info, cache, path, 0);
136*7c55ee0cSOmar Sandoval 	if (IS_ERR(info)) {
137*7c55ee0cSOmar Sandoval 		test_msg("Could not find free space info\n");
138*7c55ee0cSOmar Sandoval 		btrfs_release_path(path);
139*7c55ee0cSOmar Sandoval 		return PTR_ERR(info);
140*7c55ee0cSOmar Sandoval 	}
141*7c55ee0cSOmar Sandoval 	flags = btrfs_free_space_flags(path->nodes[0], info);
142*7c55ee0cSOmar Sandoval 	btrfs_release_path(path);
143*7c55ee0cSOmar Sandoval 
144*7c55ee0cSOmar Sandoval 	ret = __check_free_space_extents(trans, fs_info, cache, path, extents,
145*7c55ee0cSOmar Sandoval 					 num_extents);
146*7c55ee0cSOmar Sandoval 	if (ret)
147*7c55ee0cSOmar Sandoval 		return ret;
148*7c55ee0cSOmar Sandoval 
149*7c55ee0cSOmar Sandoval 	/* Flip it to the other format and check that for good measure. */
150*7c55ee0cSOmar Sandoval 	if (flags & BTRFS_FREE_SPACE_USING_BITMAPS) {
151*7c55ee0cSOmar Sandoval 		ret = convert_free_space_to_extents(trans, fs_info, cache, path);
152*7c55ee0cSOmar Sandoval 		if (ret) {
153*7c55ee0cSOmar Sandoval 			test_msg("Could not convert to extents\n");
154*7c55ee0cSOmar Sandoval 			return ret;
155*7c55ee0cSOmar Sandoval 		}
156*7c55ee0cSOmar Sandoval 	} else {
157*7c55ee0cSOmar Sandoval 		ret = convert_free_space_to_bitmaps(trans, fs_info, cache, path);
158*7c55ee0cSOmar Sandoval 		if (ret) {
159*7c55ee0cSOmar Sandoval 			test_msg("Could not convert to bitmaps\n");
160*7c55ee0cSOmar Sandoval 			return ret;
161*7c55ee0cSOmar Sandoval 		}
162*7c55ee0cSOmar Sandoval 	}
163*7c55ee0cSOmar Sandoval 	return __check_free_space_extents(trans, fs_info, cache, path, extents,
164*7c55ee0cSOmar Sandoval 					  num_extents);
165*7c55ee0cSOmar Sandoval }
166*7c55ee0cSOmar Sandoval 
167*7c55ee0cSOmar Sandoval static int test_empty_block_group(struct btrfs_trans_handle *trans,
168*7c55ee0cSOmar Sandoval 				  struct btrfs_fs_info *fs_info,
169*7c55ee0cSOmar Sandoval 				  struct btrfs_block_group_cache *cache,
170*7c55ee0cSOmar Sandoval 				  struct btrfs_path *path)
171*7c55ee0cSOmar Sandoval {
172*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
173*7c55ee0cSOmar Sandoval 		{cache->key.objectid, cache->key.offset},
174*7c55ee0cSOmar Sandoval 	};
175*7c55ee0cSOmar Sandoval 
176*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
177*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
178*7c55ee0cSOmar Sandoval }
179*7c55ee0cSOmar Sandoval 
180*7c55ee0cSOmar Sandoval static int test_remove_all(struct btrfs_trans_handle *trans,
181*7c55ee0cSOmar Sandoval 			   struct btrfs_fs_info *fs_info,
182*7c55ee0cSOmar Sandoval 			   struct btrfs_block_group_cache *cache,
183*7c55ee0cSOmar Sandoval 			   struct btrfs_path *path)
184*7c55ee0cSOmar Sandoval {
185*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {};
186*7c55ee0cSOmar Sandoval 	int ret;
187*7c55ee0cSOmar Sandoval 
188*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
189*7c55ee0cSOmar Sandoval 					    cache->key.objectid,
190*7c55ee0cSOmar Sandoval 					    cache->key.offset);
191*7c55ee0cSOmar Sandoval 	if (ret) {
192*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
193*7c55ee0cSOmar Sandoval 		return ret;
194*7c55ee0cSOmar Sandoval 	}
195*7c55ee0cSOmar Sandoval 
196*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
197*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
198*7c55ee0cSOmar Sandoval }
199*7c55ee0cSOmar Sandoval 
200*7c55ee0cSOmar Sandoval static int test_remove_beginning(struct btrfs_trans_handle *trans,
201*7c55ee0cSOmar Sandoval 				 struct btrfs_fs_info *fs_info,
202*7c55ee0cSOmar Sandoval 				 struct btrfs_block_group_cache *cache,
203*7c55ee0cSOmar Sandoval 				 struct btrfs_path *path)
204*7c55ee0cSOmar Sandoval {
205*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
206*7c55ee0cSOmar Sandoval 		{cache->key.objectid + BITMAP_RANGE,
207*7c55ee0cSOmar Sandoval 			cache->key.offset - BITMAP_RANGE},
208*7c55ee0cSOmar Sandoval 	};
209*7c55ee0cSOmar Sandoval 	int ret;
210*7c55ee0cSOmar Sandoval 
211*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
212*7c55ee0cSOmar Sandoval 					    cache->key.objectid, BITMAP_RANGE);
213*7c55ee0cSOmar Sandoval 	if (ret) {
214*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
215*7c55ee0cSOmar Sandoval 		return ret;
216*7c55ee0cSOmar Sandoval 	}
217*7c55ee0cSOmar Sandoval 
218*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
219*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
220*7c55ee0cSOmar Sandoval 
221*7c55ee0cSOmar Sandoval }
222*7c55ee0cSOmar Sandoval 
223*7c55ee0cSOmar Sandoval static int test_remove_end(struct btrfs_trans_handle *trans,
224*7c55ee0cSOmar Sandoval 			   struct btrfs_fs_info *fs_info,
225*7c55ee0cSOmar Sandoval 			   struct btrfs_block_group_cache *cache,
226*7c55ee0cSOmar Sandoval 			   struct btrfs_path *path)
227*7c55ee0cSOmar Sandoval {
228*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
229*7c55ee0cSOmar Sandoval 		{cache->key.objectid, cache->key.offset - BITMAP_RANGE},
230*7c55ee0cSOmar Sandoval 	};
231*7c55ee0cSOmar Sandoval 	int ret;
232*7c55ee0cSOmar Sandoval 
233*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
234*7c55ee0cSOmar Sandoval 					    cache->key.objectid +
235*7c55ee0cSOmar Sandoval 					    cache->key.offset - BITMAP_RANGE,
236*7c55ee0cSOmar Sandoval 					    BITMAP_RANGE);
237*7c55ee0cSOmar Sandoval 	if (ret) {
238*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
239*7c55ee0cSOmar Sandoval 		return ret;
240*7c55ee0cSOmar Sandoval 	}
241*7c55ee0cSOmar Sandoval 
242*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
243*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
244*7c55ee0cSOmar Sandoval }
245*7c55ee0cSOmar Sandoval 
246*7c55ee0cSOmar Sandoval static int test_remove_middle(struct btrfs_trans_handle *trans,
247*7c55ee0cSOmar Sandoval 			      struct btrfs_fs_info *fs_info,
248*7c55ee0cSOmar Sandoval 			      struct btrfs_block_group_cache *cache,
249*7c55ee0cSOmar Sandoval 			      struct btrfs_path *path)
250*7c55ee0cSOmar Sandoval {
251*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
252*7c55ee0cSOmar Sandoval 		{cache->key.objectid, BITMAP_RANGE},
253*7c55ee0cSOmar Sandoval 		{cache->key.objectid + 2 * BITMAP_RANGE,
254*7c55ee0cSOmar Sandoval 			cache->key.offset - 2 * BITMAP_RANGE},
255*7c55ee0cSOmar Sandoval 	};
256*7c55ee0cSOmar Sandoval 	int ret;
257*7c55ee0cSOmar Sandoval 
258*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
259*7c55ee0cSOmar Sandoval 					    cache->key.objectid + BITMAP_RANGE,
260*7c55ee0cSOmar Sandoval 					    BITMAP_RANGE);
261*7c55ee0cSOmar Sandoval 	if (ret) {
262*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
263*7c55ee0cSOmar Sandoval 		return ret;
264*7c55ee0cSOmar Sandoval 	}
265*7c55ee0cSOmar Sandoval 
266*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
267*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
268*7c55ee0cSOmar Sandoval }
269*7c55ee0cSOmar Sandoval 
270*7c55ee0cSOmar Sandoval static int test_merge_left(struct btrfs_trans_handle *trans,
271*7c55ee0cSOmar Sandoval 			   struct btrfs_fs_info *fs_info,
272*7c55ee0cSOmar Sandoval 			   struct btrfs_block_group_cache *cache,
273*7c55ee0cSOmar Sandoval 			   struct btrfs_path *path)
274*7c55ee0cSOmar Sandoval {
275*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
276*7c55ee0cSOmar Sandoval 		{cache->key.objectid, 2 * BITMAP_RANGE},
277*7c55ee0cSOmar Sandoval 	};
278*7c55ee0cSOmar Sandoval 	int ret;
279*7c55ee0cSOmar Sandoval 
280*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
281*7c55ee0cSOmar Sandoval 					    cache->key.objectid,
282*7c55ee0cSOmar Sandoval 					    cache->key.offset);
283*7c55ee0cSOmar Sandoval 	if (ret) {
284*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
285*7c55ee0cSOmar Sandoval 		return ret;
286*7c55ee0cSOmar Sandoval 	}
287*7c55ee0cSOmar Sandoval 
288*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
289*7c55ee0cSOmar Sandoval 				       cache->key.objectid, BITMAP_RANGE);
290*7c55ee0cSOmar Sandoval 	if (ret) {
291*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
292*7c55ee0cSOmar Sandoval 		return ret;
293*7c55ee0cSOmar Sandoval 	}
294*7c55ee0cSOmar Sandoval 
295*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
296*7c55ee0cSOmar Sandoval 				       cache->key.objectid + BITMAP_RANGE,
297*7c55ee0cSOmar Sandoval 				       BITMAP_RANGE);
298*7c55ee0cSOmar Sandoval 	if (ret) {
299*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
300*7c55ee0cSOmar Sandoval 		return ret;
301*7c55ee0cSOmar Sandoval 	}
302*7c55ee0cSOmar Sandoval 
303*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
304*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
305*7c55ee0cSOmar Sandoval }
306*7c55ee0cSOmar Sandoval 
307*7c55ee0cSOmar Sandoval static int test_merge_right(struct btrfs_trans_handle *trans,
308*7c55ee0cSOmar Sandoval 			   struct btrfs_fs_info *fs_info,
309*7c55ee0cSOmar Sandoval 			   struct btrfs_block_group_cache *cache,
310*7c55ee0cSOmar Sandoval 			   struct btrfs_path *path)
311*7c55ee0cSOmar Sandoval {
312*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
313*7c55ee0cSOmar Sandoval 		{cache->key.objectid + BITMAP_RANGE, 2 * BITMAP_RANGE},
314*7c55ee0cSOmar Sandoval 	};
315*7c55ee0cSOmar Sandoval 	int ret;
316*7c55ee0cSOmar Sandoval 
317*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
318*7c55ee0cSOmar Sandoval 					    cache->key.objectid,
319*7c55ee0cSOmar Sandoval 					    cache->key.offset);
320*7c55ee0cSOmar Sandoval 	if (ret) {
321*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
322*7c55ee0cSOmar Sandoval 		return ret;
323*7c55ee0cSOmar Sandoval 	}
324*7c55ee0cSOmar Sandoval 
325*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
326*7c55ee0cSOmar Sandoval 				       cache->key.objectid + 2 * BITMAP_RANGE,
327*7c55ee0cSOmar Sandoval 				       BITMAP_RANGE);
328*7c55ee0cSOmar Sandoval 	if (ret) {
329*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
330*7c55ee0cSOmar Sandoval 		return ret;
331*7c55ee0cSOmar Sandoval 	}
332*7c55ee0cSOmar Sandoval 
333*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
334*7c55ee0cSOmar Sandoval 				       cache->key.objectid + BITMAP_RANGE,
335*7c55ee0cSOmar Sandoval 				       BITMAP_RANGE);
336*7c55ee0cSOmar Sandoval 	if (ret) {
337*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
338*7c55ee0cSOmar Sandoval 		return ret;
339*7c55ee0cSOmar Sandoval 	}
340*7c55ee0cSOmar Sandoval 
341*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
342*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
343*7c55ee0cSOmar Sandoval }
344*7c55ee0cSOmar Sandoval 
345*7c55ee0cSOmar Sandoval static int test_merge_both(struct btrfs_trans_handle *trans,
346*7c55ee0cSOmar Sandoval 			   struct btrfs_fs_info *fs_info,
347*7c55ee0cSOmar Sandoval 			   struct btrfs_block_group_cache *cache,
348*7c55ee0cSOmar Sandoval 			   struct btrfs_path *path)
349*7c55ee0cSOmar Sandoval {
350*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
351*7c55ee0cSOmar Sandoval 		{cache->key.objectid, 3 * BITMAP_RANGE},
352*7c55ee0cSOmar Sandoval 	};
353*7c55ee0cSOmar Sandoval 	int ret;
354*7c55ee0cSOmar Sandoval 
355*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
356*7c55ee0cSOmar Sandoval 					    cache->key.objectid,
357*7c55ee0cSOmar Sandoval 					    cache->key.offset);
358*7c55ee0cSOmar Sandoval 	if (ret) {
359*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
360*7c55ee0cSOmar Sandoval 		return ret;
361*7c55ee0cSOmar Sandoval 	}
362*7c55ee0cSOmar Sandoval 
363*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
364*7c55ee0cSOmar Sandoval 				       cache->key.objectid, BITMAP_RANGE);
365*7c55ee0cSOmar Sandoval 	if (ret) {
366*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
367*7c55ee0cSOmar Sandoval 		return ret;
368*7c55ee0cSOmar Sandoval 	}
369*7c55ee0cSOmar Sandoval 
370*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
371*7c55ee0cSOmar Sandoval 				       cache->key.objectid + 2 * BITMAP_RANGE,
372*7c55ee0cSOmar Sandoval 				       BITMAP_RANGE);
373*7c55ee0cSOmar Sandoval 	if (ret) {
374*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
375*7c55ee0cSOmar Sandoval 		return ret;
376*7c55ee0cSOmar Sandoval 	}
377*7c55ee0cSOmar Sandoval 
378*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
379*7c55ee0cSOmar Sandoval 				       cache->key.objectid + BITMAP_RANGE,
380*7c55ee0cSOmar Sandoval 				       BITMAP_RANGE);
381*7c55ee0cSOmar Sandoval 	if (ret) {
382*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
383*7c55ee0cSOmar Sandoval 		return ret;
384*7c55ee0cSOmar Sandoval 	}
385*7c55ee0cSOmar Sandoval 
386*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
387*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
388*7c55ee0cSOmar Sandoval }
389*7c55ee0cSOmar Sandoval 
390*7c55ee0cSOmar Sandoval static int test_merge_none(struct btrfs_trans_handle *trans,
391*7c55ee0cSOmar Sandoval 			   struct btrfs_fs_info *fs_info,
392*7c55ee0cSOmar Sandoval 			   struct btrfs_block_group_cache *cache,
393*7c55ee0cSOmar Sandoval 			   struct btrfs_path *path)
394*7c55ee0cSOmar Sandoval {
395*7c55ee0cSOmar Sandoval 	struct free_space_extent extents[] = {
396*7c55ee0cSOmar Sandoval 		{cache->key.objectid, BITMAP_RANGE},
397*7c55ee0cSOmar Sandoval 		{cache->key.objectid + 2 * BITMAP_RANGE, BITMAP_RANGE},
398*7c55ee0cSOmar Sandoval 		{cache->key.objectid + 4 * BITMAP_RANGE, BITMAP_RANGE},
399*7c55ee0cSOmar Sandoval 	};
400*7c55ee0cSOmar Sandoval 	int ret;
401*7c55ee0cSOmar Sandoval 
402*7c55ee0cSOmar Sandoval 	ret = __remove_from_free_space_tree(trans, fs_info, cache, path,
403*7c55ee0cSOmar Sandoval 					    cache->key.objectid,
404*7c55ee0cSOmar Sandoval 					    cache->key.offset);
405*7c55ee0cSOmar Sandoval 	if (ret) {
406*7c55ee0cSOmar Sandoval 		test_msg("Could not remove free space\n");
407*7c55ee0cSOmar Sandoval 		return ret;
408*7c55ee0cSOmar Sandoval 	}
409*7c55ee0cSOmar Sandoval 
410*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
411*7c55ee0cSOmar Sandoval 				       cache->key.objectid, BITMAP_RANGE);
412*7c55ee0cSOmar Sandoval 	if (ret) {
413*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
414*7c55ee0cSOmar Sandoval 		return ret;
415*7c55ee0cSOmar Sandoval 	}
416*7c55ee0cSOmar Sandoval 
417*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
418*7c55ee0cSOmar Sandoval 				       cache->key.objectid + 4 * BITMAP_RANGE,
419*7c55ee0cSOmar Sandoval 				       BITMAP_RANGE);
420*7c55ee0cSOmar Sandoval 	if (ret) {
421*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
422*7c55ee0cSOmar Sandoval 		return ret;
423*7c55ee0cSOmar Sandoval 	}
424*7c55ee0cSOmar Sandoval 
425*7c55ee0cSOmar Sandoval 	ret = __add_to_free_space_tree(trans, fs_info, cache, path,
426*7c55ee0cSOmar Sandoval 				       cache->key.objectid + 2 * BITMAP_RANGE,
427*7c55ee0cSOmar Sandoval 				       BITMAP_RANGE);
428*7c55ee0cSOmar Sandoval 	if (ret) {
429*7c55ee0cSOmar Sandoval 		test_msg("Could not add free space\n");
430*7c55ee0cSOmar Sandoval 		return ret;
431*7c55ee0cSOmar Sandoval 	}
432*7c55ee0cSOmar Sandoval 
433*7c55ee0cSOmar Sandoval 	return check_free_space_extents(trans, fs_info, cache, path,
434*7c55ee0cSOmar Sandoval 					extents, ARRAY_SIZE(extents));
435*7c55ee0cSOmar Sandoval }
436*7c55ee0cSOmar Sandoval 
437*7c55ee0cSOmar Sandoval typedef int (*test_func_t)(struct btrfs_trans_handle *,
438*7c55ee0cSOmar Sandoval 			   struct btrfs_fs_info *,
439*7c55ee0cSOmar Sandoval 			   struct btrfs_block_group_cache *,
440*7c55ee0cSOmar Sandoval 			   struct btrfs_path *);
441*7c55ee0cSOmar Sandoval 
442*7c55ee0cSOmar Sandoval static int run_test(test_func_t test_func, int bitmaps)
443*7c55ee0cSOmar Sandoval {
444*7c55ee0cSOmar Sandoval 	struct btrfs_root *root = NULL;
445*7c55ee0cSOmar Sandoval 	struct btrfs_block_group_cache *cache = NULL;
446*7c55ee0cSOmar Sandoval 	struct btrfs_trans_handle trans;
447*7c55ee0cSOmar Sandoval 	struct btrfs_path *path = NULL;
448*7c55ee0cSOmar Sandoval 	int ret;
449*7c55ee0cSOmar Sandoval 
450*7c55ee0cSOmar Sandoval 	root = btrfs_alloc_dummy_root();
451*7c55ee0cSOmar Sandoval 	if (IS_ERR(root)) {
452*7c55ee0cSOmar Sandoval 		test_msg("Couldn't allocate dummy root\n");
453*7c55ee0cSOmar Sandoval 		ret = PTR_ERR(root);
454*7c55ee0cSOmar Sandoval 		goto out;
455*7c55ee0cSOmar Sandoval 	}
456*7c55ee0cSOmar Sandoval 
457*7c55ee0cSOmar Sandoval 	root->fs_info = btrfs_alloc_dummy_fs_info();
458*7c55ee0cSOmar Sandoval 	if (!root->fs_info) {
459*7c55ee0cSOmar Sandoval 		test_msg("Couldn't allocate dummy fs info\n");
460*7c55ee0cSOmar Sandoval 		ret = -ENOMEM;
461*7c55ee0cSOmar Sandoval 		goto out;
462*7c55ee0cSOmar Sandoval 	}
463*7c55ee0cSOmar Sandoval 
464*7c55ee0cSOmar Sandoval 	btrfs_set_super_compat_ro_flags(root->fs_info->super_copy,
465*7c55ee0cSOmar Sandoval 					BTRFS_FEATURE_COMPAT_RO_FREE_SPACE_TREE);
466*7c55ee0cSOmar Sandoval 	root->fs_info->free_space_root = root;
467*7c55ee0cSOmar Sandoval 	root->fs_info->tree_root = root;
468*7c55ee0cSOmar Sandoval 
469*7c55ee0cSOmar Sandoval 	root->node = alloc_test_extent_buffer(root->fs_info, 4096);
470*7c55ee0cSOmar Sandoval 	if (!root->node) {
471*7c55ee0cSOmar Sandoval 		test_msg("Couldn't allocate dummy buffer\n");
472*7c55ee0cSOmar Sandoval 		ret = -ENOMEM;
473*7c55ee0cSOmar Sandoval 		goto out;
474*7c55ee0cSOmar Sandoval 	}
475*7c55ee0cSOmar Sandoval 	btrfs_set_header_level(root->node, 0);
476*7c55ee0cSOmar Sandoval 	btrfs_set_header_nritems(root->node, 0);
477*7c55ee0cSOmar Sandoval 	root->alloc_bytenr += 8192;
478*7c55ee0cSOmar Sandoval 
479*7c55ee0cSOmar Sandoval 	cache = btrfs_alloc_dummy_block_group(8 * BITMAP_RANGE);
480*7c55ee0cSOmar Sandoval 	if (!cache) {
481*7c55ee0cSOmar Sandoval 		test_msg("Couldn't allocate dummy block group cache\n");
482*7c55ee0cSOmar Sandoval 		ret = -ENOMEM;
483*7c55ee0cSOmar Sandoval 		goto out;
484*7c55ee0cSOmar Sandoval 	}
485*7c55ee0cSOmar Sandoval 	cache->bitmap_low_thresh = 0;
486*7c55ee0cSOmar Sandoval 	cache->bitmap_high_thresh = (u32)-1;
487*7c55ee0cSOmar Sandoval 	cache->needs_free_space = 1;
488*7c55ee0cSOmar Sandoval 
489*7c55ee0cSOmar Sandoval 	btrfs_init_dummy_trans(&trans);
490*7c55ee0cSOmar Sandoval 
491*7c55ee0cSOmar Sandoval 	path = btrfs_alloc_path();
492*7c55ee0cSOmar Sandoval 	if (!path) {
493*7c55ee0cSOmar Sandoval 		test_msg("Couldn't allocate path\n");
494*7c55ee0cSOmar Sandoval 		return -ENOMEM;
495*7c55ee0cSOmar Sandoval 	}
496*7c55ee0cSOmar Sandoval 
497*7c55ee0cSOmar Sandoval 	ret = add_block_group_free_space(&trans, root->fs_info, cache);
498*7c55ee0cSOmar Sandoval 	if (ret) {
499*7c55ee0cSOmar Sandoval 		test_msg("Could not add block group free space\n");
500*7c55ee0cSOmar Sandoval 		goto out;
501*7c55ee0cSOmar Sandoval 	}
502*7c55ee0cSOmar Sandoval 
503*7c55ee0cSOmar Sandoval 	if (bitmaps) {
504*7c55ee0cSOmar Sandoval 		ret = convert_free_space_to_bitmaps(&trans, root->fs_info,
505*7c55ee0cSOmar Sandoval 						    cache, path);
506*7c55ee0cSOmar Sandoval 		if (ret) {
507*7c55ee0cSOmar Sandoval 			test_msg("Could not convert block group to bitmaps\n");
508*7c55ee0cSOmar Sandoval 			goto out;
509*7c55ee0cSOmar Sandoval 		}
510*7c55ee0cSOmar Sandoval 	}
511*7c55ee0cSOmar Sandoval 
512*7c55ee0cSOmar Sandoval 	ret = test_func(&trans, root->fs_info, cache, path);
513*7c55ee0cSOmar Sandoval 	if (ret)
514*7c55ee0cSOmar Sandoval 		goto out;
515*7c55ee0cSOmar Sandoval 
516*7c55ee0cSOmar Sandoval 	ret = remove_block_group_free_space(&trans, root->fs_info, cache);
517*7c55ee0cSOmar Sandoval 	if (ret) {
518*7c55ee0cSOmar Sandoval 		test_msg("Could not remove block group free space\n");
519*7c55ee0cSOmar Sandoval 		goto out;
520*7c55ee0cSOmar Sandoval 	}
521*7c55ee0cSOmar Sandoval 
522*7c55ee0cSOmar Sandoval 	if (btrfs_header_nritems(root->node) != 0) {
523*7c55ee0cSOmar Sandoval 		test_msg("Free space tree has leftover items\n");
524*7c55ee0cSOmar Sandoval 		ret = -EINVAL;
525*7c55ee0cSOmar Sandoval 		goto out;
526*7c55ee0cSOmar Sandoval 	}
527*7c55ee0cSOmar Sandoval 
528*7c55ee0cSOmar Sandoval 	ret = 0;
529*7c55ee0cSOmar Sandoval out:
530*7c55ee0cSOmar Sandoval 	btrfs_free_path(path);
531*7c55ee0cSOmar Sandoval 	btrfs_free_dummy_block_group(cache);
532*7c55ee0cSOmar Sandoval 	btrfs_free_dummy_root(root);
533*7c55ee0cSOmar Sandoval 	return ret;
534*7c55ee0cSOmar Sandoval }
535*7c55ee0cSOmar Sandoval 
536*7c55ee0cSOmar Sandoval static int run_test_both_formats(test_func_t test_func)
537*7c55ee0cSOmar Sandoval {
538*7c55ee0cSOmar Sandoval 	int ret;
539*7c55ee0cSOmar Sandoval 
540*7c55ee0cSOmar Sandoval 	ret = run_test(test_func, 0);
541*7c55ee0cSOmar Sandoval 	if (ret)
542*7c55ee0cSOmar Sandoval 		return ret;
543*7c55ee0cSOmar Sandoval 	return run_test(test_func, 1);
544*7c55ee0cSOmar Sandoval }
545*7c55ee0cSOmar Sandoval 
546*7c55ee0cSOmar Sandoval int btrfs_test_free_space_tree(void)
547*7c55ee0cSOmar Sandoval {
548*7c55ee0cSOmar Sandoval 	test_func_t tests[] = {
549*7c55ee0cSOmar Sandoval 		test_empty_block_group,
550*7c55ee0cSOmar Sandoval 		test_remove_all,
551*7c55ee0cSOmar Sandoval 		test_remove_beginning,
552*7c55ee0cSOmar Sandoval 		test_remove_end,
553*7c55ee0cSOmar Sandoval 		test_remove_middle,
554*7c55ee0cSOmar Sandoval 		test_merge_left,
555*7c55ee0cSOmar Sandoval 		test_merge_right,
556*7c55ee0cSOmar Sandoval 		test_merge_both,
557*7c55ee0cSOmar Sandoval 		test_merge_none,
558*7c55ee0cSOmar Sandoval 	};
559*7c55ee0cSOmar Sandoval 	int i;
560*7c55ee0cSOmar Sandoval 
561*7c55ee0cSOmar Sandoval 	test_msg("Running free space tree tests\n");
562*7c55ee0cSOmar Sandoval 	for (i = 0; i < ARRAY_SIZE(tests); i++) {
563*7c55ee0cSOmar Sandoval 		int ret = run_test_both_formats(tests[i]);
564*7c55ee0cSOmar Sandoval 		if (ret) {
565*7c55ee0cSOmar Sandoval 			test_msg("%pf failed\n", tests[i]);
566*7c55ee0cSOmar Sandoval 			return ret;
567*7c55ee0cSOmar Sandoval 		}
568*7c55ee0cSOmar Sandoval 	}
569*7c55ee0cSOmar Sandoval 
570*7c55ee0cSOmar Sandoval 	return 0;
571*7c55ee0cSOmar Sandoval }
572