]> git.neil.brown.name Git - LaFS.git/commitdiff
Take a ref on dblock whenever the InoIdx block has a ->parent link.
authorNeilBrown <neilb@suse.de>
Wed, 15 Sep 2010 02:57:07 +0000 (12:57 +1000)
committerNeilBrown <neilb@suse.de>
Wed, 15 Sep 2010 02:57:07 +0000 (12:57 +1000)
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 <neilb@suse.de>
index.c

diff --git a/index.c b/index.c
index 1f7759bce23609cca7f4db9feb3a9d425a55e7a7..acff2fe8067edf10c00cb6b2c0c867a061f02439 100644 (file)
--- 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);