]> git.neil.brown.name Git - LaFS.git/commitdiff
Break linkage between inode and dblock at earliest opportunity.
authorNeilBrown <neilb@suse.de>
Sat, 31 Jul 2010 00:00:22 +0000 (10:00 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 9 Aug 2010 02:01:42 +0000 (12:01 +1000)
clear_inode is the first chance to break this linkage,
so do it there.
It is still possible for lafs_iget to get a new inode before
clear_inode has completed, so we need to do the same
test/clear in lafs_iget if b->my_inode is found to be non-NULL;

Signed-off-by: NeilBrown <neilb@suse.de>
index.c
inode.c

diff --git a/index.c b/index.c
index 4c86d6aec29f2b40481da3ee9256bff4f170c1a8..ceda44320d44205ba7814ab00db2870af1bb88ec 100644 (file)
--- a/index.c
+++ b/index.c
@@ -1053,6 +1053,7 @@ void lafs_refile(struct block *b, int dec)
                     test_bit(I_Destroyed, &LAFSI(in)->iflags))) {
                        dblk(b)->my_inode = NULL;
                        LAFSI(in)->dblock = NULL;
+                       LAFSI(in)->iblock = NULL;
                        spin_unlock(&lafs_hash_lock);
                        if (test_bit(I_Destroyed, &LAFSI(in)->iflags))
                                lafs_destroy_inode(in);
diff --git a/inode.c b/inode.c
index 0db0b4961525efdf5fb726c186fa77d37d3e5c39..52f5d995c9a9f9938902bd9e3d2ef519a0877399 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -65,6 +65,7 @@ lafs_iget(struct super_block *sb, ino_t inum, int async)
 {
        /* find, and load if needed, this inum */
        struct inode *ino = NULL;
+       struct inode *oldino;
        struct datablock *b = NULL;
        struct inode *inodefile;
        struct sb_key *k;
@@ -155,15 +156,25 @@ lafs_iget(struct super_block *sb, ino_t inum, int async)
        if (err)
                goto err;
 
-       if (b->my_inode) {
+       oldino = b->my_inode;
+       if (oldino) {
                /* The inode is new, but the block thinks it has an
                 * old inode, so we must be in the process of destroying
                 * the old one.
                 * So fail the lookup without even looking at the content
                 * of the block (Which might not be clear yet).
                 */
-               err = -ENOENT;
-               goto err;
+               spin_lock(&oldino->i_data.private_lock);
+               if (!test_bit(I_Deleting, &LAFSI(oldino)->iflags)) {
+                       b->my_inode = NULL;
+                       LAFSI(oldino)->dblock = NULL;
+                       LAFSI(oldino)->iblock = NULL;
+               }
+               spin_unlock(&oldino->i_data.private_lock);
+               if (b->my_inode) {
+                       err = -ENOENT;
+                       goto err;
+               }
        }
 
        err = lafs_import_inode(ino, b);
@@ -578,6 +589,24 @@ void lafs_clear_inode(struct inode *ino)
 
        li->type = 0;
 
+       /* Now is a good time to break the linkage between
+        * inode and dblock - but node if the file is
+        * being deleted
+        */
+       if (!test_bit(I_Deleting, &LAFSI(ino)->iflags)) {
+               struct datablock *db;
+               spin_lock(&ino->i_data.private_lock);
+               db = LAFSI(ino)->dblock;
+               if (db) {
+                       struct indexblock *ib = LAFSI(ino)->iblock;
+                       LAFS_BUG(ib && atomic_read(&ib->b.refcnt), &db->b);
+                       db->my_inode = NULL;
+                       LAFSI(ino)->dblock = NULL;
+                       LAFSI(ino)->iblock = NULL;
+               }
+               spin_unlock(&ino->i_data.private_lock);
+       }
+
        /* FIXME release quota inodes if filesystem */
 }