From: NeilBrown Date: Sun, 1 Aug 2010 02:43:04 +0000 (+1000) Subject: Hold ref on inode during orphan handling. X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=4fbacb536346bf0cd9c03ce51d4a274fc2753642;p=LaFS.git Hold ref on inode during orphan handling. 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 --- diff --git a/orphan.c b/orphan.c index 55c287a..8a562e9 100644 --- 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);