ocfs2: Fix lock inversion in quotas during umount
Jan Kara [Thu, 13 May 2010 20:14:53 +0000 (22:14 +0200)]
We cannot cancel delayed work from ocfs2_local_free_info because that is called
with dqonoff_mutex held and the work it cancels requires dqonoff_mutex to
finish. Cancel the work before acquiring dqonoff_mutex.

Acked-by: Joel Becker <Joel.Becker@oracle.com>
Signed-off-by: Jan Kara <jack@suse.cz>

fs/ocfs2/quota_local.c
fs/ocfs2/super.c

index 551a6bf..8bd70d4 100644 (file)
@@ -816,10 +816,6 @@ static int ocfs2_local_free_info(struct super_block *sb, int type)
        int mark_clean = 1, len;
        int status;
 
-       /* At this point we know there are no more dquots and thus
-        * even if there's some sync in the pdflush queue, it won't
-        * find any dquots and return without doing anything */
-       cancel_delayed_work_sync(&oinfo->dqi_sync_work);
        iput(oinfo->dqi_gqinode);
        ocfs2_simple_drop_lockres(OCFS2_SB(sb), &oinfo->dqi_gqlock);
        ocfs2_lock_res_free(&oinfo->dqi_gqlock);
index 1c2c39f..2c26ce2 100644 (file)
@@ -938,12 +938,16 @@ static void ocfs2_disable_quotas(struct ocfs2_super *osb)
        int type;
        struct inode *inode;
        struct super_block *sb = osb->sb;
+       struct ocfs2_mem_dqinfo *oinfo;
 
        /* We mostly ignore errors in this function because there's not much
         * we can do when we see them */
        for (type = 0; type < MAXQUOTAS; type++) {
                if (!sb_has_quota_loaded(sb, type))
                        continue;
+               /* Cancel periodic syncing before we grab dqonoff_mutex */
+               oinfo = sb_dqinfo(sb, type)->dqi_priv;
+               cancel_delayed_work_sync(&oinfo->dqi_sync_work);
                inode = igrab(sb->s_dquot.files[type]);
                /* Turn off quotas. This will remove all dquot structures from
                 * memory and so they will be automatically synced to global