History

nilfs2: fix incorrect block address termination in node concatenation

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.

Ryusuke Konishi committed 15 years ago

Commit fe744fd1 parent 59c5f461 file · +13 −5Browse files

Unified · Split

fs/nilfs2/btree.c+13−5
@@ -1356,20 +1356,19 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 1355 unmodified lines
13561356 struct buffer_head *bh;
13571357 struct nilfs_btree_node *node, *parent, *sib;
13581358 __u64 sibptr;
1359− int pindex, level, ncmin, ncmax, ncblk, ret;
1359+ int pindex, dindex, level, ncmin, ncmax, ncblk, ret;
13601360
13611361 ret = 0;
13621362 stats->bs_nblocks = 0;
13631363 ncmin = NILFS_BTREE_NODE_NCHILDREN_MIN(nilfs_btree_node_size(btree));
13641364 ncblk = nilfs_btree_nchildren_per_block(btree);
13651365
1366− for (level = NILFS_BTREE_LEVEL_NODE_MIN;
1366+ for (level = NILFS_BTREE_LEVEL_NODE_MIN, dindex = path[level].bp_index;
13671367 level < nilfs_btree_height(btree) - 1;
13681368 level++) {
13691369 node = nilfs_btree_get_nonroot_node(path, level);
13701370 path[level].bp_oldreq.bpr_ptr =
1371− nilfs_btree_node_get_ptr(node, path[level].bp_index,
1372− ncblk);
1371+ nilfs_btree_node_get_ptr(node, dindex, ncblk);
13731372 ret = nilfs_bmap_prepare_end_ptr(btree,
13741373 &path[level].bp_oldreq, dat);
13751374 if (ret < 0)
@@ -1383,6 +1382,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 7 unmodified lines
13831382
13841383 parent = nilfs_btree_get_node(btree, path, level + 1, &ncmax);
13851384 pindex = path[level + 1].bp_index;
1385+ dindex = pindex;
13861386
13871387 if (pindex > 0) {
13881388 /* left sibling */
@@ -1421,6 +1421,14 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 32 unmodified lines
14211421 path[level].bp_sib_bh = bh;
14221422 path[level].bp_op = nilfs_btree_concat_right;
14231423 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;
14241432 /* continue; */
14251433 }
14261434 } else {
@@ -1443,7 +1451,7 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree, · 16 unmodified lines
14431451
14441452 node = nilfs_btree_get_root(btree);
14451453 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,
14471455 NILFS_BTREE_ROOT_NCHILDREN_MAX);
14481456
14491457 ret = nilfs_bmap_prepare_end_ptr(btree, &path[level].bp_oldreq, dat);