]> git.baikalelectronics.ru Git - kernel.git/commitdiff
dm persistent data: fix nested btree deletion
authorJoe Thornber <ejt@redhat.com>
Fri, 21 Dec 2012 20:23:32 +0000 (20:23 +0000)
committerAlasdair G Kergon <agk@redhat.com>
Fri, 21 Dec 2012 20:23:32 +0000 (20:23 +0000)
When deleting nested btrees, the code forgets to delete the innermost
btree.  The thin-metadata code serendipitously compensates for this by
claiming there is one extra layer in the tree.

This patch corrects both problems.

Signed-off-by: Joe Thornber <ejt@redhat.com>
Signed-off-by: Alasdair G Kergon <agk@redhat.com>
drivers/md/dm-thin-metadata.c
drivers/md/persistent-data/dm-btree.c

index 693e149e97271dbe3fa3b646cfac018533892835..4d6e85367b847c498be7a26c7feb900bd607d329 100644 (file)
@@ -408,7 +408,7 @@ static void __setup_btree_details(struct dm_pool_metadata *pmd)
 
        pmd->tl_info.tm = pmd->tm;
        pmd->tl_info.levels = 1;
-       pmd->tl_info.value_type.context = &pmd->info;
+       pmd->tl_info.value_type.context = &pmd->bl_info;
        pmd->tl_info.value_type.size = sizeof(__le64);
        pmd->tl_info.value_type.inc = subtree_inc;
        pmd->tl_info.value_type.dec = subtree_dec;
index 371f3d49d18e717316ad39b2d1277e77ce0903b6..4caf66918cdb35249544fdf296dd07d2594ae63a 100644 (file)
@@ -230,6 +230,11 @@ static void pop_frame(struct del_stack *s)
        dm_tm_unlock(s->tm, f->b);
 }
 
+static bool is_internal_level(struct dm_btree_info *info, struct frame *f)
+{
+       return f->level < (info->levels - 1);
+}
+
 int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
 {
        int r;
@@ -241,7 +246,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
        s->tm = info->tm;
        s->top = -1;
 
-       r = push_frame(s, root, 1);
+       r = push_frame(s, root, 0);
        if (r)
                goto out;
 
@@ -267,7 +272,7 @@ int dm_btree_del(struct dm_btree_info *info, dm_block_t root)
                        if (r)
                                goto out;
 
-               } else if (f->level != (info->levels - 1)) {
+               } else if (is_internal_level(info, f)) {
                        b = value64(f->n, f->current_child);
                        f->current_child++;
                        r = push_frame(s, b, f->level + 1);