2 * Copyright (C) 2008 Red Hat. All rights reserved.
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.
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.
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.
19 #include <linux/sched.h>
22 static int tree_insert_offset(struct rb_root
*root
, u64 offset
,
25 struct rb_node
**p
= &root
->rb_node
;
26 struct rb_node
*parent
= NULL
;
27 struct btrfs_free_space
*info
;
31 info
= rb_entry(parent
, struct btrfs_free_space
, offset_index
);
33 if (offset
< info
->offset
)
35 else if (offset
> info
->offset
)
41 rb_link_node(node
, parent
, p
);
42 rb_insert_color(node
, root
);
47 static int tree_insert_bytes(struct rb_root
*root
, u64 bytes
,
50 struct rb_node
**p
= &root
->rb_node
;
51 struct rb_node
*parent
= NULL
;
52 struct btrfs_free_space
*info
;
56 info
= rb_entry(parent
, struct btrfs_free_space
, bytes_index
);
58 if (bytes
< info
->bytes
)
64 rb_link_node(node
, parent
, p
);
65 rb_insert_color(node
, root
);
71 * searches the tree for the given offset. If contains is set we will return
72 * the free space that contains the given offset. If contains is not set we
73 * will return the free space that starts at or after the given offset and is
74 * at least bytes long.
76 static struct btrfs_free_space
*tree_search_offset(struct rb_root
*root
,
77 u64 offset
, u64 bytes
,
80 struct rb_node
*n
= root
->rb_node
;
81 struct btrfs_free_space
*entry
, *ret
= NULL
;
84 entry
= rb_entry(n
, struct btrfs_free_space
, offset_index
);
86 if (offset
< entry
->offset
) {
88 (!ret
|| entry
->offset
< ret
->offset
) &&
89 (bytes
<= entry
->bytes
))
92 } else if (offset
> entry
->offset
) {
93 if ((entry
->offset
+ entry
->bytes
- 1) >= offset
&&
94 bytes
<= entry
->bytes
) {
100 if (bytes
> entry
->bytes
) {
113 * return a chunk at least bytes size, as close to offset that we can get.
115 static struct btrfs_free_space
*tree_search_bytes(struct rb_root
*root
,
116 u64 offset
, u64 bytes
)
118 struct rb_node
*n
= root
->rb_node
;
119 struct btrfs_free_space
*entry
, *ret
= NULL
;
122 entry
= rb_entry(n
, struct btrfs_free_space
, bytes_index
);
124 if (bytes
< entry
->bytes
) {
126 * We prefer to get a hole size as close to the size we
127 * are asking for so we don't take small slivers out of
128 * huge holes, but we also want to get as close to the
129 * offset as possible so we don't have a whole lot of
132 if (offset
<= entry
->offset
) {
135 else if (entry
->bytes
< ret
->bytes
)
137 else if (entry
->offset
< ret
->offset
)
141 } else if (bytes
> entry
->bytes
) {
145 * Ok we may have multiple chunks of the wanted size,
146 * so we don't want to take the first one we find, we
147 * want to take the one closest to our given offset, so
148 * keep searching just in case theres a better match.
151 if (offset
> entry
->offset
)
153 else if (!ret
|| entry
->offset
< ret
->offset
)
161 static void unlink_free_space(struct btrfs_block_group_cache
*block_group
,
162 struct btrfs_free_space
*info
)
164 rb_erase(&info
->offset_index
, &block_group
->free_space_offset
);
165 rb_erase(&info
->bytes_index
, &block_group
->free_space_bytes
);
168 static int link_free_space(struct btrfs_block_group_cache
*block_group
,
169 struct btrfs_free_space
*info
)
174 ret
= tree_insert_offset(&block_group
->free_space_offset
, info
->offset
,
175 &info
->offset_index
);
179 ret
= tree_insert_bytes(&block_group
->free_space_bytes
, info
->bytes
,
187 static int __btrfs_add_free_space(struct btrfs_block_group_cache
*block_group
,
188 u64 offset
, u64 bytes
)
190 struct btrfs_free_space
*right_info
;
191 struct btrfs_free_space
*left_info
;
192 struct btrfs_free_space
*info
= NULL
;
193 struct btrfs_free_space
*alloc_info
;
196 alloc_info
= kzalloc(sizeof(struct btrfs_free_space
), GFP_NOFS
);
201 * first we want to see if there is free space adjacent to the range we
202 * are adding, if there is remove that struct and add a new one to
203 * cover the entire range
205 right_info
= tree_search_offset(&block_group
->free_space_offset
,
207 left_info
= tree_search_offset(&block_group
->free_space_offset
,
210 if (right_info
&& right_info
->offset
== offset
+bytes
) {
211 unlink_free_space(block_group
, right_info
);
213 info
->offset
= offset
;
214 info
->bytes
+= bytes
;
215 } else if (right_info
&& right_info
->offset
!= offset
+bytes
) {
216 printk(KERN_ERR
"adding space in the middle of an existing "
217 "free space area. existing: offset=%Lu, bytes=%Lu. "
218 "new: offset=%Lu, bytes=%Lu\n", right_info
->offset
,
219 right_info
->bytes
, offset
, bytes
);
224 unlink_free_space(block_group
, left_info
);
226 if (unlikely((left_info
->offset
+ left_info
->bytes
) !=
228 printk(KERN_ERR
"free space to the left of new free "
229 "space isn't quite right. existing: offset=%Lu,"
230 " bytes=%Lu. new: offset=%Lu, bytes=%Lu\n",
231 left_info
->offset
, left_info
->bytes
, offset
,
237 info
->offset
= left_info
->offset
;
238 info
->bytes
+= left_info
->bytes
;
242 info
->bytes
+= bytes
;
247 ret
= link_free_space(block_group
, info
);
255 info
->offset
= offset
;
258 ret
= link_free_space(block_group
, info
);
263 printk(KERN_ERR
"btrfs: unable to add free space :%d\n", ret
);
275 __btrfs_remove_free_space(struct btrfs_block_group_cache
*block_group
,
276 u64 offset
, u64 bytes
)
278 struct btrfs_free_space
*info
;
281 info
= tree_search_offset(&block_group
->free_space_offset
, offset
, 0,
284 if (info
&& info
->offset
== offset
) {
285 if (info
->bytes
< bytes
) {
286 printk(KERN_ERR
"Found free space at %Lu, size %Lu,"
287 "trying to use %Lu\n",
288 info
->offset
, info
->bytes
, bytes
);
294 unlink_free_space(block_group
, info
);
296 if (info
->bytes
== bytes
) {
301 info
->offset
+= bytes
;
302 info
->bytes
-= bytes
;
304 ret
= link_free_space(block_group
, info
);
306 } else if (info
&& info
->offset
< offset
&&
307 info
->offset
+ info
->bytes
>= offset
+ bytes
) {
308 u64 old_start
= info
->offset
;
310 * we're freeing space in the middle of the info,
311 * this can happen during tree log replay
313 * first unlink the old info and then
314 * insert it again after the hole we're creating
316 unlink_free_space(block_group
, info
);
317 if (offset
+ bytes
< info
->offset
+ info
->bytes
) {
318 u64 old_end
= info
->offset
+ info
->bytes
;
320 info
->offset
= offset
+ bytes
;
321 info
->bytes
= old_end
- info
->offset
;
322 ret
= link_free_space(block_group
, info
);
325 /* the hole we're creating ends at the end
326 * of the info struct, just free the info
331 /* step two, insert a new info struct to cover anything
334 ret
= __btrfs_add_free_space(block_group
, old_start
,
344 int btrfs_add_free_space(struct btrfs_block_group_cache
*block_group
,
345 u64 offset
, u64 bytes
)
348 struct btrfs_free_space
*sp
;
350 mutex_lock(&block_group
->alloc_mutex
);
351 ret
= __btrfs_add_free_space(block_group
, offset
, bytes
);
352 sp
= tree_search_offset(&block_group
->free_space_offset
, offset
, 0, 1);
354 mutex_unlock(&block_group
->alloc_mutex
);
359 int btrfs_add_free_space_lock(struct btrfs_block_group_cache
*block_group
,
360 u64 offset
, u64 bytes
)
363 struct btrfs_free_space
*sp
;
365 ret
= __btrfs_add_free_space(block_group
, offset
, bytes
);
366 sp
= tree_search_offset(&block_group
->free_space_offset
, offset
, 0, 1);
372 int btrfs_remove_free_space(struct btrfs_block_group_cache
*block_group
,
373 u64 offset
, u64 bytes
)
377 mutex_lock(&block_group
->alloc_mutex
);
378 ret
= __btrfs_remove_free_space(block_group
, offset
, bytes
);
379 mutex_unlock(&block_group
->alloc_mutex
);
384 int btrfs_remove_free_space_lock(struct btrfs_block_group_cache
*block_group
,
385 u64 offset
, u64 bytes
)
389 ret
= __btrfs_remove_free_space(block_group
, offset
, bytes
);
394 void btrfs_dump_free_space(struct btrfs_block_group_cache
*block_group
,
397 struct btrfs_free_space
*info
;
401 for (n
= rb_first(&block_group
->free_space_offset
); n
; n
= rb_next(n
)) {
402 info
= rb_entry(n
, struct btrfs_free_space
, offset_index
);
403 if (info
->bytes
>= bytes
)
405 //printk(KERN_INFO "offset=%Lu, bytes=%Lu\n", info->offset,
408 printk(KERN_INFO
"%d blocks of free space at or bigger than bytes is"
412 u64
btrfs_block_group_free_space(struct btrfs_block_group_cache
*block_group
)
414 struct btrfs_free_space
*info
;
418 for (n
= rb_first(&block_group
->free_space_offset
); n
;
420 info
= rb_entry(n
, struct btrfs_free_space
, offset_index
);
427 void btrfs_remove_free_space_cache(struct btrfs_block_group_cache
*block_group
)
429 struct btrfs_free_space
*info
;
430 struct rb_node
*node
;
432 mutex_lock(&block_group
->alloc_mutex
);
433 while ((node
= rb_last(&block_group
->free_space_bytes
)) != NULL
) {
434 info
= rb_entry(node
, struct btrfs_free_space
, bytes_index
);
435 unlink_free_space(block_group
, info
);
437 if (need_resched()) {
438 mutex_unlock(&block_group
->alloc_mutex
);
440 mutex_lock(&block_group
->alloc_mutex
);
443 mutex_unlock(&block_group
->alloc_mutex
);
446 struct btrfs_free_space
*btrfs_find_free_space_offset(struct
447 btrfs_block_group_cache
448 *block_group
, u64 offset
,
451 struct btrfs_free_space
*ret
;
453 mutex_lock(&block_group
->alloc_mutex
);
454 ret
= tree_search_offset(&block_group
->free_space_offset
, offset
,
456 mutex_unlock(&block_group
->alloc_mutex
);
461 struct btrfs_free_space
*btrfs_find_free_space_bytes(struct
462 btrfs_block_group_cache
463 *block_group
, u64 offset
,
466 struct btrfs_free_space
*ret
;
468 mutex_lock(&block_group
->alloc_mutex
);
470 ret
= tree_search_bytes(&block_group
->free_space_bytes
, offset
, bytes
);
471 mutex_unlock(&block_group
->alloc_mutex
);
476 struct btrfs_free_space
*btrfs_find_free_space(struct btrfs_block_group_cache
477 *block_group
, u64 offset
,
480 struct btrfs_free_space
*ret
= NULL
;
482 ret
= tree_search_offset(&block_group
->free_space_offset
, offset
,
485 ret
= tree_search_bytes(&block_group
->free_space_bytes
,