From: NeilBrown Date: Wed, 15 Sep 2010 02:57:07 +0000 (+1000) Subject: Take a ref on dblock whenever the InoIdx block has a ->parent link. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=acdf79893018ffffc902990732b86d37fc658dbb;p=LaFS.git Take a ref on dblock whenever the InoIdx block has a ->parent link. This will be needed to ensure the dblock stays referenced when we stop holding a reference to blocks on the 'leafs' lists. Signed-off-by: NeilBrown --- diff --git a/index.c b/index.c index 1f7759b..acff2fe 100644 --- a/index.c +++ b/index.c @@ -366,8 +366,16 @@ block_adopt(struct block *blk, struct indexblock *parent) /* Remove from the per-inode free list */ if (!test_bit(B_InoIdx, &blk->flags)) list_move(&blk->siblings, &parent->children); - else + else { + /* Remove from ->free_index list */ list_del_init(&blk->siblings); + /* Having set ->parent, we take a ref on the dblock. + * The dblock must exist because we can only reach here from + * lafs_make_iblock which can only be called while holding a ref + * on the dblock + */ + (void)getdref(LAFSI(blk->inode)->dblock, MKREF(pdblock)); + } } spin_unlock(&as->private_lock); } @@ -973,6 +981,26 @@ void lafs_refile(struct block *b, int dec) del_ref(&b->parent->b, MKREF(child), __FILE__, __LINE__); b->parent = NULL; + + if (test_bit(B_InoIdx, &b->flags)) { + /* While an InoIdx has a parent we hold a count on + * the dblock. Now we have dropped one, we must drop the + * other + */ + struct datablock *db = LAFSI(b->inode)->dblock; + if (&db->b.parent->b != next_parent && + &db->b != next_parent) { + printk("db = %s\n", strblk(&db->b)); + printk("dp->p = %s\n", strblk(&db->b.parent->b)); + printk("np = %s\n", strblk(next_parent)); + printk("b = %s\n", strblk(b)); + } + BUG_ON(&db->b.parent->b != next_parent && &db->b != next_parent); + if (atomic_dec_and_test(&next_parent->refcnt)) + LAFS_BUG(1, b); + next_parent = &db->b; + del_ref(&db->b, MKREF(pdblock), __FILE__, __LINE__); + } if (test_and_clear_bit(B_SegRef, &b->flags)) physref = b->physaddr; spin_lock(&b->inode->i_data.private_lock);