diff options
-rw-r--r-- | fs/btrfs/ctree.h | 5 | ||||
-rw-r--r-- | fs/btrfs/extent-tree.c | 85 |
2 files changed, 65 insertions, 25 deletions
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h index 756ea9d0123b..1bb62867deda 100644 --- a/fs/btrfs/ctree.h +++ b/fs/btrfs/ctree.h | |||
@@ -249,10 +249,13 @@ struct btrfs_device_item { | |||
249 | /* tag for the radix tree of block groups in ram */ | 249 | /* tag for the radix tree of block groups in ram */ |
250 | #define BTRFS_BLOCK_GROUP_DIRTY 0 | 250 | #define BTRFS_BLOCK_GROUP_DIRTY 0 |
251 | #define BTRFS_BLOCK_GROUP_AVAIL 1 | 251 | #define BTRFS_BLOCK_GROUP_AVAIL 1 |
252 | #define BTRFS_BLOCK_GROUP_HINTS 8 | ||
253 | #define BTRFS_BLOCK_GROUP_SIZE (256 * 1024 * 1024) | 252 | #define BTRFS_BLOCK_GROUP_SIZE (256 * 1024 * 1024) |
253 | |||
254 | |||
255 | #define BTRFS_BLOCK_GROUP_DATA 1 | ||
254 | struct btrfs_block_group_item { | 256 | struct btrfs_block_group_item { |
255 | __le64 used; | 257 | __le64 used; |
258 | u8 flags; | ||
256 | } __attribute__ ((__packed__)); | 259 | } __attribute__ ((__packed__)); |
257 | 260 | ||
258 | struct btrfs_block_group_cache { | 261 | struct btrfs_block_group_cache { |
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index a366415e03a6..b6dc020bdde9 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -232,6 +232,7 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
232 | struct btrfs_block_group_cache *found_group = NULL; | 232 | struct btrfs_block_group_cache *found_group = NULL; |
233 | struct btrfs_fs_info *info = root->fs_info; | 233 | struct btrfs_fs_info *info = root->fs_info; |
234 | struct radix_tree_root *radix; | 234 | struct radix_tree_root *radix; |
235 | struct radix_tree_root *swap_radix; | ||
235 | u64 used; | 236 | u64 used; |
236 | u64 last = 0; | 237 | u64 last = 0; |
237 | u64 hint_last; | 238 | u64 hint_last; |
@@ -239,14 +240,18 @@ struct btrfs_block_group_cache *btrfs_find_block_group(struct btrfs_root *root, | |||
239 | int ret; | 240 | int ret; |
240 | int full_search = 0; | 241 | int full_search = 0; |
241 | int factor = 8; | 242 | int factor = 8; |
243 | int data_swap = 0; | ||
242 | 244 | ||
243 | if (!owner) | 245 | if (!owner) |
244 | factor = 5; | 246 | factor = 5; |
245 | 247 | ||
246 | if (data) | 248 | if (data) { |
247 | radix = &info->block_group_data_radix; | 249 | radix = &info->block_group_data_radix; |
248 | else | 250 | swap_radix = &info->block_group_radix; |
251 | } else { | ||
249 | radix = &info->block_group_radix; | 252 | radix = &info->block_group_radix; |
253 | swap_radix = &info->block_group_data_radix; | ||
254 | } | ||
250 | 255 | ||
251 | if (search_start) { | 256 | if (search_start) { |
252 | struct btrfs_block_group_cache *shint; | 257 | struct btrfs_block_group_cache *shint; |
@@ -334,15 +339,27 @@ again: | |||
334 | cond_resched(); | 339 | cond_resched(); |
335 | } | 340 | } |
336 | if (!full_search) { | 341 | if (!full_search) { |
337 | printk("find block group doing full search data %d start %Lu\n", data, search_start); | ||
338 | last = search_start; | 342 | last = search_start; |
339 | full_search = 1; | 343 | full_search = 1; |
340 | goto again; | 344 | goto again; |
341 | } | 345 | } |
346 | if (!data_swap) { | ||
347 | struct radix_tree_root *tmp = radix; | ||
348 | data_swap = 1; | ||
349 | radix = swap_radix; | ||
350 | swap_radix = tmp; | ||
351 | last = search_start; | ||
352 | goto again; | ||
353 | } | ||
342 | if (!found_group) { | 354 | if (!found_group) { |
343 | printk("find block group bailing to zero data %d\n", data); | 355 | printk("find block group bailing to zero data %d\n", data); |
344 | ret = radix_tree_gang_lookup(radix, | 356 | ret = radix_tree_gang_lookup(radix, |
345 | (void **)&found_group, 0, 1); | 357 | (void **)&found_group, 0, 1); |
358 | if (ret == 0) { | ||
359 | ret = radix_tree_gang_lookup(swap_radix, | ||
360 | (void **)&found_group, | ||
361 | 0, 1); | ||
362 | } | ||
346 | BUG_ON(ret != 1); | 363 | BUG_ON(ret != 1); |
347 | } | 364 | } |
348 | found: | 365 | found: |
@@ -552,7 +569,8 @@ int btrfs_write_dirty_block_groups(struct btrfs_trans_handle *trans, | |||
552 | 569 | ||
553 | static int update_block_group(struct btrfs_trans_handle *trans, | 570 | static int update_block_group(struct btrfs_trans_handle *trans, |
554 | struct btrfs_root *root, | 571 | struct btrfs_root *root, |
555 | u64 blocknr, u64 num, int alloc, int mark_free) | 572 | u64 blocknr, u64 num, int alloc, int mark_free, |
573 | int data) | ||
556 | { | 574 | { |
557 | struct btrfs_block_group_cache *cache; | 575 | struct btrfs_block_group_cache *cache; |
558 | struct btrfs_fs_info *info = root->fs_info; | 576 | struct btrfs_fs_info *info = root->fs_info; |
@@ -560,6 +578,7 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
560 | u64 old_val; | 578 | u64 old_val; |
561 | u64 block_in_group; | 579 | u64 block_in_group; |
562 | u64 i; | 580 | u64 i; |
581 | int ret; | ||
563 | 582 | ||
564 | while(total) { | 583 | while(total) { |
565 | cache = lookup_block_group(info, blocknr); | 584 | cache = lookup_block_group(info, blocknr); |
@@ -577,7 +596,6 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
577 | old_val = btrfs_block_group_used(&cache->item); | 596 | old_val = btrfs_block_group_used(&cache->item); |
578 | num = min(total, cache->key.offset - block_in_group); | 597 | num = min(total, cache->key.offset - block_in_group); |
579 | if (alloc) { | 598 | if (alloc) { |
580 | old_val += num; | ||
581 | if (blocknr > cache->last_alloc) | 599 | if (blocknr > cache->last_alloc) |
582 | cache->last_alloc = blocknr; | 600 | cache->last_alloc = blocknr; |
583 | if (!cache->data) { | 601 | if (!cache->data) { |
@@ -586,6 +604,30 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
586 | blocknr + i); | 604 | blocknr + i); |
587 | } | 605 | } |
588 | } | 606 | } |
607 | if (cache->data != data && | ||
608 | old_val < cache->key.offset / 2) { | ||
609 | printk("changing block group %Lu from %d to %d\n", cache->key.objectid, cache->data, data); | ||
610 | cache->data = data; | ||
611 | radix_tree_delete(cache->radix, | ||
612 | cache->key.objectid + | ||
613 | cache->key.offset - 1); | ||
614 | |||
615 | if (data) { | ||
616 | cache->radix = | ||
617 | &info->block_group_data_radix; | ||
618 | cache->item.flags |= | ||
619 | BTRFS_BLOCK_GROUP_DATA; | ||
620 | } else { | ||
621 | cache->radix = &info->block_group_radix; | ||
622 | cache->item.flags &= | ||
623 | ~BTRFS_BLOCK_GROUP_DATA; | ||
624 | } | ||
625 | ret = radix_tree_insert(cache->radix, | ||
626 | cache->key.objectid + | ||
627 | cache->key.offset - 1, | ||
628 | (void *)cache); | ||
629 | } | ||
630 | old_val += num; | ||
589 | } else { | 631 | } else { |
590 | old_val -= num; | 632 | old_val -= num; |
591 | if (blocknr < cache->first_free) | 633 | if (blocknr < cache->first_free) |
@@ -596,8 +638,8 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
596 | blocknr + i); | 638 | blocknr + i); |
597 | } | 639 | } |
598 | } | 640 | } |
599 | if (old_val < (cache->key.offset * 5) / 10 && | 641 | if (old_val < cache->key.offset / 2 && |
600 | old_val + num >= (cache->key.offset * 5) / 10) { | 642 | old_val + num >= cache->key.offset / 2) { |
601 | printk("group %Lu now available\n", cache->key.objectid); | 643 | printk("group %Lu now available\n", cache->key.objectid); |
602 | radix_tree_tag_set(cache->radix, | 644 | radix_tree_tag_set(cache->radix, |
603 | cache->key.objectid + | 645 | cache->key.objectid + |
@@ -779,7 +821,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
779 | if (ret) | 821 | if (ret) |
780 | BUG(); | 822 | BUG(); |
781 | ret = update_block_group(trans, root, blocknr, num_blocks, 0, | 823 | ret = update_block_group(trans, root, blocknr, num_blocks, 0, |
782 | mark_free); | 824 | mark_free, 0); |
783 | BUG_ON(ret); | 825 | BUG_ON(ret); |
784 | } | 826 | } |
785 | btrfs_free_path(path); | 827 | btrfs_free_path(path); |
@@ -909,10 +951,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
909 | } | 951 | } |
910 | 952 | ||
911 | check_failed: | 953 | check_failed: |
912 | if (!full_scan && block_group->data != data) | 954 | if (!block_group->data) |
913 | WARN_ON(1); | ||
914 | |||
915 | if (!data) | ||
916 | search_start = find_search_start(root, &block_group, | 955 | search_start = find_search_start(root, &block_group, |
917 | search_start, total_needed); | 956 | search_start, total_needed); |
918 | else | 957 | else |
@@ -1142,7 +1181,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1142 | info->extent_tree_insert[info->extent_tree_insert_nr++] = | 1181 | info->extent_tree_insert[info->extent_tree_insert_nr++] = |
1143 | ins->objectid; | 1182 | ins->objectid; |
1144 | ret = update_block_group(trans, root, | 1183 | ret = update_block_group(trans, root, |
1145 | ins->objectid, ins->offset, 1, 0); | 1184 | ins->objectid, ins->offset, 1, 0, 0); |
1146 | BUG_ON(ret); | 1185 | BUG_ON(ret); |
1147 | return 0; | 1186 | return 0; |
1148 | } | 1187 | } |
@@ -1208,7 +1247,8 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1208 | if (pending_ret) { | 1247 | if (pending_ret) { |
1209 | return pending_ret; | 1248 | return pending_ret; |
1210 | } | 1249 | } |
1211 | ret = update_block_group(trans, root, ins->objectid, ins->offset, 1, 0); | 1250 | ret = update_block_group(trans, root, ins->objectid, ins->offset, 1, 0, |
1251 | data); | ||
1212 | return 0; | 1252 | return 0; |
1213 | } | 1253 | } |
1214 | 1254 | ||
@@ -1477,7 +1517,6 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1477 | struct btrfs_leaf *leaf; | 1517 | struct btrfs_leaf *leaf; |
1478 | u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize; | 1518 | u64 group_size_blocks = BTRFS_BLOCK_GROUP_SIZE / root->blocksize; |
1479 | u64 used; | 1519 | u64 used; |
1480 | u64 nr = 0; | ||
1481 | 1520 | ||
1482 | root = info->extent_root; | 1521 | root = info->extent_root; |
1483 | key.objectid = 0; | 1522 | key.objectid = 0; |
@@ -1505,13 +1544,16 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1505 | break; | 1544 | break; |
1506 | } | 1545 | } |
1507 | 1546 | ||
1508 | if (nr % 3) | 1547 | bi = btrfs_item_ptr(leaf, path->slots[0], |
1548 | struct btrfs_block_group_item); | ||
1549 | if (bi->flags & BTRFS_BLOCK_GROUP_DATA) { | ||
1509 | radix = &info->block_group_data_radix; | 1550 | radix = &info->block_group_data_radix; |
1510 | else | 1551 | cache->data = 1; |
1552 | } else { | ||
1511 | radix = &info->block_group_radix; | 1553 | radix = &info->block_group_radix; |
1554 | cache->data = 0; | ||
1555 | } | ||
1512 | 1556 | ||
1513 | bi = btrfs_item_ptr(leaf, path->slots[0], | ||
1514 | struct btrfs_block_group_item); | ||
1515 | memcpy(&cache->item, bi, sizeof(*bi)); | 1557 | memcpy(&cache->item, bi, sizeof(*bi)); |
1516 | memcpy(&cache->key, &found_key, sizeof(found_key)); | 1558 | memcpy(&cache->key, &found_key, sizeof(found_key)); |
1517 | cache->last_alloc = cache->key.objectid; | 1559 | cache->last_alloc = cache->key.objectid; |
@@ -1520,10 +1562,6 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1520 | cache->pinned = 0; | 1562 | cache->pinned = 0; |
1521 | cache->cached = 0; | 1563 | cache->cached = 0; |
1522 | 1564 | ||
1523 | if (nr % 3) | ||
1524 | cache->data = 1; | ||
1525 | else | ||
1526 | cache->data = 0; | ||
1527 | cache->radix = radix; | 1565 | cache->radix = radix; |
1528 | 1566 | ||
1529 | key.objectid = found_key.objectid + found_key.offset; | 1567 | key.objectid = found_key.objectid + found_key.offset; |
@@ -1541,7 +1579,6 @@ int btrfs_read_block_groups(struct btrfs_root *root) | |||
1541 | if (key.objectid >= | 1579 | if (key.objectid >= |
1542 | btrfs_super_total_blocks(info->disk_super)) | 1580 | btrfs_super_total_blocks(info->disk_super)) |
1543 | break; | 1581 | break; |
1544 | nr++; | ||
1545 | } | 1582 | } |
1546 | 1583 | ||
1547 | btrfs_free_path(path); | 1584 | btrfs_free_path(path); |