aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2016-04-01 01:31:28 -0400
committerTheodore Ts'o <tytso@mit.edu>2016-04-01 01:31:28 -0400
commitdaf647d2dd58cec59570d7698a45b98e580f2076 (patch)
tree91d950bb640b3e16c36bf09265d46bd07dd0fba0
parent1028b55bafb7611dda1d8fed2aeca16a436b7dff (diff)
ext4: add lockdep annotations for i_data_sem
With the internal Quota feature, mke2fs creates empty quota inodes and quota usage tracking is enabled as soon as the file system is mounted. Since quotacheck is no longer preallocating all of the blocks in the quota inode that are likely needed to be written to, we are now seeing a lockdep false positive caused by needing to allocate a quota block from inside ext4_map_blocks(), while holding i_data_sem for a data inode. This results in this complaint: Possible unsafe locking scenario: CPU0 CPU1 ---- ---- lock(&ei->i_data_sem); lock(&s->s_dquot.dqio_mutex); lock(&ei->i_data_sem); lock(&s->s_dquot.dqio_mutex); Google-Bug-Id: 27907753 Signed-off-by: Theodore Ts'o <tytso@mit.edu> Cc: stable@vger.kernel.org
-rw-r--r--fs/ext4/ext4.h23
-rw-r--r--fs/ext4/move_extent.c11
-rw-r--r--fs/ext4/super.c25
3 files changed, 55 insertions, 4 deletions
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index 7e4e3e9b4494..6a857af0e6b1 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -912,6 +912,29 @@ do { \
912#include "extents_status.h" 912#include "extents_status.h"
913 913
914/* 914/*
915 * Lock subclasses for i_data_sem in the ext4_inode_info structure.
916 *
917 * These are needed to avoid lockdep false positives when we need to
918 * allocate blocks to the quota inode during ext4_map_blocks(), while
919 * holding i_data_sem for a normal (non-quota) inode. Since we don't
920 * do quota tracking for the quota inode, this avoids deadlock (as
921 * well as infinite recursion, since it isn't turtles all the way
922 * down...)
923 *
924 * I_DATA_SEM_NORMAL - Used for most inodes
925 * I_DATA_SEM_OTHER - Used by move_inode.c for the second normal inode
926 * where the second inode has larger inode number
927 * than the first
928 * I_DATA_SEM_QUOTA - Used for quota inodes only
929 */
930enum {
931 I_DATA_SEM_NORMAL = 0,
932 I_DATA_SEM_OTHER,
933 I_DATA_SEM_QUOTA,
934};
935
936
937/*
915 * fourth extended file system inode data in memory 938 * fourth extended file system inode data in memory
916 */ 939 */
917struct ext4_inode_info { 940struct ext4_inode_info {
diff --git a/fs/ext4/move_extent.c b/fs/ext4/move_extent.c
index 4098acc701c3..796ff0eafd3c 100644
--- a/fs/ext4/move_extent.c
+++ b/fs/ext4/move_extent.c
@@ -60,10 +60,10 @@ ext4_double_down_write_data_sem(struct inode *first, struct inode *second)
60{ 60{
61 if (first < second) { 61 if (first < second) {
62 down_write(&EXT4_I(first)->i_data_sem); 62 down_write(&EXT4_I(first)->i_data_sem);
63 down_write_nested(&EXT4_I(second)->i_data_sem, SINGLE_DEPTH_NESTING); 63 down_write_nested(&EXT4_I(second)->i_data_sem, I_DATA_SEM_OTHER);
64 } else { 64 } else {
65 down_write(&EXT4_I(second)->i_data_sem); 65 down_write(&EXT4_I(second)->i_data_sem);
66 down_write_nested(&EXT4_I(first)->i_data_sem, SINGLE_DEPTH_NESTING); 66 down_write_nested(&EXT4_I(first)->i_data_sem, I_DATA_SEM_OTHER);
67 67
68 } 68 }
69} 69}
@@ -484,6 +484,13 @@ mext_check_arguments(struct inode *orig_inode,
484 return -EBUSY; 484 return -EBUSY;
485 } 485 }
486 486
487 if (IS_NOQUOTA(orig_inode) || IS_NOQUOTA(donor_inode)) {
488 ext4_debug("ext4 move extent: The argument files should "
489 "not be quota files [ino:orig %lu, donor %lu]\n",
490 orig_inode->i_ino, donor_inode->i_ino);
491 return -EBUSY;
492 }
493
487 /* Ext4 move extent supports only extent based file */ 494 /* Ext4 move extent supports only extent based file */
488 if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) { 495 if (!(ext4_test_inode_flag(orig_inode, EXT4_INODE_EXTENTS))) {
489 ext4_debug("ext4 move extent: orig file is not extents " 496 ext4_debug("ext4 move extent: orig file is not extents "
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 539297515896..7ebd9f040b16 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -5028,6 +5028,20 @@ static int ext4_quota_on_mount(struct super_block *sb, int type)
5028 EXT4_SB(sb)->s_jquota_fmt, type); 5028 EXT4_SB(sb)->s_jquota_fmt, type);
5029} 5029}
5030 5030
5031static void lockdep_set_quota_inode(struct inode *inode, int subclass)
5032{
5033 struct ext4_inode_info *ei = EXT4_I(inode);
5034
5035 /* The first argument of lockdep_set_subclass has to be
5036 * *exactly* the same as the argument to init_rwsem() --- in
5037 * this case, in init_once() --- or lockdep gets unhappy
5038 * because the name of the lock is set using the
5039 * stringification of the argument to init_rwsem().
5040 */
5041 (void) ei; /* shut up clang warning if !CONFIG_LOCKDEP */
5042 lockdep_set_subclass(&ei->i_data_sem, subclass);
5043}
5044
5031/* 5045/*
5032 * Standard function to be called on quota_on 5046 * Standard function to be called on quota_on
5033 */ 5047 */
@@ -5067,8 +5081,12 @@ static int ext4_quota_on(struct super_block *sb, int type, int format_id,
5067 if (err) 5081 if (err)
5068 return err; 5082 return err;
5069 } 5083 }
5070 5084 lockdep_set_quota_inode(path->dentry->d_inode, I_DATA_SEM_QUOTA);
5071 return dquot_quota_on(sb, type, format_id, path); 5085 err = dquot_quota_on(sb, type, format_id, path);
5086 if (err)
5087 lockdep_set_quota_inode(path->dentry->d_inode,
5088 I_DATA_SEM_NORMAL);
5089 return err;
5072} 5090}
5073 5091
5074static int ext4_quota_enable(struct super_block *sb, int type, int format_id, 5092static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
@@ -5095,8 +5113,11 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
5095 5113
5096 /* Don't account quota for quota files to avoid recursion */ 5114 /* Don't account quota for quota files to avoid recursion */
5097 qf_inode->i_flags |= S_NOQUOTA; 5115 qf_inode->i_flags |= S_NOQUOTA;
5116 lockdep_set_quota_inode(qf_inode, I_DATA_SEM_QUOTA);
5098 err = dquot_enable(qf_inode, type, format_id, flags); 5117 err = dquot_enable(qf_inode, type, format_id, flags);
5099 iput(qf_inode); 5118 iput(qf_inode);
5119 if (err)
5120 lockdep_set_quota_inode(qf_inode, I_DATA_SEM_NORMAL);
5100 5121
5101 return err; 5122 return err;
5102} 5123}