aboutsummaryrefslogtreecommitdiffstats
path: root/fs/btrfs/extent-tree.c
diff options
context:
space:
mode:
authorChris Mason <chris.mason@oracle.com>2007-08-07 16:15:09 -0400
committerDavid Woodhouse <dwmw2@hera.kernel.org>2007-08-07 16:15:09 -0400
commit6702ed490ca0bb44e17131818a5a18b773957c5a (patch)
treef6bc4b77e58506a68f1ab539ca6c96854f39f92d /fs/btrfs/extent-tree.c
parent3c69faecb8d83cb2ef085a98b196a3fecea67725 (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.c53
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
25static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root 25static 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,
708static int try_remove_page(struct address_space *mapping, unsigned long index) 709static 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 */
985static int find_free_extent(struct btrfs_trans_handle *trans, struct btrfs_root 987static 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
1047check_failed: 1050check_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 */
1265int btrfs_alloc_extent(struct btrfs_trans_handle *trans, 1272int 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 */
1370struct buffer_head *btrfs_alloc_free_block(struct btrfs_trans_handle *trans, 1377struct 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 }
1632out: 1643out: