]> git.neil.brown.name Git - LaFS.git/commitdiff
Hold ref on inode while truncating.
authorNeilBrown <neilb@suse.de>
Sun, 1 Aug 2010 02:46:48 +0000 (12:46 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 9 Aug 2010 02:01:42 +0000 (12:01 +1000)
If I_Trunc is set and I_Deleting is not, then we hold a
reference to the inode and must drop it when clearing I_Trunc.

This ensure that delete_inode won't get called while truncate
is happening, and the inode won't otherwise disappear.

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

diff --git a/inode.c b/inode.c
index 9ca882e9aa1180f99487683cd75040748e0c2e18..b209ca2a3e21ac260dee781b5d4e75a17130af59 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -626,8 +626,10 @@ void lafs_delete_inode(struct inode *ino)
        }
        dprintk("DELETE INODE %d\n", (int)ino->i_ino);
 
-       wait_event(fs->trunc_wait,
-                  !test_bit(I_Trunc, &LAFSI(ino)->iflags));
+       /* Normal truncation holds an igrab, so we cannot be
+        * deleted until any truncation finishes
+        */
+       BUG_ON(test_bit(I_Trunc, &LAFSI(ino)->iflags));
 
        spin_lock(&ino->i_data.private_lock);
        b = LAFSI(ino)->dblock;
@@ -786,6 +788,8 @@ int lafs_inode_handle_orphan(struct datablock *b)
                        /* must be finished */
                        LAFS_BUG(test_bit(B_Dirty, &ib->b.flags), &ib->b);
                        clear_bit(I_Trunc, &LAFSI(ino)->iflags);
+                       if (!test_bit(I_Deleting, &LAFSI(ino)->iflags))
+                               iput(ino);
                        wake_up(&fs->trunc_wait);
                        err = -ERESTARTSYS;
                        goto out2;
@@ -828,6 +832,8 @@ int lafs_inode_handle_orphan(struct datablock *b)
                if (ib2->b.fileaddr < lastaddr) {
                        /* Must be all done */
                        clear_bit(I_Trunc, &LAFSI(ino)->iflags);
+                       if (!test_bit(I_Deleting, &LAFSI(ino)->iflags))
+                               iput(ino);
                        wake_up(&fs->trunc_wait);
                        err = -ERESTARTSYS;
                        goto out2;
@@ -897,6 +903,8 @@ int lafs_inode_handle_orphan(struct datablock *b)
        if (LAFSI(ino)->depth == 0) {
                /* Nothing to truncate */
                clear_bit(I_Trunc, &LAFSI(ino)->iflags);
+               if (!test_bit(I_Deleting, &LAFSI(ino)->iflags))
+                       iput(ino);
                if (test_bit(B_Pinned, &ib->b.flags))
                        /* Need to move the dirtiness which keeps this
                         * pinned to the data block.
@@ -1615,6 +1623,8 @@ void lafs_truncate(struct inode *ino)
        /* FIXME there is nothing I can do with an error here */
        lafs_make_orphan(fs, db);
 
+       if (!test_and_set_bit(I_Trunc, &LAFSI(ino)->iflags))
+               igrab(ino);
        LAFSI(ino)->trunc_next = trunc_block;
        putdref(db, MKREF(trunc));
 }