]> git.neil.brown.name Git - LaFS.git/commitdiff
While truncating, hold ref on superblock as well as inode.
authorNeilBrown <neilb@suse.de>
Sun, 10 Oct 2010 23:47:33 +0000 (10:47 +1100)
committerNeilBrown <neilb@suse.de>
Sun, 10 Oct 2010 23:47:33 +0000 (10:47 +1100)
An unmount of a subsect filesystem could happen while still truncating
a file on the filesystem.  So hold a ref to the superblock so that it
doesn't go away.
When deleting, we cannot grab the inode, so we need to modify
lafs_iput_fs to not do an iput in that case.

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

diff --git a/inode.c b/inode.c
index 1c651725de7bc4bd1fac516d26b133dea707bc45..acc9261ea813c44719d0ac92e4be1f2c7e28f076 100644 (file)
--- a/inode.c
+++ b/inode.c
@@ -705,9 +705,10 @@ void lafs_delete_inode(struct inode *ino)
        i_size_write(ino, 0);
        truncate_inode_pages(&ino->i_data, 0);
        LAFSI(ino)->trunc_next = 0;
+       set_bit(I_Deleting, &LAFSI(ino)->iflags);
        set_bit(I_Trunc, &LAFSI(ino)->iflags);
+       lafs_igrab_fs(ino);
 
-       set_bit(I_Deleting, &LAFSI(ino)->iflags);
        if (!IS_ERR(b)) {
                set_bit(B_Claimed, &b->b.flags);
                lafs_add_orphan(fs, b);
@@ -851,8 +852,7 @@ 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);
+                       lafs_iput_fs(ino);
                        wake_up(&fs->trunc_wait);
                        err = -ERESTARTSYS;
                        goto out2;
@@ -894,8 +894,7 @@ int lafs_inode_handle_orphan(struct datablock *b)
                        /* Must be all done */
                        spin_unlock(&ib->b.inode->i_data.private_lock);
                        clear_bit(I_Trunc, &LAFSI(ino)->iflags);
-                       if (!test_bit(I_Deleting, &LAFSI(ino)->iflags))
-                               iput(ino);
+                       lafs_iput_fs(ino);
                        wake_up(&fs->trunc_wait);
                        err = -ERESTARTSYS;
                        goto out2;
@@ -966,8 +965,7 @@ 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);
+               lafs_iput_fs(ino);
                if (test_bit(B_Pinned, &ib->b.flags))
                        /* Need to move the dirtiness which keeps this
                         * pinned to the data block.
@@ -1748,7 +1746,7 @@ void lafs_truncate(struct inode *ino)
        lafs_make_orphan(fs, db);
 
        if (!test_and_set_bit(I_Trunc, &LAFSI(ino)->iflags))
-               igrab(ino);
+               lafs_igrab_fs(ino);
        if (trunc_block == 0)
                LAFSI(ino)->trunc_gen++;
        LAFSI(ino)->trunc_next = trunc_block;
diff --git a/lafs.h b/lafs.h
index c6c0bb205499cc8643e98fcdbba2cc67a656442b..42198fa9fabf8f601988e2357e948632e2d2e3b0 100644 (file)
--- a/lafs.h
+++ b/lafs.h
@@ -156,13 +156,16 @@ int lafs_inode_handle_orphan(struct datablock *b);
 static inline void lafs_iput_fs(struct inode *ino)
 {
        struct super_block *sb = ino->i_sb;
-       iput(ino);
+       if (!test_bit(I_Deleting, &LAFSI(ino)->iflags))
+               iput(ino);
        deactivate_super(sb);
 }
 
 static inline void lafs_igrab_fs(struct inode *ino)
 {
-       igrab(ino);
+       if (igrab(ino) == NULL &&       
+           !test_bit(I_Deleting, &LAFSI(ino)->iflags))
+               BUG();
        atomic_inc(&ino->i_sb->s_active);
 }