diff options
author | Jan Kara <jack@suse.cz> | 2010-05-13 14:18:45 -0400 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2010-05-21 13:30:48 -0400 |
commit | 52a9ee281cfb26fffce1d6c409fb4b1f4aa8a766 (patch) | |
tree | b30f8ac1bab7f793f7c3c999e9df59818578e6d9 /fs | |
parent | 741e128933448e589a85286e535078b24f4cf568 (diff) |
ocfs2: Use __dquot_transfer to avoid lock inversion
dquot_transfer() acquires own references to dquots via dqget(). Thus it waits
for dq_lock which creates a lock inversion because dq_lock ranks above
transaction start but transaction is already started in ocfs2_setattr(). Fix
the problem by passing own references directly to __dquot_transfer.
Acked-by: Joel Becker <Joel.Becker@oracle.com>
Signed-off-by: Jan Kara <jack@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/file.c | 17 |
1 files changed, 5 insertions, 12 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index e127c53ec2e7..97e54b9e654b 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -933,9 +933,8 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
933 | struct ocfs2_super *osb = OCFS2_SB(sb); | 933 | struct ocfs2_super *osb = OCFS2_SB(sb); |
934 | struct buffer_head *bh = NULL; | 934 | struct buffer_head *bh = NULL; |
935 | handle_t *handle = NULL; | 935 | handle_t *handle = NULL; |
936 | int qtype; | ||
937 | struct dquot *transfer_from[MAXQUOTAS] = { }; | ||
938 | struct dquot *transfer_to[MAXQUOTAS] = { }; | 936 | struct dquot *transfer_to[MAXQUOTAS] = { }; |
937 | int qtype; | ||
939 | 938 | ||
940 | mlog_entry("(0x%p, '%.*s')\n", dentry, | 939 | mlog_entry("(0x%p, '%.*s')\n", dentry, |
941 | dentry->d_name.len, dentry->d_name.name); | 940 | dentry->d_name.len, dentry->d_name.name); |
@@ -1019,9 +1018,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1019 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { | 1018 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { |
1020 | transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, | 1019 | transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, |
1021 | USRQUOTA); | 1020 | USRQUOTA); |
1022 | transfer_from[USRQUOTA] = dqget(sb, inode->i_uid, | 1021 | if (!transfer_to[USRQUOTA]) { |
1023 | USRQUOTA); | ||
1024 | if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) { | ||
1025 | status = -ESRCH; | 1022 | status = -ESRCH; |
1026 | goto bail_unlock; | 1023 | goto bail_unlock; |
1027 | } | 1024 | } |
@@ -1031,9 +1028,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1031 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { | 1028 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { |
1032 | transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, | 1029 | transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, |
1033 | GRPQUOTA); | 1030 | GRPQUOTA); |
1034 | transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid, | 1031 | if (!transfer_to[GRPQUOTA]) { |
1035 | GRPQUOTA); | ||
1036 | if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) { | ||
1037 | status = -ESRCH; | 1032 | status = -ESRCH; |
1038 | goto bail_unlock; | 1033 | goto bail_unlock; |
1039 | } | 1034 | } |
@@ -1045,7 +1040,7 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1045 | mlog_errno(status); | 1040 | mlog_errno(status); |
1046 | goto bail_unlock; | 1041 | goto bail_unlock; |
1047 | } | 1042 | } |
1048 | status = dquot_transfer(inode, attr); | 1043 | status = __dquot_transfer(inode, transfer_to); |
1049 | if (status < 0) | 1044 | if (status < 0) |
1050 | goto bail_commit; | 1045 | goto bail_commit; |
1051 | } else { | 1046 | } else { |
@@ -1085,10 +1080,8 @@ bail: | |||
1085 | brelse(bh); | 1080 | brelse(bh); |
1086 | 1081 | ||
1087 | /* Release quota pointers in case we acquired them */ | 1082 | /* Release quota pointers in case we acquired them */ |
1088 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) { | 1083 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) |
1089 | dqput(transfer_to[qtype]); | 1084 | dqput(transfer_to[qtype]); |
1090 | dqput(transfer_from[qtype]); | ||
1091 | } | ||
1092 | 1085 | ||
1093 | if (!status && attr->ia_valid & ATTR_MODE) { | 1086 | if (!status && attr->ia_valid & ATTR_MODE) { |
1094 | status = ocfs2_acl_chmod(inode); | 1087 | status = ocfs2_acl_chmod(inode); |