nilfs_btree_delete function does not terminate part of virtual block addresses when shrinking the last remaining child node into the root node. The missing address termination causes that dead btree node blocks persist and chip away free disk space. This fixes the leak bug on the btree node deletion.
Unified · Split
| @@ -1346,6 +1346,11 @@ static void nilfs_btree_shrink(struct nilfs_bmap *btree, · 1345 unmodified lines | |||
| 1346 | path[level].bp_bh = NULL; | 1346 | path[level].bp_bh = NULL; |
| 1347 | } | 1347 | } |
| 1348 | 1348 | ||
| 1349 | static void nilfs_btree_nop(struct nilfs_bmap *btree, | ||
| 1350 | struct nilfs_btree_path *path, | ||
| 1351 | int level, __u64 *keyp, __u64 *ptrp) | ||
| 1352 | { | ||
| 1353 | } | ||
| 1349 | 1354 | ||
| 1350 | static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, | 1355 | static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, |
| 1351 | struct nilfs_btree_path *path, | 1356 | struct nilfs_btree_path *path, |
| @@ -1439,16 +1444,22 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 87 unmodified lines | |||
| 1439 | NILFS_BTREE_ROOT_NCHILDREN_MAX) { | 1444 | NILFS_BTREE_ROOT_NCHILDREN_MAX) { |
| 1440 | path[level].bp_op = nilfs_btree_shrink; | 1445 | path[level].bp_op = nilfs_btree_shrink; |
| 1441 | stats->bs_nblocks += 2; | 1446 | stats->bs_nblocks += 2; |
| 1447 | level++; | ||
| 1448 | path[level].bp_op = nilfs_btree_nop; | ||
| 1449 | goto shrink_root_child; | ||
| 1442 | } else { | 1450 | } else { |
| 1443 | path[level].bp_op = nilfs_btree_do_delete; | 1451 | path[level].bp_op = nilfs_btree_do_delete; |
| 1444 | stats->bs_nblocks++; | 1452 | stats->bs_nblocks++; |
| 1453 | goto out; | ||
| 1445 | } | 1454 | } |
| 1446 | |||
| 1447 | goto out; | ||
| 1448 | |||
| 1449 | } | 1455 | } |
| 1450 | } | 1456 | } |
| 1451 | 1457 | ||
| 1458 | /* child of the root node is deleted */ | ||
| 1459 | path[level].bp_op = nilfs_btree_do_delete; | ||
| 1460 | stats->bs_nblocks++; | ||
| 1461 | |||
| 1462 | shrink_root_child: | ||
| 1452 | node = nilfs_btree_get_root(btree); | 1463 | node = nilfs_btree_get_root(btree); |
| 1453 | path[level].bp_oldreq.bpr_ptr = | 1464 | path[level].bp_oldreq.bpr_ptr = |
| 1454 | nilfs_btree_node_get_ptr(node, dindex, | 1465 | nilfs_btree_node_get_ptr(node, dindex, |
| @@ -1458,10 +1469,6 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 3 unmodified lines | |||
| 1458 | if (ret < 0) | 1469 | if (ret < 0) |
| 1459 | goto err_out_child_node; | 1470 | goto err_out_child_node; |
| 1460 | 1471 | ||
| 1461 | /* child of the root node is deleted */ | ||
| 1462 | path[level].bp_op = nilfs_btree_do_delete; | ||
| 1463 | stats->bs_nblocks++; | ||
| 1464 | |||
| 1465 | /* success */ | 1472 | /* success */ |
| 1466 | out: | 1473 | out: |
| 1467 | *levelp = level; | 1474 | *levelp = level; |