nilfs_btree_delete function wrongly terminates virtual block address of the btree node held by its parent at index 0. When concatenating the index-0 node with its right sibling node, nilfs_btree_delete terminates the block address of index-0 node instead of the right sibling node which should be deleted. This bug not only wears disk space in the long run, but also causes file system corruption. This will fix it.
Unified · Split
| @@ -1356,20 +1356,19 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 1355 unmodified lines | |||
| 1356 | struct buffer_head *bh; | 1356 | struct buffer_head *bh; |
| 1357 | struct nilfs_btree_node *node, *parent, *sib; | 1357 | struct nilfs_btree_node *node, *parent, *sib; |
| 1358 | __u64 sibptr; | 1358 | __u64 sibptr; |
| 1359 | int pindex, level, ncmin, ncmax, ncblk, ret; | 1359 | int pindex, dindex, level, ncmin, ncmax, ncblk, ret; |
| 1360 | 1360 | ||
| 1361 | ret = 0; | 1361 | ret = 0; |
| 1362 | stats->bs_nblocks = 0; | 1362 | stats->bs_nblocks = 0; |
| 1363 | ncmin = NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree)); | 1363 | ncmin = NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree)); |
| 1364 | ncblk = nilfs_btree_nchildren_per_block(btree); | 1364 | ncblk = nilfs_btree_nchildren_per_block(btree); |
| 1365 | 1365 | ||
| 1366 | for (level = NILFS_BTREE_LEVEL_NODE_MIN; | 1366 | for (level = NILFS_BTREE_LEVEL_NODE_MIN, dindex = path[level].bp_index; |
| 1367 | level < nilfs_btree_height(btree) - 1; | 1367 | level < nilfs_btree_height(btree) - 1; |
| 1368 | level++) { | 1368 | level++) { |
| 1369 | node = nilfs_btree_get_nonroot_node(path, level); | 1369 | node = nilfs_btree_get_nonroot_node(path, level); |
| 1370 | path[level].bp_oldreq.bpr_ptr = | 1370 | path[level].bp_oldreq.bpr_ptr = |
| 1371 | nilfs_btree_node_get_ptr(node, path[level].bp_index, | 1371 | nilfs_btree_node_get_ptr(node, dindex, ncblk); |
| 1372 | ncblk); | ||
| 1373 | ret = nilfs_bmap_prepare_end_ptr(btree, | 1372 | ret = nilfs_bmap_prepare_end_ptr(btree, |
| 1374 | &path[level].bp_oldreq, dat); | 1373 | &path[level].bp_oldreq, dat); |
| 1375 | if (ret < 0) | 1374 | if (ret < 0) |
| @@ -1383,6 +1382,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 7 unmodified lines | |||
| 1383 | 1382 | ||
| 1384 | parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax); | 1383 | parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax); |
| 1385 | pindex = path[level + 1].bp_index; | 1384 | pindex = path[level + 1].bp_index; |
| 1385 | dindex = pindex; | ||
| 1386 | 1386 | ||
| 1387 | if (pindex > 0) { | 1387 | if (pindex > 0) { |
| 1388 | /* left sibling */ | 1388 | /* left sibling */ |
| @@ -1421,6 +1421,14 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 32 unmodified lines | |||
| 1421 | path[level].bp_sib_bh = bh; | 1421 | path[level].bp_sib_bh = bh; |
| 1422 | path[level].bp_op = nilfs_btree_concat_right; | 1422 | path[level].bp_op = nilfs_btree_concat_right; |
| 1423 | stats->bs_nblocks++; | 1423 | stats->bs_nblocks++; |
| 1424 | /* | ||
| 1425 | * When merging right sibling node | ||
| 1426 | * into the current node, pointer to | ||
| 1427 | * the right sibling node must be | ||
| 1428 | * terminated instead. The adjustment | ||
| 1429 | * below is required for that. | ||
| 1430 | */ | ||
| 1431 | dindex = pindex + 1; | ||
| 1424 | /* continue; */ | 1432 | /* continue; */ |
| 1425 | } | 1433 | } |
| 1426 | } else { | 1434 | } else { |
| @@ -1443,7 +1451,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 16 unmodified lines | |||
| 1443 | 1451 | ||
| 1444 | node = nilfs_btree_get_root(btree); | 1452 | node = nilfs_btree_get_root(btree); |
| 1445 | path[level].bp_oldreq.bpr_ptr = | 1453 | path[level].bp_oldreq.bpr_ptr = |
| 1446 | nilfs_btree_node_get_ptr(node, path[level].bp_index, | 1454 | nilfs_btree_node_get_ptr(node, dindex, |
| 1447 | NILFS_BTREE_ROOT_NCHILDREN_MAX); | 1455 | NILFS_BTREE_ROOT_NCHILDREN_MAX); |
| 1448 | 1456 | ||
| 1449 | ret = nilfs_bmap_prepare_end_ptr(btree, &path[level].bp_oldreq, dat); | 1457 | ret = nilfs_bmap_prepare_end_ptr(btree, &path[level].bp_oldreq, dat); |