]> git.neil.brown.name Git - LaFS.git/commitdiff
Hold ref on inode during orphan handling.
authorNeilBrown <neilb@suse.de>
Sun, 1 Aug 2010 02:43:04 +0000 (12:43 +1000)
committerNeilBrown <neilb@suse.de>
Mon, 9 Aug 2010 02:01:42 +0000 (12:01 +1000)
Orphan handling will shortly drop references to the inode controlling
the orphan block.  As run_orphans needs to drop the mutex at the end
it needs to hold another reference too.

If I_Deleting is set, then the db effectively owns a reference,
so no further igrab is needed, nor will it work.

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

index 55c287a10cb6de4d500583754a78463f05cd6d40..8a562e905c78fed8248ca51baa4e2811db19b9cc 100644 (file)
--- a/orphan.c
+++ b/orphan.c
@@ -436,20 +436,30 @@ out:
        lafs_checkpoint_unlock(fs);
 }
 
-static struct mutex *orphan_mutex(struct datablock *db)
+static struct inode *orphan_inode(struct datablock *db)
 {
        switch (LAFSI(db->b.inode)->type) {
        case TypeInodeFile:
-               if (db->my_inode == NULL)
-                       return NULL;
-               return &db->my_inode->i_mutex;
+               if (db->my_inode &&
+                   test_bit(I_Deleting, &LAFSI(db->my_inode)->iflags))
+                       return db->my_inode;
+               return igrab(db->my_inode);
        case TypeDir:
-               return &db->b.inode->i_mutex;
+               return igrab(db->b.inode);
        default:
                BUG();
        }
 }
 
+static void orphan_iput(struct inode *ino)
+{
+       if (!ino)
+               return;
+       if (test_bit(I_Deleting, &LAFSI(ino)->iflags))
+               return;
+       iput(ino);
+}
+
 long lafs_run_orphans(struct fs *fs)
 {
        struct datablock *db;
@@ -468,26 +478,27 @@ long lafs_run_orphans(struct fs *fs)
        set_bit(OrphansRunning, &fs->fsstate);
        spin_lock(&fs->lock);
        while (!list_empty(&fs->pending_orphans)) {
-               struct mutex *mx;
+               struct inode *ino;
                db = list_entry(fs->pending_orphans.next,
                                struct datablock,
                                orphans);
                list_move(&db->orphans, &done);
-               mx = orphan_mutex(db);
-               if (!mx && !test_bit(B_Claimed, &db->b.flags))
-                       /* OK not to have a mutex */;
-               else if (!mx || !mutex_trylock(mx)) {
+               ino = orphan_inode(db);
+               if (!ino && !test_bit(B_Claimed, &db->b.flags))
+                       /* OK not to have an inode */;
+               else if (!ino || !mutex_trylock(&ino->i_mutex)) {
                        /* we cannot get a wakeup when mutex
                         * is unlocked, so we need timeout
                         * FIXME this is unfortunate
                         */
+                       orphan_iput(ino);
                        timeout = msecs_to_jiffies(500);
                        continue;
                }
                getdref(db, MKREF(run_orphans));
                spin_unlock(&fs->lock);
 
-               if (!mx)
+               if (!ino)
                        lafs_orphan_release(fs, db);
                else {
                        int err = -ERESTARTSYS;
@@ -503,9 +514,10 @@ long lafs_run_orphans(struct fs *fs)
                                if (err == -ENOMEM)
                                        timeout = msecs_to_jiffies(500);
                        }
-                       mutex_unlock(mx);
+                       mutex_unlock(&ino->i_mutex);
                }
 
+               orphan_iput(ino);
                putdref(db, MKREF(run_orphans));
                spin_lock(&fs->lock);
        }
@@ -534,8 +546,11 @@ int lafs_drop_orphan(struct fs *fs, struct datablock *db)
         * It must be IOlocked, and this call must not come
         * from lafs_run_orphans.
         */
-       struct mutex *mx = orphan_mutex(db);
-       BUG_ON(mx && !mutex_is_locked(mx));
+       struct inode *ino = orphan_inode(db);
+
+       BUG_ON(ino && !mutex_is_locked(&ino->i_mutex));
+       orphan_iput(ino);
+
        if (test_bit(B_Orphan, &db->b.flags))
                return 0;
        spin_lock(&fs->lock);