nilfs2: fix missing block address termination in btree node shrinking
authorRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Wed, 25 May 2011 14:00:27 +0000 (23:00 +0900)
committerRyusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
Sat, 11 Jun 2011 06:51:15 +0000 (15:51 +0900)
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.

Signed-off-by: Ryusuke Konishi <konishi.ryusuke@lab.ntt.co.jp>
fs/nilfs2/btree.c

index fd4f05b91942324be119df26ad5c736a4a948000..b2e3ff34762070a4b37085c051223809b59e4a6c 100644 (file)
@@ -1346,6 +1346,11 @@ static void nilfs_btree_shrink(struct nilfs_bmap *btree,
        path[level].bp_bh = NULL;
 }
 
+static void nilfs_btree_nop(struct nilfs_bmap *btree,
+                           struct nilfs_btree_path *path,
+                           int level, __u64 *keyp, __u64 *ptrp)
+{
+}
 
 static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
                                      struct nilfs_btree_path *path,
@@ -1439,16 +1444,22 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
                            NILFS_BTREE_ROOT_NCHILDREN_MAX) {
                                path[level].bp_op = nilfs_btree_shrink;
                                stats->bs_nblocks += 2;
+                               level++;
+                               path[level].bp_op = nilfs_btree_nop;
+                               goto shrink_root_child;
                        } else {
                                path[level].bp_op = nilfs_btree_do_delete;
                                stats->bs_nblocks++;
+                               goto out;
                        }
-
-                       goto out;
-
                }
        }
 
+       /* child of the root node is deleted */
+       path[level].bp_op = nilfs_btree_do_delete;
+       stats->bs_nblocks++;
+
+shrink_root_child:
        node = nilfs_btree_get_root(btree);
        path[level].bp_oldreq.bpr_ptr =
                nilfs_btree_node_get_ptr(node, dindex,
@@ -1458,10 +1469,6 @@ static int nilfs_btree_prepare_delete(struct nilfs_bmap *btree,
        if (ret < 0)
                goto err_out_child_node;
 
-       /* child of the root node is deleted */
-       path[level].bp_op = nilfs_btree_do_delete;
-       stats->bs_nblocks++;
-
        /* success */
  out:
        *levelp = level;