]> git.neil.brown.name Git - LaFS.git/commitdiff
unhash iblock when it becomes empty.
authorNeilBrown <neilb@suse.de>
Sun, 13 Jun 2010 07:16:30 +0000 (17:16 +1000)
committerNeilBrown <neilb@suse.de>
Sun, 13 Jun 2010 07:20:00 +0000 (17:20 +1000)
Our handling of empty iblocks was flawed - when they become empty they
stayed in the hash table and could be found again - bad.

So unhash them.
To keep things tidy, always use hlist_del_init to removing things from
the hash table, and assert that they are present before removing, and
that they aren't before adding.

Signed-off-by: NeilBrown <neilb@suse.de>
index.c
lafs.h
modify.c

diff --git a/index.c b/index.c
index d866af5623b562c52812501e6862643065cf679b..1eb1ff174a8f43da6fe5e0167474a94d866d88d3 100644 (file)
--- a/index.c
+++ b/index.c
@@ -82,7 +82,7 @@ static int lafs_shrinker(int nr_to_scan, /*gfp_t*/unsigned int gfp_mask)
                         */
                        LAFS_BUG(test_bit(B_Pinned, &ib->b.flags), &ib->b);
                        if (!hlist_unhashed(&ib->hash))
-                               hlist_del(&ib->hash);
+                               hlist_del_init(&ib->hash);
                        /* delete from inode->free_index */
                        list_del_init(&ib->b.siblings);
                        list_move(&ib->b.lru, &togo);
@@ -123,7 +123,7 @@ void lafs_release_index(struct list_head *head)
                list_del_init(&ib->b.siblings);
                LAFS_BUG(!test_bit(B_OnFree, &ib->b.flags), &ib->b);
                if (!hlist_unhashed(&ib->hash))
-                       hlist_del(&ib->hash);
+                       hlist_del_init(&ib->hash);
                list_move(&ib->b.lru, &togo);
                freelist.freecnt--;
        }
@@ -305,10 +305,22 @@ void lafs_hash_iblock(struct indexblock *ib)
        struct hlist_head *head =
                &hash_table[ihash(ib->b.inode, ib->b.fileaddr, ib->depth)];
        spin_lock(&lafs_hash_lock);
+       LAFS_BUG(!hlist_unhashed(&ib->hash), &ib->b);
        hlist_add_head(&ib->hash, head);
        spin_unlock(&lafs_hash_lock);
 }
 
+void lafs_unhash_iblock(struct indexblock *ib)
+{
+       /* This block has been emptied and deleted and is no longer
+        * wanted in the hash tables
+        */
+       spin_lock(&lafs_hash_lock);
+       LAFS_BUG(hlist_unhashed(&ib->hash), &ib->b);
+       hlist_del_init(&ib->hash);
+       spin_unlock(&lafs_hash_lock);
+}
+
 /* adopt blk into parent if possible.
  */
 static void
diff --git a/lafs.h b/lafs.h
index bfd0fa5f0791792f15fd476535b3906dc03c1b2e..580025d9fc1a10f5b0543c692b15f05c4b0bc5e3 100644 (file)
--- a/lafs.h
+++ b/lafs.h
@@ -527,6 +527,7 @@ struct indexblock *lafs_iblock_alloc(struct fs *fs, int gfp, int with_buffer,
                                     REFARG);
 void lafs_iblock_free(struct indexblock *ib);
 void lafs_hash_iblock(struct indexblock *ib);
+void lafs_unhash_iblock(struct indexblock *ib);
 
 void lafs_summary_update(struct fs *fs, struct inode *ino,
                         u64 oldphys, u64 newphys, int is_index, int phase,
index a6ef2e7178eb67d0f884d52041d84d6108c5b855..a1dd25bdf3000ea8aed01d41e7797afdc59a008d 100644 (file)
--- a/modify.c
+++ b/modify.c
@@ -1664,6 +1664,7 @@ static void readdress_index(struct inode *ino, u32 addr, int depth,
                if (ib) {
                        lafs_iolock_block(&ib->b);
                        ib->b.fileaddr = newaddr;
+                       lafs_unhash_iblock(ib);
                        lafs_hash_iblock(ib);
                        lafs_iounlock_block(&ib->b);
                        putiref(ib, MKREF(readdr));
@@ -1987,6 +1988,7 @@ void lafs_incorporate(struct fs *fs, struct indexblock *ib)
        nxt = NULL;
        if (ib->b.siblings.next != &ib->b.parent->children)
                nxt = list_entry(ib->b.siblings.next, struct indexblock, b.siblings);
+       lafs_unhash_iblock(ib);
        if (test_and_clear_bit(B_PrimaryRef, &ib->b.flags)) {
                int cr = 0;
                /* This was not incorporated yet, revert the uninc status */