diff options
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: |