aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/btrfs/extent-tree.c63
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 }