ext4: clear lockdep subtype for quota files on quota off
authorJan Kara <jack@suse.cz>
Mon, 22 May 2017 02:31:23 +0000 (22:31 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 22 May 2017 02:31:23 +0000 (22:31 -0400)
Quota files have special ranking of i_data_sem lock. We inform lockdep
about it when turning on quotas however when turning quotas off, we
don't clear the lockdep subclass from i_data_sem lock and thus when the
inode gets later reused for a normal file or directory, lockdep gets
confused and complains about possible deadlocks. Fix the problem by
resetting lockdep subclass of i_data_sem on quota off.

Cc: stable@vger.kernel.org
Fixes: daf647d2dd58cec59570d7698a45b98e580f2076
Reported-and-tested-by: Ross Zwisler <ross.zwisler@linux.intel.com>
Reviewed-by: Andreas Dilger <adilger@dilger.ca>
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
fs/ext4/super.c

index 0b177da9ea8271f4a46208937d3c43fd20c0e9b7..8f05c72bc4ec7c08361513b5689334fa6a71ae77 100644 (file)
@@ -848,14 +848,9 @@ static inline void ext4_quota_off_umount(struct super_block *sb)
 {
        int type;
 
-       if (ext4_has_feature_quota(sb)) {
-               dquot_disable(sb, -1,
-                             DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED);
-       } else {
-               /* Use our quota_off function to clear inode flags etc. */
-               for (type = 0; type < EXT4_MAXQUOTAS; type++)
-                       ext4_quota_off(sb, type);
-       }
+       /* Use our quota_off function to clear inode flags etc. */
+       for (type = 0; type < EXT4_MAXQUOTAS; type++)
+               ext4_quota_off(sb, type);
 }
 #else
 static inline void ext4_quota_off_umount(struct super_block *sb)
@@ -5485,7 +5480,7 @@ static int ext4_quota_off(struct super_block *sb, int type)
                goto out;
 
        err = dquot_quota_off(sb, type);
-       if (err)
+       if (err || ext4_has_feature_quota(sb))
                goto out_put;
 
        inode_lock(inode);
@@ -5505,6 +5500,7 @@ static int ext4_quota_off(struct super_block *sb, int type)
 out_unlock:
        inode_unlock(inode);
 out_put:
+       lockdep_set_quota_inode(inode, I_DATA_SEM_NORMAL);
        iput(inode);
        return err;
 out: