diff options
-rw-r--r-- | fs/btrfs/extent-tree.c | 63 |
1 files changed, 54 insertions, 9 deletions
diff --git a/fs/btrfs/extent-tree.c b/fs/btrfs/extent-tree.c index 239e9d8669cb..8f441783a6ed 100644 --- a/fs/btrfs/extent-tree.c +++ b/fs/btrfs/extent-tree.c | |||
@@ -1251,6 +1251,9 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1251 | struct btrfs_root *extent_root = info->extent_root; | 1251 | struct btrfs_root *extent_root = info->extent_root; |
1252 | struct extent_buffer *leaf; | 1252 | struct extent_buffer *leaf; |
1253 | int ret; | 1253 | int ret; |
1254 | int extent_slot = 0; | ||
1255 | int found_extent = 0; | ||
1256 | int num_to_del = 1; | ||
1254 | struct btrfs_extent_item *ei; | 1257 | struct btrfs_extent_item *ei; |
1255 | u32 refs; | 1258 | u32 refs; |
1256 | 1259 | ||
@@ -1267,7 +1270,24 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1267 | ref_generation, | 1270 | ref_generation, |
1268 | owner_objectid, owner_offset, 1); | 1271 | owner_objectid, owner_offset, 1); |
1269 | if (ret == 0) { | 1272 | if (ret == 0) { |
1270 | ret = btrfs_del_item(trans, extent_root, path); | 1273 | struct btrfs_key found_key; |
1274 | extent_slot = path->slots[0]; | ||
1275 | while(extent_slot > 0) { | ||
1276 | extent_slot--; | ||
1277 | btrfs_item_key_to_cpu(path->nodes[0], &found_key, | ||
1278 | extent_slot); | ||
1279 | if (found_key.objectid != bytenr) | ||
1280 | break; | ||
1281 | if (found_key.type == BTRFS_EXTENT_ITEM_KEY && | ||
1282 | found_key.offset == num_bytes) { | ||
1283 | found_extent = 1; | ||
1284 | break; | ||
1285 | } | ||
1286 | if (path->slots[0] - extent_slot > 5) | ||
1287 | break; | ||
1288 | } | ||
1289 | if (!found_extent) | ||
1290 | ret = btrfs_del_item(trans, extent_root, path); | ||
1271 | } else { | 1291 | } else { |
1272 | btrfs_print_leaf(extent_root, path->nodes[0]); | 1292 | btrfs_print_leaf(extent_root, path->nodes[0]); |
1273 | WARN_ON(1); | 1293 | WARN_ON(1); |
@@ -1276,21 +1296,46 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1276 | root_objectid, ref_generation, owner_objectid, | 1296 | root_objectid, ref_generation, owner_objectid, |
1277 | owner_offset); | 1297 | owner_offset); |
1278 | } | 1298 | } |
1279 | btrfs_release_path(extent_root, path); | 1299 | if (!found_extent) { |
1280 | ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); | 1300 | btrfs_release_path(extent_root, path); |
1281 | if (ret < 0) | 1301 | ret = btrfs_search_slot(trans, extent_root, &key, path, -1, 1); |
1282 | return ret; | 1302 | if (ret < 0) |
1283 | BUG_ON(ret); | 1303 | return ret; |
1304 | BUG_ON(ret); | ||
1305 | extent_slot = path->slots[0]; | ||
1306 | } | ||
1284 | 1307 | ||
1285 | leaf = path->nodes[0]; | 1308 | leaf = path->nodes[0]; |
1286 | ei = btrfs_item_ptr(leaf, path->slots[0], | 1309 | ei = btrfs_item_ptr(leaf, extent_slot, |
1287 | struct btrfs_extent_item); | 1310 | struct btrfs_extent_item); |
1288 | refs = btrfs_extent_refs(leaf, ei); | 1311 | refs = btrfs_extent_refs(leaf, ei); |
1289 | BUG_ON(refs == 0); | 1312 | BUG_ON(refs == 0); |
1290 | refs -= 1; | 1313 | refs -= 1; |
1291 | btrfs_set_extent_refs(leaf, ei, refs); | 1314 | btrfs_set_extent_refs(leaf, ei, refs); |
1315 | |||
1292 | btrfs_mark_buffer_dirty(leaf); | 1316 | btrfs_mark_buffer_dirty(leaf); |
1293 | 1317 | ||
1318 | if (refs == 0 && found_extent && path->slots[0] == extent_slot + 1) { | ||
1319 | /* if the back ref and the extent are next to each other | ||
1320 | * they get deleted below in one shot | ||
1321 | */ | ||
1322 | path->slots[0] = extent_slot; | ||
1323 | num_to_del = 2; | ||
1324 | } else if (found_extent) { | ||
1325 | /* otherwise delete the extent back ref */ | ||
1326 | ret = btrfs_del_item(trans, extent_root, path); | ||
1327 | BUG_ON(ret); | ||
1328 | /* if refs are 0, we need to setup the path for deletion */ | ||
1329 | if (refs == 0) { | ||
1330 | btrfs_release_path(extent_root, path); | ||
1331 | ret = btrfs_search_slot(trans, extent_root, &key, path, | ||
1332 | -1, 1); | ||
1333 | if (ret < 0) | ||
1334 | return ret; | ||
1335 | BUG_ON(ret); | ||
1336 | } | ||
1337 | } | ||
1338 | |||
1294 | if (refs == 0) { | 1339 | if (refs == 0) { |
1295 | u64 super_used; | 1340 | u64 super_used; |
1296 | u64 root_used; | 1341 | u64 root_used; |
@@ -1311,8 +1356,8 @@ static int __free_extent(struct btrfs_trans_handle *trans, struct btrfs_root | |||
1311 | root_used = btrfs_root_used(&root->root_item); | 1356 | root_used = btrfs_root_used(&root->root_item); |
1312 | btrfs_set_root_used(&root->root_item, | 1357 | btrfs_set_root_used(&root->root_item, |
1313 | root_used - num_bytes); | 1358 | root_used - num_bytes); |
1314 | 1359 | ret = btrfs_del_items(trans, extent_root, path, path->slots[0], | |
1315 | ret = btrfs_del_item(trans, extent_root, path); | 1360 | num_to_del); |
1316 | if (ret) { | 1361 | if (ret) { |
1317 | return ret; | 1362 | return ret; |
1318 | } | 1363 | } |