diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-08-07 16:15:09 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-08-07 16:15:09 -0400 |
commit | 6702ed490ca0bb44e17131818a5a18b773957c5a (patch) | |
tree | f6bc4b77e58506a68f1ab539ca6c96854f39f92d /fs/btrfs/extent-tree.c | |
parent | 3c69faecb8d83cb2ef085a98b196a3fecea67725 (diff) |
Btrfs: Add run time btree defrag, and an ioctl to force btree defrag
This adds two types of btree defrag, a run time form that tries to
defrag recently allocated blocks in the btree when they are still in ram,
and an ioctl that forces defrag of all btree blocks.
File data blocks are not defragged yet, but this can make a huge difference
in sequential btree reads.
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 | 53 |
1 files changed, 32 insertions, 21 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 5d4d5d8db8ef..26b8d3406491 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -23,7 +23,8 @@ | |||
23 | #include "transaction.h" | 23 | #include "transaction.h" |
24 | 24 | ||
25 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | 25 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root |
26 | *orig_root, u64 num_blocks, u64 search_start, | 26 | *orig_root, u64 num_blocks, u64 empty_size, |
27 | u64 search_start, | ||
27 | u64 search_end, u64 hint_block, | 28 | u64 search_end, u64 hint_block, |
28 | struct btrfs_key *ins, u64 exclude_start, | 29 | struct btrfs_key *ins, u64 exclude_start, |
29 | u64 exclude_nr, int data); | 30 | u64 exclude_nr, int data); |
@@ -379,7 +380,7 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans, | |||
379 | path = btrfs_alloc_path(); | 380 | path = btrfs_alloc_path(); |
380 | if (!path) | 381 | if (!path) |
381 | return -ENOMEM; | 382 | return -ENOMEM; |
382 | ret = find_free_extent(trans, root->fs_info->extent_root, 0, 0, | 383 | ret = find_free_extent(trans, root->fs_info->extent_root, 0, 0, 0, |
383 | (u64)-1, 0, &ins, 0, 0, 0); | 384 | (u64)-1, 0, &ins, 0, 0, 0); |
384 | if (ret) { | 385 | if (ret) { |
385 | btrfs_free_path(path); | 386 | btrfs_free_path(path); |
@@ -533,7 +534,7 @@ static int write_one_cache_group(struct btrfs_trans_handle *trans, | |||
533 | struct btrfs_block_group_item *bi; | 534 | struct btrfs_block_group_item *bi; |
534 | struct btrfs_key ins; | 535 | struct btrfs_key ins; |
535 | 536 | ||
536 | ret = find_free_extent(trans, extent_root, 0, 0, (u64)-1, 0, &ins, | 537 | ret = find_free_extent(trans, extent_root, 0, 0, 0, (u64)-1, 0, &ins, |
537 | 0, 0, 0); | 538 | 0, 0, 0); |
538 | /* FIXME, set bit to recalc cache groups on next mount */ | 539 | /* FIXME, set bit to recalc cache groups on next mount */ |
539 | if (ret) | 540 | if (ret) |
@@ -708,6 +709,7 @@ static int update_block_group(struct btrfs_trans_handle *trans, | |||
708 | static int try_remove_page(struct address_space *mapping, unsigned long index) | 709 | static int try_remove_page(struct address_space *mapping, unsigned long index) |
709 | { | 710 | { |
710 | int ret; | 711 | int ret; |
712 | return 0; | ||
711 | ret = invalidate_mapping_pages(mapping, index, index); | 713 | ret = invalidate_mapping_pages(mapping, index, index); |
712 | return ret; | 714 | return ret; |
713 | } | 715 | } |
@@ -866,7 +868,7 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
866 | if (!path) | 868 | if (!path) |
867 | return -ENOMEM; | 869 | return -ENOMEM; |
868 | 870 | ||
869 | ret = find_free_extent(trans, root, 0, 0, (u64)-1, 0, &ins, 0, 0, 0); | 871 | ret = find_free_extent(trans, root, 0, 0, 0, (u64)-1, 0, &ins, 0, 0, 0); |
870 | if (ret) { | 872 | if (ret) { |
871 | btrfs_free_path(path); | 873 | btrfs_free_path(path); |
872 | return ret; | 874 | return ret; |
@@ -983,8 +985,8 @@ int btrfs_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
983 | * Any available blocks before search_start are skipped. | 985 | * Any available blocks before search_start are skipped. |
984 | */ | 986 | */ |
985 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | 987 | static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root |
986 | *orig_root, u64 num_blocks, u64 search_start, u64 | 988 | *orig_root, u64 num_blocks, u64 empty_size, |
987 | search_end, u64 hint_block, | 989 | u64 search_start, u64 search_end, u64 hint_block, |
988 | struct btrfs_key *ins, u64 exclude_start, | 990 | struct btrfs_key *ins, u64 exclude_start, |
989 | u64 exclude_nr, int data) | 991 | u64 exclude_nr, int data) |
990 | { | 992 | { |
@@ -1042,6 +1044,7 @@ static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1042 | data, 1); | 1044 | data, 1); |
1043 | } | 1045 | } |
1044 | 1046 | ||
1047 | total_needed += empty_size; | ||
1045 | path = btrfs_alloc_path(); | 1048 | path = btrfs_alloc_path(); |
1046 | 1049 | ||
1047 | check_failed: | 1050 | check_failed: |
@@ -1157,9 +1160,11 @@ check_pending: | |||
1157 | goto error; | 1160 | goto error; |
1158 | } | 1161 | } |
1159 | search_start = orig_search_start; | 1162 | search_start = orig_search_start; |
1160 | if (wrapped) | 1163 | if (wrapped) { |
1164 | if (!full_scan) | ||
1165 | total_needed -= empty_size; | ||
1161 | full_scan = 1; | 1166 | full_scan = 1; |
1162 | else | 1167 | } else |
1163 | wrapped = 1; | 1168 | wrapped = 1; |
1164 | goto new_group; | 1169 | goto new_group; |
1165 | } | 1170 | } |
@@ -1238,9 +1243,11 @@ new_group: | |||
1238 | ret = -ENOSPC; | 1243 | ret = -ENOSPC; |
1239 | goto error; | 1244 | goto error; |
1240 | } | 1245 | } |
1241 | if (wrapped) | 1246 | if (wrapped) { |
1247 | if (!full_scan) | ||
1248 | total_needed -= empty_size; | ||
1242 | full_scan = 1; | 1249 | full_scan = 1; |
1243 | else | 1250 | } else |
1244 | wrapped = 1; | 1251 | wrapped = 1; |
1245 | } | 1252 | } |
1246 | block_group = btrfs_lookup_block_group(info, search_start); | 1253 | block_group = btrfs_lookup_block_group(info, search_start); |
@@ -1264,7 +1271,7 @@ error: | |||
1264 | */ | 1271 | */ |
1265 | int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | 1272 | int btrfs_alloc_extent(struct btrfs_trans_handle *trans, |
1266 | struct btrfs_root *root, u64 owner, | 1273 | struct btrfs_root *root, u64 owner, |
1267 | u64 num_blocks, u64 hint_block, | 1274 | u64 num_blocks, u64 empty_size, u64 hint_block, |
1268 | u64 search_end, struct btrfs_key *ins, int data) | 1275 | u64 search_end, struct btrfs_key *ins, int data) |
1269 | { | 1276 | { |
1270 | int ret; | 1277 | int ret; |
@@ -1303,7 +1310,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1303 | * in the correct block group. | 1310 | * in the correct block group. |
1304 | */ | 1311 | */ |
1305 | if (data) { | 1312 | if (data) { |
1306 | ret = find_free_extent(trans, root, 0, 0, | 1313 | ret = find_free_extent(trans, root, 0, 0, 0, |
1307 | search_end, 0, &prealloc_key, 0, 0, 0); | 1314 | search_end, 0, &prealloc_key, 0, 0, 0); |
1308 | BUG_ON(ret); | 1315 | BUG_ON(ret); |
1309 | if (ret) | 1316 | if (ret) |
@@ -1313,8 +1320,8 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1313 | } | 1320 | } |
1314 | 1321 | ||
1315 | /* do the real allocation */ | 1322 | /* do the real allocation */ |
1316 | ret = find_free_extent(trans, root, num_blocks, search_start, | 1323 | ret = find_free_extent(trans, root, num_blocks, empty_size, |
1317 | search_end, hint_block, ins, | 1324 | search_start, search_end, hint_block, ins, |
1318 | exclude_start, exclude_nr, data); | 1325 | exclude_start, exclude_nr, data); |
1319 | BUG_ON(ret); | 1326 | BUG_ON(ret); |
1320 | if (ret) | 1327 | if (ret) |
@@ -1333,7 +1340,7 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1333 | exclude_start = ins->objectid; | 1340 | exclude_start = ins->objectid; |
1334 | exclude_nr = ins->offset; | 1341 | exclude_nr = ins->offset; |
1335 | hint_block = exclude_start + exclude_nr; | 1342 | hint_block = exclude_start + exclude_nr; |
1336 | ret = find_free_extent(trans, root, 0, search_start, | 1343 | ret = find_free_extent(trans, root, 0, 0, search_start, |
1337 | search_end, hint_block, | 1344 | search_end, hint_block, |
1338 | &prealloc_key, exclude_start, | 1345 | &prealloc_key, exclude_start, |
1339 | exclude_nr, 0); | 1346 | exclude_nr, 0); |
@@ -1368,14 +1375,16 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans, | |||
1368 | * returns the tree buffer or NULL. | 1375 | * returns the tree buffer or NULL. |
1369 | */ | 1376 | */ |
1370 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | 1377 | struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, |
1371 | struct btrfs_root *root, u64 hint) | 1378 | struct btrfs_root *root, u64 hint, |
1379 | u64 empty_size) | ||
1372 | { | 1380 | { |
1373 | struct btrfs_key ins; | 1381 | struct btrfs_key ins; |
1374 | int ret; | 1382 | int ret; |
1375 | struct buffer_head *buf; | 1383 | struct buffer_head *buf; |
1376 | 1384 | ||
1377 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, | 1385 | ret = btrfs_alloc_extent(trans, root, root->root_key.objectid, |
1378 | 1, hint, (unsigned long)-1, &ins, 0); | 1386 | 1, empty_size, hint, |
1387 | (unsigned long)-1, &ins, 0); | ||
1379 | if (ret) { | 1388 | if (ret) { |
1380 | BUG_ON(ret > 0); | 1389 | BUG_ON(ret > 0); |
1381 | return ERR_PTR(ret); | 1390 | return ERR_PTR(ret); |
@@ -1385,6 +1394,7 @@ struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, | |||
1385 | btrfs_free_extent(trans, root, ins.objectid, 1, 0); | 1394 | btrfs_free_extent(trans, root, ins.objectid, 1, 0); |
1386 | return ERR_PTR(-ENOMEM); | 1395 | return ERR_PTR(-ENOMEM); |
1387 | } | 1396 | } |
1397 | WARN_ON(buffer_dirty(buf)); | ||
1388 | set_buffer_uptodate(buf); | 1398 | set_buffer_uptodate(buf); |
1389 | set_buffer_checked(buf); | 1399 | set_buffer_checked(buf); |
1390 | set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); | 1400 | set_radix_bit(&trans->transaction->dirty_pages, buf->b_page->index); |
@@ -1591,13 +1601,15 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1591 | struct btrfs_key key; | 1601 | struct btrfs_key key; |
1592 | struct btrfs_disk_key *found_key; | 1602 | struct btrfs_disk_key *found_key; |
1593 | struct btrfs_node *node; | 1603 | struct btrfs_node *node; |
1604 | |||
1594 | btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); | 1605 | btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); |
1606 | level = root_item->drop_level; | ||
1607 | path->lowest_level = level; | ||
1595 | wret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | 1608 | wret = btrfs_search_slot(NULL, root, &key, path, 0, 0); |
1596 | if (ret < 0) { | 1609 | if (wret < 0) { |
1597 | ret = wret; | 1610 | ret = wret; |
1598 | goto out; | 1611 | goto out; |
1599 | } | 1612 | } |
1600 | level = root_item->drop_level; | ||
1601 | node = btrfs_buffer_node(path->nodes[level]); | 1613 | node = btrfs_buffer_node(path->nodes[level]); |
1602 | found_key = &node->ptrs[path->slots[level]].key; | 1614 | found_key = &node->ptrs[path->slots[level]].key; |
1603 | WARN_ON(memcmp(found_key, &root_item->drop_progress, | 1615 | WARN_ON(memcmp(found_key, &root_item->drop_progress, |
@@ -1617,8 +1629,6 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1617 | ret = wret; | 1629 | ret = wret; |
1618 | num_walks++; | 1630 | num_walks++; |
1619 | if (num_walks > 10) { | 1631 | if (num_walks > 10) { |
1620 | struct btrfs_key key; | ||
1621 | btrfs_disk_key_to_cpu(&key, &root_item->drop_progress); | ||
1622 | ret = -EAGAIN; | 1632 | ret = -EAGAIN; |
1623 | get_bh(root->node); | 1633 | get_bh(root->node); |
1624 | break; | 1634 | break; |
@@ -1627,6 +1637,7 @@ int btrfs_drop_snapshot(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1627 | for (i = 0; i <= orig_level; i++) { | 1637 | for (i = 0; i <= orig_level; i++) { |
1628 | if (path->nodes[i]) { | 1638 | if (path->nodes[i]) { |
1629 | btrfs_block_release(root, path->nodes[i]); | 1639 | btrfs_block_release(root, path->nodes[i]); |
1640 | path->nodes[i] = 0; | ||
1630 | } | 1641 | } |
1631 | } | 1642 | } |
1632 | out: | 1643 | out: |