diff options
author | Chris Mason <chris.mason@oracle.com> | 2008-05-24 14:04:53 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2008-09-25 11:04:03 -0400 |
commit | 0ef3e66b6700eb8f052daa8b89443ff872fbbdfc (patch) | |
tree | 26bce57770b4f093199b6f87ab8ed3a54e951337 /fs/btrfs/extent-tree.c | |
parent | 515dc3228c568f9df8b634f82b3471e20205ac16 (diff) |
Btrfs: Allocator fix variety pack
* Force chunk allocation when find_free_extent has to do a full scan
* Record the max key at the start of defrag so it doesn't run forever
* Block groups might not be contiguous, make a forward search for the
next block group in extent-tree.c
* Get rid of extra checks for total fs size
* Fix relocate_one_reference to avoid relocating the same file data block
twice when referenced by an older transaction
* Use the open device count when allocating chunks so that we don't
try to allocate from devices that don't exist
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/extent-tree.c')
-rw-r--r-- | fs/btrfs/extent-tree.c | 273 |
1 files changed, 185 insertions, 88 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 605018c6045c..41a63462d3eb 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -136,6 +136,35 @@ err: | |||
136 | return 0; | 136 | return 0; |
137 | } | 137 | } |
138 | 138 | ||
139 | struct btrfs_block_group_cache *btrfs_lookup_first_block_group(struct | ||
140 | btrfs_fs_info *info, | ||
141 | u64 bytenr) | ||
142 | { | ||
143 | struct extent_io_tree *block_group_cache; | ||
144 | struct btrfs_block_group_cache *block_group = NULL; | ||
145 | u64 ptr; | ||
146 | u64 start; | ||
147 | u64 end; | ||
148 | int ret; | ||
149 | |||
150 | bytenr = max_t(u64, bytenr, | ||
151 | BTRFS_SUPER_INFO_OFFSET + BTRFS_SUPER_INFO_SIZE); | ||
152 | block_group_cache = &info->block_group_cache; | ||
153 | ret = find_first_extent_bit(block_group_cache, | ||
154 | bytenr, &start, &end, | ||
155 | BLOCK_GROUP_DATA | BLOCK_GROUP_METADATA | | ||
156 | BLOCK_GROUP_SYSTEM); | ||
157 | if (ret) { | ||
158 | return NULL; | ||
159 | } | ||
160 | ret = get_state_private(block_group_cache, start, &ptr); | ||
161 | if (ret) | ||
162 | return NULL; | ||
163 | |||
164 | block_group = (struct btrfs_block_group_cache *)(unsigned long)ptr; | ||
165 | return block_group; | ||
166 | } | ||
167 | |||
139 | struct btrfs_block_group_cache *btrfs_lookup_block_group(struct | 168 | struct btrfs_block_group_cache *btrfs_lookup_block_group(struct |
140 | btrfs_fs_info *info, | 169 | btrfs_fs_info *info, |
141 | u64 bytenr) | 170 | u64 bytenr) |
@@ -175,7 +204,7 @@ static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits) | |||
175 | 204 | ||
176 | static int noinline find_search_start(struct btrfs_root *root, | 205 | static int noinline find_search_start(struct btrfs_root *root, |
177 | struct btrfs_block_group_cache **cache_ret, | 206 | struct btrfs_block_group_cache **cache_ret, |
178 | u64 *start_ret, int num, int data) | 207 | u64 *start_ret, u64 num, int data) |
179 | { | 208 | { |
180 | int ret; | 209 | int ret; |
181 | struct btrfs_block_group_cache *cache = *cache_ret; | 210 | struct btrfs_block_group_cache *cache = *cache_ret; |
@@ -188,21 +217,21 @@ static int noinline find_search_start(struct btrfs_root *root, | |||
188 | u64 search_start = *start_ret; | 217 | u64 search_start = *start_ret; |
189 | int wrapped = 0; | 218 | int wrapped = 0; |
190 | 219 | ||
191 | if (!cache) | ||
192 | goto out; | ||
193 | |||
194 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); | 220 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); |
195 | free_space_cache = &root->fs_info->free_space_cache; | 221 | free_space_cache = &root->fs_info->free_space_cache; |
196 | 222 | ||
223 | if (!cache) | ||
224 | goto out; | ||
225 | |||
197 | again: | 226 | again: |
198 | ret = cache_block_group(root, cache); | 227 | ret = cache_block_group(root, cache); |
199 | if (ret) | 228 | if (ret) { |
200 | goto out; | 229 | goto out; |
230 | } | ||
201 | 231 | ||
202 | last = max(search_start, cache->key.objectid); | 232 | last = max(search_start, cache->key.objectid); |
203 | if (!block_group_bits(cache, data) || cache->ro) { | 233 | if (!block_group_bits(cache, data) || cache->ro) |
204 | goto new_group; | 234 | goto new_group; |
205 | } | ||
206 | 235 | ||
207 | spin_lock_irq(&free_space_cache->lock); | 236 | spin_lock_irq(&free_space_cache->lock); |
208 | state = find_first_extent_bit_state(free_space_cache, last, EXTENT_DIRTY); | 237 | state = find_first_extent_bit_state(free_space_cache, last, EXTENT_DIRTY); |
@@ -217,20 +246,17 @@ again: | |||
217 | start = max(last, state->start); | 246 | start = max(last, state->start); |
218 | last = state->end + 1; | 247 | last = state->end + 1; |
219 | if (last - start < num) { | 248 | if (last - start < num) { |
220 | if (last == cache->key.objectid + cache->key.offset) | ||
221 | cache_miss = start; | ||
222 | do { | 249 | do { |
223 | state = extent_state_next(state); | 250 | state = extent_state_next(state); |
224 | } while(state && !(state->state & EXTENT_DIRTY)); | 251 | } while(state && !(state->state & EXTENT_DIRTY)); |
225 | continue; | 252 | continue; |
226 | } | 253 | } |
227 | spin_unlock_irq(&free_space_cache->lock); | 254 | spin_unlock_irq(&free_space_cache->lock); |
228 | if (cache->ro) | 255 | if (cache->ro) { |
229 | goto new_group; | 256 | goto new_group; |
257 | } | ||
230 | if (start + num > cache->key.objectid + cache->key.offset) | 258 | if (start + num > cache->key.objectid + cache->key.offset) |
231 | goto new_group; | 259 | goto new_group; |
232 | if (start + num > total_fs_bytes) | ||
233 | goto new_group; | ||
234 | if (!block_group_bits(cache, data)) { | 260 | if (!block_group_bits(cache, data)) { |
235 | printk("block group bits don't match %Lu %d\n", cache->flags, data); | 261 | printk("block group bits don't match %Lu %d\n", cache->flags, data); |
236 | } | 262 | } |
@@ -248,7 +274,7 @@ out: | |||
248 | new_group: | 274 | new_group: |
249 | last = cache->key.objectid + cache->key.offset; | 275 | last = cache->key.objectid + cache->key.offset; |
250 | wrapped: | 276 | wrapped: |
251 | cache = btrfs_lookup_block_group(root->fs_info, last); | 277 | cache = btrfs_lookup_first_block_group(root->fs_info, last); |
252 | if (!cache || cache->key.objectid >= total_fs_bytes) { | 278 | if (!cache || cache->key.objectid >= total_fs_bytes) { |
253 | no_cache: | 279 | no_cache: |
254 | if (!wrapped) { | 280 | if (!wrapped) { |
@@ -261,13 +287,13 @@ no_cache: | |||
261 | if (cache_miss && !cache->cached) { | 287 | if (cache_miss && !cache->cached) { |
262 | cache_block_group(root, cache); | 288 | cache_block_group(root, cache); |
263 | last = cache_miss; | 289 | last = cache_miss; |
264 | cache = btrfs_lookup_block_group(root->fs_info, last); | 290 | cache = btrfs_lookup_first_block_group(root->fs_info, last); |
265 | } | 291 | } |
292 | cache_miss = 0; | ||
266 | cache = btrfs_find_block_group(root, cache, last, data, 0); | 293 | cache = btrfs_find_block_group(root, cache, last, data, 0); |
267 | if (!cache) | 294 | if (!cache) |
268 | goto no_cache; | 295 | goto no_cache; |
269 | *cache_ret = cache; | 296 | *cache_ret = cache; |
270 | cache_miss = 0; | ||
271 | goto again; | 297 | goto again; |
272 | } | 298 | } |
273 | 299 | ||
@@ -303,28 +329,26 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
303 | struct btrfs_fs_info *info = root->fs_info; | 329 | struct btrfs_fs_info *info = root->fs_info; |
304 | u64 used; | 330 | u64 used; |
305 | u64 last = 0; | 331 | u64 last = 0; |
306 | u64 hint_last; | ||
307 | u64 start; | 332 | u64 start; |
308 | u64 end; | 333 | u64 end; |
309 | u64 free_check; | 334 | u64 free_check; |
310 | u64 ptr; | 335 | u64 ptr; |
311 | u64 total_fs_bytes; | ||
312 | int bit; | 336 | int bit; |
313 | int ret; | 337 | int ret; |
314 | int full_search = 0; | 338 | int full_search = 0; |
315 | int factor = 10; | 339 | int factor = 10; |
340 | int wrapped = 0; | ||
316 | 341 | ||
317 | block_group_cache = &info->block_group_cache; | 342 | block_group_cache = &info->block_group_cache; |
318 | total_fs_bytes = btrfs_super_total_bytes(&root->fs_info->super_copy); | ||
319 | 343 | ||
320 | if (data & BTRFS_BLOCK_GROUP_METADATA) | 344 | if (data & BTRFS_BLOCK_GROUP_METADATA) |
321 | factor = 9; | 345 | factor = 9; |
322 | 346 | ||
323 | bit = block_group_state_bits(data); | 347 | bit = block_group_state_bits(data); |
324 | 348 | ||
325 | if (search_start && search_start < total_fs_bytes) { | 349 | if (search_start) { |
326 | struct btrfs_block_group_cache *shint; | 350 | struct btrfs_block_group_cache *shint; |
327 | shint = btrfs_lookup_block_group(info, search_start); | 351 | shint = btrfs_lookup_first_block_group(info, search_start); |
328 | if (shint && block_group_bits(shint, data) && !shint->ro) { | 352 | if (shint && block_group_bits(shint, data) && !shint->ro) { |
329 | used = btrfs_block_group_used(&shint->item); | 353 | used = btrfs_block_group_used(&shint->item); |
330 | if (used + shint->pinned < | 354 | if (used + shint->pinned < |
@@ -333,24 +357,18 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
333 | } | 357 | } |
334 | } | 358 | } |
335 | } | 359 | } |
336 | if (hint && !hint->ro && block_group_bits(hint, data) && | 360 | if (hint && !hint->ro && block_group_bits(hint, data)) { |
337 | hint->key.objectid < total_fs_bytes) { | ||
338 | used = btrfs_block_group_used(&hint->item); | 361 | used = btrfs_block_group_used(&hint->item); |
339 | if (used + hint->pinned < | 362 | if (used + hint->pinned < |
340 | div_factor(hint->key.offset, factor)) { | 363 | div_factor(hint->key.offset, factor)) { |
341 | return hint; | 364 | return hint; |
342 | } | 365 | } |
343 | last = hint->key.objectid + hint->key.offset; | 366 | last = hint->key.objectid + hint->key.offset; |
344 | hint_last = last; | ||
345 | } else { | 367 | } else { |
346 | if (hint) | 368 | if (hint) |
347 | hint_last = max(hint->key.objectid, search_start); | 369 | last = max(hint->key.objectid, search_start); |
348 | else | 370 | else |
349 | hint_last = search_start; | 371 | last = search_start; |
350 | |||
351 | if (hint_last >= total_fs_bytes) | ||
352 | hint_last = search_start; | ||
353 | last = hint_last; | ||
354 | } | 372 | } |
355 | again: | 373 | again: |
356 | while(1) { | 374 | while(1) { |
@@ -360,23 +378,17 @@ again: | |||
360 | break; | 378 | break; |
361 | 379 | ||
362 | ret = get_state_private(block_group_cache, start, &ptr); | 380 | ret = get_state_private(block_group_cache, start, &ptr); |
363 | if (ret) | 381 | if (ret) { |
364 | break; | 382 | last = end + 1; |
383 | continue; | ||
384 | } | ||
365 | 385 | ||
366 | cache = (struct btrfs_block_group_cache *)(unsigned long)ptr; | 386 | cache = (struct btrfs_block_group_cache *)(unsigned long)ptr; |
367 | last = cache->key.objectid + cache->key.offset; | 387 | last = cache->key.objectid + cache->key.offset; |
368 | used = btrfs_block_group_used(&cache->item); | 388 | used = btrfs_block_group_used(&cache->item); |
369 | 389 | ||
370 | if (cache->key.objectid > total_fs_bytes) | ||
371 | break; | ||
372 | |||
373 | if (!cache->ro && block_group_bits(cache, data)) { | 390 | if (!cache->ro && block_group_bits(cache, data)) { |
374 | if (full_search) | 391 | free_check = div_factor(cache->key.offset, factor); |
375 | free_check = cache->key.offset; | ||
376 | else | ||
377 | free_check = div_factor(cache->key.offset, | ||
378 | factor); | ||
379 | |||
380 | if (used + cache->pinned < free_check) { | 392 | if (used + cache->pinned < free_check) { |
381 | found_group = cache; | 393 | found_group = cache; |
382 | goto found; | 394 | goto found; |
@@ -384,9 +396,15 @@ again: | |||
384 | } | 396 | } |
385 | cond_resched(); | 397 | cond_resched(); |
386 | } | 398 | } |
387 | if (!full_search) { | 399 | if (!wrapped) { |
400 | last = search_start; | ||
401 | wrapped = 1; | ||
402 | goto again; | ||
403 | } | ||
404 | if (!full_search && factor < 10) { | ||
388 | last = search_start; | 405 | last = search_start; |
389 | full_search = 1; | 406 | full_search = 1; |
407 | factor = 10; | ||
390 | goto again; | 408 | goto again; |
391 | } | 409 | } |
392 | found: | 410 | found: |
@@ -1070,6 +1088,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags, | |||
1070 | found->bytes_used = bytes_used; | 1088 | found->bytes_used = bytes_used; |
1071 | found->bytes_pinned = 0; | 1089 | found->bytes_pinned = 0; |
1072 | found->full = 0; | 1090 | found->full = 0; |
1091 | found->force_alloc = 0; | ||
1073 | *space_info = found; | 1092 | *space_info = found; |
1074 | return 0; | 1093 | return 0; |
1075 | } | 1094 | } |
@@ -1120,7 +1139,7 @@ static u64 reduce_alloc_profile(struct btrfs_root *root, u64 flags) | |||
1120 | 1139 | ||
1121 | static int do_chunk_alloc(struct btrfs_trans_handle *trans, | 1140 | static int do_chunk_alloc(struct btrfs_trans_handle *trans, |
1122 | struct btrfs_root *extent_root, u64 alloc_bytes, | 1141 | struct btrfs_root *extent_root, u64 alloc_bytes, |
1123 | u64 flags) | 1142 | u64 flags, int force) |
1124 | { | 1143 | { |
1125 | struct btrfs_space_info *space_info; | 1144 | struct btrfs_space_info *space_info; |
1126 | u64 thresh; | 1145 | u64 thresh; |
@@ -1138,11 +1157,16 @@ static int do_chunk_alloc(struct btrfs_trans_handle *trans, | |||
1138 | } | 1157 | } |
1139 | BUG_ON(!space_info); | 1158 | BUG_ON(!space_info); |
1140 | 1159 | ||
1160 | if (space_info->force_alloc) { | ||
1161 | force = 1; | ||
1162 | space_info->force_alloc = 0; | ||
1163 | } | ||
1141 | if (space_info->full) | 1164 | if (space_info->full) |
1142 | return 0; | 1165 | return 0; |
1143 | 1166 | ||
1144 | thresh = div_factor(space_info->total_bytes, 6); | 1167 | thresh = div_factor(space_info->total_bytes, 6); |
1145 | if ((space_info->bytes_used + space_info->bytes_pinned + alloc_bytes) < | 1168 | if (!force && |
1169 | (space_info->bytes_used + space_info->bytes_pinned + alloc_bytes) < | ||
1146 | thresh) | 1170 | thresh) |
1147 | return 0; | 1171 | return 0; |
1148 | 1172 | ||
@@ -1152,7 +1176,6 @@ printk("space info full %Lu\n", flags); | |||
1152 | space_info->full = 1; | 1176 | space_info->full = 1; |
1153 | return 0; | 1177 | return 0; |
1154 | } | 1178 | } |
1155 | |||
1156 | BUG_ON(ret); | 1179 | BUG_ON(ret); |
1157 | 1180 | ||
1158 | ret = btrfs_make_block_group(trans, extent_root, 0, flags, | 1181 | ret = btrfs_make_block_group(trans, extent_root, 0, flags, |
@@ -1619,11 +1642,16 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, | |||
1619 | struct btrfs_block_group_cache *block_group; | 1642 | struct btrfs_block_group_cache *block_group; |
1620 | int full_scan = 0; | 1643 | int full_scan = 0; |
1621 | int wrapped = 0; | 1644 | int wrapped = 0; |
1645 | int chunk_alloc_done = 0; | ||
1622 | int empty_cluster = 2 * 1024 * 1024; | 1646 | int empty_cluster = 2 * 1024 * 1024; |
1647 | int allowed_chunk_alloc = 0; | ||
1623 | 1648 | ||
1624 | WARN_ON(num_bytes < root->sectorsize); | 1649 | WARN_ON(num_bytes < root->sectorsize); |
1625 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); | 1650 | btrfs_set_key_type(ins, BTRFS_EXTENT_ITEM_KEY); |
1626 | 1651 | ||
1652 | if (orig_root->ref_cows || empty_size) | ||
1653 | allowed_chunk_alloc = 1; | ||
1654 | |||
1627 | if (data & BTRFS_BLOCK_GROUP_METADATA) { | 1655 | if (data & BTRFS_BLOCK_GROUP_METADATA) { |
1628 | last_ptr = &root->fs_info->last_alloc; | 1656 | last_ptr = &root->fs_info->last_alloc; |
1629 | empty_cluster = 256 * 1024; | 1657 | empty_cluster = 256 * 1024; |
@@ -1648,7 +1676,7 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, | |||
1648 | search_end = btrfs_super_total_bytes(&info->super_copy); | 1676 | search_end = btrfs_super_total_bytes(&info->super_copy); |
1649 | 1677 | ||
1650 | if (hint_byte) { | 1678 | if (hint_byte) { |
1651 | block_group = btrfs_lookup_block_group(info, hint_byte); | 1679 | block_group = btrfs_lookup_first_block_group(info, hint_byte); |
1652 | if (!block_group) | 1680 | if (!block_group) |
1653 | hint_byte = search_start; | 1681 | hint_byte = search_start; |
1654 | block_group = btrfs_find_block_group(root, block_group, | 1682 | block_group = btrfs_find_block_group(root, block_group, |
@@ -1666,17 +1694,28 @@ static int noinline find_free_extent(struct btrfs_trans_handle *trans, | |||
1666 | 1694 | ||
1667 | check_failed: | 1695 | check_failed: |
1668 | if (!block_group) { | 1696 | if (!block_group) { |
1669 | block_group = btrfs_lookup_block_group(info, search_start); | 1697 | block_group = btrfs_lookup_first_block_group(info, |
1698 | search_start); | ||
1670 | if (!block_group) | 1699 | if (!block_group) |
1671 | block_group = btrfs_lookup_block_group(info, | 1700 | block_group = btrfs_lookup_first_block_group(info, |
1672 | orig_search_start); | 1701 | orig_search_start); |
1673 | } | 1702 | } |
1703 | if (full_scan && !chunk_alloc_done) { | ||
1704 | if (allowed_chunk_alloc) { | ||
1705 | do_chunk_alloc(trans, root, | ||
1706 | num_bytes + 2 * 1024 * 1024, data, 1); | ||
1707 | allowed_chunk_alloc = 0; | ||
1708 | } else if (block_group && block_group_bits(block_group, data)) { | ||
1709 | block_group->space_info->force_alloc = 1; | ||
1710 | } | ||
1711 | chunk_alloc_done = 1; | ||
1712 | } | ||
1674 | ret = find_search_start(root, &block_group, &search_start, | 1713 | ret = find_search_start(root, &block_group, &search_start, |
1675 | total_needed, data); | 1714 | total_needed, data); |
1676 | if (ret == -ENOSPC && last_ptr && *last_ptr) { | 1715 | if (ret == -ENOSPC && last_ptr && *last_ptr) { |
1677 | *last_ptr = 0; | 1716 | *last_ptr = 0; |
1678 | block_group = btrfs_lookup_block_group(info, | 1717 | block_group = btrfs_lookup_first_block_group(info, |
1679 | orig_search_start); | 1718 | orig_search_start); |
1680 | search_start = orig_search_start; | 1719 | search_start = orig_search_start; |
1681 | ret = find_search_start(root, &block_group, &search_start, | 1720 | ret = find_search_start(root, &block_group, &search_start, |
1682 | total_needed, data); | 1721 | total_needed, data); |
@@ -1692,7 +1731,7 @@ check_failed: | |||
1692 | empty_size += empty_cluster; | 1731 | empty_size += empty_cluster; |
1693 | total_needed += empty_size; | 1732 | total_needed += empty_size; |
1694 | } | 1733 | } |
1695 | block_group = btrfs_lookup_block_group(info, | 1734 | block_group = btrfs_lookup_first_block_group(info, |
1696 | orig_search_start); | 1735 | orig_search_start); |
1697 | search_start = orig_search_start; | 1736 | search_start = orig_search_start; |
1698 | ret = find_search_start(root, &block_group, | 1737 | ret = find_search_start(root, &block_group, |
@@ -1765,7 +1804,7 @@ enospc: | |||
1765 | } else | 1804 | } else |
1766 | wrapped = 1; | 1805 | wrapped = 1; |
1767 | } | 1806 | } |
1768 | block_group = btrfs_lookup_block_group(info, search_start); | 1807 | block_group = btrfs_lookup_first_block_group(info, search_start); |
1769 | cond_resched(); | 1808 | cond_resched(); |
1770 | block_group = btrfs_find_block_group(root, block_group, | 1809 | block_group = btrfs_find_block_group(root, block_group, |
1771 | search_start, data, 0); | 1810 | search_start, data, 0); |
@@ -1819,17 +1858,21 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1819 | } | 1858 | } |
1820 | again: | 1859 | again: |
1821 | data = reduce_alloc_profile(root, data); | 1860 | data = reduce_alloc_profile(root, data); |
1822 | if (root->ref_cows) { | 1861 | /* |
1862 | * the only place that sets empty_size is btrfs_realloc_node, which | ||
1863 | * is not called recursively on allocations | ||
1864 | */ | ||
1865 | if (empty_size || root->ref_cows) { | ||
1823 | if (!(data & BTRFS_BLOCK_GROUP_METADATA)) { | 1866 | if (!(data & BTRFS_BLOCK_GROUP_METADATA)) { |
1824 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | 1867 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, |
1825 | 2 * 1024 * 1024, | 1868 | 2 * 1024 * 1024, |
1826 | BTRFS_BLOCK_GROUP_METADATA | | 1869 | BTRFS_BLOCK_GROUP_METADATA | |
1827 | (info->metadata_alloc_profile & | 1870 | (info->metadata_alloc_profile & |
1828 | info->avail_metadata_alloc_bits)); | 1871 | info->avail_metadata_alloc_bits), 0); |
1829 | BUG_ON(ret); | 1872 | BUG_ON(ret); |
1830 | } | 1873 | } |
1831 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, | 1874 | ret = do_chunk_alloc(trans, root->fs_info->extent_root, |
1832 | num_bytes + 2 * 1024 * 1024, data); | 1875 | num_bytes + 2 * 1024 * 1024, data, 0); |
1833 | BUG_ON(ret); | 1876 | BUG_ON(ret); |
1834 | } | 1877 | } |
1835 | 1878 | ||
@@ -1842,6 +1885,8 @@ again: | |||
1842 | if (ret == -ENOSPC && num_bytes > min_alloc_size) { | 1885 | if (ret == -ENOSPC && num_bytes > min_alloc_size) { |
1843 | num_bytes = num_bytes >> 1; | 1886 | num_bytes = num_bytes >> 1; |
1844 | num_bytes = max(num_bytes, min_alloc_size); | 1887 | num_bytes = max(num_bytes, min_alloc_size); |
1888 | do_chunk_alloc(trans, root->fs_info->extent_root, | ||
1889 | num_bytes, data, 1); | ||
1845 | goto again; | 1890 | goto again; |
1846 | } | 1891 | } |
1847 | if (ret) { | 1892 | if (ret) { |
@@ -2537,7 +2582,11 @@ out: | |||
2537 | */ | 2582 | */ |
2538 | static int noinline relocate_one_reference(struct btrfs_root *extent_root, | 2583 | static int noinline relocate_one_reference(struct btrfs_root *extent_root, |
2539 | struct btrfs_path *path, | 2584 | struct btrfs_path *path, |
2540 | struct btrfs_key *extent_key) | 2585 | struct btrfs_key *extent_key, |
2586 | u64 *last_file_objectid, | ||
2587 | u64 *last_file_offset, | ||
2588 | u64 *last_file_root, | ||
2589 | u64 last_extent) | ||
2541 | { | 2590 | { |
2542 | struct inode *inode; | 2591 | struct inode *inode; |
2543 | struct btrfs_root *found_root; | 2592 | struct btrfs_root *found_root; |
@@ -2576,6 +2625,12 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2576 | found_key.offset = ref_offset; | 2625 | found_key.offset = ref_offset; |
2577 | level = 0; | 2626 | level = 0; |
2578 | 2627 | ||
2628 | if (last_extent == extent_key->objectid && | ||
2629 | *last_file_objectid == ref_objectid && | ||
2630 | *last_file_offset == ref_offset && | ||
2631 | *last_file_root == ref_root) | ||
2632 | goto out; | ||
2633 | |||
2579 | ret = find_root_for_ref(extent_root, path, &found_key, | 2634 | ret = find_root_for_ref(extent_root, path, &found_key, |
2580 | level, 1, &found_root, | 2635 | level, 1, &found_root, |
2581 | extent_key->objectid); | 2636 | extent_key->objectid); |
@@ -2583,6 +2638,12 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2583 | if (ret) | 2638 | if (ret) |
2584 | goto out; | 2639 | goto out; |
2585 | 2640 | ||
2641 | if (last_extent == extent_key->objectid && | ||
2642 | *last_file_objectid == ref_objectid && | ||
2643 | *last_file_offset == ref_offset && | ||
2644 | *last_file_root == ref_root) | ||
2645 | goto out; | ||
2646 | |||
2586 | mutex_unlock(&extent_root->fs_info->fs_mutex); | 2647 | mutex_unlock(&extent_root->fs_info->fs_mutex); |
2587 | inode = btrfs_iget_locked(extent_root->fs_info->sb, | 2648 | inode = btrfs_iget_locked(extent_root->fs_info->sb, |
2588 | ref_objectid, found_root); | 2649 | ref_objectid, found_root); |
@@ -2603,6 +2664,10 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2603 | mutex_lock(&extent_root->fs_info->fs_mutex); | 2664 | mutex_lock(&extent_root->fs_info->fs_mutex); |
2604 | goto out; | 2665 | goto out; |
2605 | } | 2666 | } |
2667 | *last_file_objectid = inode->i_ino; | ||
2668 | *last_file_root = found_root->root_key.objectid; | ||
2669 | *last_file_offset = ref_offset; | ||
2670 | |||
2606 | relocate_inode_pages(inode, ref_offset, extent_key->offset); | 2671 | relocate_inode_pages(inode, ref_offset, extent_key->offset); |
2607 | iput(inode); | 2672 | iput(inode); |
2608 | mutex_lock(&extent_root->fs_info->fs_mutex); | 2673 | mutex_lock(&extent_root->fs_info->fs_mutex); |
@@ -2643,6 +2708,8 @@ static int noinline relocate_one_reference(struct btrfs_root *extent_root, | |||
2643 | path->nodes[i] = NULL; | 2708 | path->nodes[i] = NULL; |
2644 | } | 2709 | } |
2645 | btrfs_release_path(found_root, path); | 2710 | btrfs_release_path(found_root, path); |
2711 | if (found_root == found_root->fs_info->extent_root) | ||
2712 | btrfs_extent_post_op(trans, found_root); | ||
2646 | btrfs_end_transaction(trans, found_root); | 2713 | btrfs_end_transaction(trans, found_root); |
2647 | } | 2714 | } |
2648 | 2715 | ||
@@ -2678,6 +2745,10 @@ static int noinline relocate_one_extent(struct btrfs_root *extent_root, | |||
2678 | struct btrfs_key key; | 2745 | struct btrfs_key key; |
2679 | struct btrfs_key found_key; | 2746 | struct btrfs_key found_key; |
2680 | struct extent_buffer *leaf; | 2747 | struct extent_buffer *leaf; |
2748 | u64 last_file_objectid = 0; | ||
2749 | u64 last_file_root = 0; | ||
2750 | u64 last_file_offset = (u64)-1; | ||
2751 | u64 last_extent = 0; | ||
2681 | u32 nritems; | 2752 | u32 nritems; |
2682 | u32 item_size; | 2753 | u32 item_size; |
2683 | int ret = 0; | 2754 | int ret = 0; |
@@ -2722,9 +2793,13 @@ static int noinline relocate_one_extent(struct btrfs_root *extent_root, | |||
2722 | key.offset = found_key.offset + 1; | 2793 | key.offset = found_key.offset + 1; |
2723 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); | 2794 | item_size = btrfs_item_size_nr(leaf, path->slots[0]); |
2724 | 2795 | ||
2725 | ret = relocate_one_reference(extent_root, path, extent_key); | 2796 | ret = relocate_one_reference(extent_root, path, extent_key, |
2797 | &last_file_objectid, | ||
2798 | &last_file_offset, | ||
2799 | &last_file_root, last_extent); | ||
2726 | if (ret) | 2800 | if (ret) |
2727 | goto out; | 2801 | goto out; |
2802 | last_extent = extent_key->objectid; | ||
2728 | } | 2803 | } |
2729 | ret = 0; | 2804 | ret = 0; |
2730 | out: | 2805 | out: |
@@ -2770,6 +2845,32 @@ static u64 update_block_group_flags(struct btrfs_root *root, u64 flags) | |||
2770 | return flags; | 2845 | return flags; |
2771 | } | 2846 | } |
2772 | 2847 | ||
2848 | int __alloc_chunk_for_shrink(struct btrfs_root *root, | ||
2849 | struct btrfs_block_group_cache *shrink_block_group, | ||
2850 | int force) | ||
2851 | { | ||
2852 | struct btrfs_trans_handle *trans; | ||
2853 | u64 new_alloc_flags; | ||
2854 | u64 calc; | ||
2855 | |||
2856 | if (btrfs_block_group_used(&shrink_block_group->item) > 0) { | ||
2857 | |||
2858 | trans = btrfs_start_transaction(root, 1); | ||
2859 | new_alloc_flags = update_block_group_flags(root, | ||
2860 | shrink_block_group->flags); | ||
2861 | if (new_alloc_flags != shrink_block_group->flags) { | ||
2862 | calc = | ||
2863 | btrfs_block_group_used(&shrink_block_group->item); | ||
2864 | } else { | ||
2865 | calc = shrink_block_group->key.offset; | ||
2866 | } | ||
2867 | do_chunk_alloc(trans, root->fs_info->extent_root, | ||
2868 | calc + 2 * 1024 * 1024, new_alloc_flags, force); | ||
2869 | btrfs_end_transaction(trans, root); | ||
2870 | } | ||
2871 | return 0; | ||
2872 | } | ||
2873 | |||
2773 | int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) | 2874 | int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) |
2774 | { | 2875 | { |
2775 | struct btrfs_trans_handle *trans; | 2876 | struct btrfs_trans_handle *trans; |
@@ -2778,7 +2879,6 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) | |||
2778 | u64 cur_byte; | 2879 | u64 cur_byte; |
2779 | u64 total_found; | 2880 | u64 total_found; |
2780 | u64 shrink_last_byte; | 2881 | u64 shrink_last_byte; |
2781 | u64 new_alloc_flags; | ||
2782 | struct btrfs_block_group_cache *shrink_block_group; | 2882 | struct btrfs_block_group_cache *shrink_block_group; |
2783 | struct btrfs_fs_info *info = root->fs_info; | 2883 | struct btrfs_fs_info *info = root->fs_info; |
2784 | struct btrfs_key key; | 2884 | struct btrfs_key key; |
@@ -2792,7 +2892,8 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) | |||
2792 | shrink_start); | 2892 | shrink_start); |
2793 | BUG_ON(!shrink_block_group); | 2893 | BUG_ON(!shrink_block_group); |
2794 | 2894 | ||
2795 | shrink_last_byte = shrink_start + shrink_block_group->key.offset; | 2895 | shrink_last_byte = shrink_block_group->key.objectid + |
2896 | shrink_block_group->key.offset; | ||
2796 | 2897 | ||
2797 | shrink_block_group->space_info->total_bytes -= | 2898 | shrink_block_group->space_info->total_bytes -= |
2798 | shrink_block_group->key.offset; | 2899 | shrink_block_group->key.offset; |
@@ -2804,23 +2905,10 @@ int btrfs_shrink_extent_tree(struct btrfs_root *root, u64 shrink_start) | |||
2804 | (unsigned long long)shrink_start, | 2905 | (unsigned long long)shrink_start, |
2805 | (unsigned long long)shrink_block_group->flags); | 2906 | (unsigned long long)shrink_block_group->flags); |
2806 | 2907 | ||
2908 | __alloc_chunk_for_shrink(root, shrink_block_group, 1); | ||
2909 | |||
2807 | again: | 2910 | again: |
2808 | if (btrfs_block_group_used(&shrink_block_group->item) > 0) { | ||
2809 | u64 calc; | ||
2810 | 2911 | ||
2811 | trans = btrfs_start_transaction(root, 1); | ||
2812 | new_alloc_flags = update_block_group_flags(root, | ||
2813 | shrink_block_group->flags); | ||
2814 | if (new_alloc_flags != shrink_block_group->flags) { | ||
2815 | calc = | ||
2816 | btrfs_block_group_used(&shrink_block_group->item); | ||
2817 | } else { | ||
2818 | calc = shrink_block_group->key.offset; | ||
2819 | } | ||
2820 | do_chunk_alloc(trans, root->fs_info->extent_root, | ||
2821 | calc + 2 * 1024 * 1024, new_alloc_flags); | ||
2822 | btrfs_end_transaction(trans, root); | ||
2823 | } | ||
2824 | shrink_block_group->ro = 1; | 2912 | shrink_block_group->ro = 1; |
2825 | 2913 | ||
2826 | total_found = 0; | 2914 | total_found = 0; |
@@ -2888,6 +2976,8 @@ next: | |||
2888 | 2976 | ||
2889 | if (btrfs_key_type(&found_key) != BTRFS_EXTENT_ITEM_KEY || | 2977 | if (btrfs_key_type(&found_key) != BTRFS_EXTENT_ITEM_KEY || |
2890 | found_key.objectid + found_key.offset <= cur_byte) { | 2978 | found_key.objectid + found_key.offset <= cur_byte) { |
2979 | memcpy(&key, &found_key, sizeof(key)); | ||
2980 | key.offset++; | ||
2891 | path->slots[0]++; | 2981 | path->slots[0]++; |
2892 | goto next; | 2982 | goto next; |
2893 | } | 2983 | } |
@@ -2897,6 +2987,7 @@ next: | |||
2897 | key.objectid = cur_byte; | 2987 | key.objectid = cur_byte; |
2898 | btrfs_release_path(root, path); | 2988 | btrfs_release_path(root, path); |
2899 | ret = relocate_one_extent(root, path, &found_key); | 2989 | ret = relocate_one_extent(root, path, &found_key); |
2990 | __alloc_chunk_for_shrink(root, shrink_block_group, 0); | ||
2900 | } | 2991 | } |
2901 | 2992 | ||
2902 | btrfs_release_path(root, path); | 2993 | btrfs_release_path(root, path); |
@@ -2930,20 +3021,27 @@ next: | |||
2930 | if (ret < 0) | 3021 | if (ret < 0) |
2931 | goto out; | 3022 | goto out; |
2932 | 3023 | ||
2933 | leaf = path->nodes[0]; | 3024 | clear_extent_bits(&info->block_group_cache, key.objectid, |
2934 | nritems = btrfs_header_nritems(leaf); | 3025 | key.objectid + key.offset - 1, |
2935 | btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]); | ||
2936 | kfree(shrink_block_group); | ||
2937 | |||
2938 | clear_extent_bits(&info->block_group_cache, found_key.objectid, | ||
2939 | found_key.objectid + found_key.offset - 1, | ||
2940 | (unsigned int)-1, GFP_NOFS); | 3026 | (unsigned int)-1, GFP_NOFS); |
2941 | 3027 | ||
3028 | |||
3029 | clear_extent_bits(&info->free_space_cache, | ||
3030 | key.objectid, key.objectid + key.offset - 1, | ||
3031 | (unsigned int)-1, GFP_NOFS); | ||
3032 | |||
3033 | memset(shrink_block_group, 0, sizeof(*shrink_block_group)); | ||
3034 | kfree(shrink_block_group); | ||
3035 | |||
2942 | btrfs_del_item(trans, root, path); | 3036 | btrfs_del_item(trans, root, path); |
2943 | clear_extent_dirty(&info->free_space_cache, | ||
2944 | shrink_start, shrink_last_byte - 1, | ||
2945 | GFP_NOFS); | ||
2946 | btrfs_commit_transaction(trans, root); | 3037 | btrfs_commit_transaction(trans, root); |
3038 | |||
3039 | /* the code to unpin extents might set a few bits in the free | ||
3040 | * space cache for this range again | ||
3041 | */ | ||
3042 | clear_extent_bits(&info->free_space_cache, | ||
3043 | key.objectid, key.objectid + key.offset - 1, | ||
3044 | (unsigned int)-1, GFP_NOFS); | ||
2947 | out: | 3045 | out: |
2948 | btrfs_free_path(path); | 3046 | btrfs_free_path(path); |
2949 | return ret; | 3047 | return ret; |
@@ -3081,9 +3179,8 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans, | |||
3081 | BUG_ON(!cache); | 3179 | BUG_ON(!cache); |
3082 | cache->key.objectid = chunk_offset; | 3180 | cache->key.objectid = chunk_offset; |
3083 | cache->key.offset = size; | 3181 | cache->key.offset = size; |
3084 | |||
3085 | btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY); | 3182 | btrfs_set_key_type(&cache->key, BTRFS_BLOCK_GROUP_ITEM_KEY); |
3086 | memset(&cache->item, 0, sizeof(cache->item)); | 3183 | |
3087 | btrfs_set_block_group_used(&cache->item, bytes_used); | 3184 | btrfs_set_block_group_used(&cache->item, bytes_used); |
3088 | btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid); | 3185 | btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid); |
3089 | cache->flags = type; | 3186 | cache->flags = type; |