diff options
Diffstat (limited to 'fs/ocfs2/file.c')
-rw-r--r-- | fs/ocfs2/file.c | 53 |
1 files changed, 30 insertions, 23 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index c2a87c885b73..1a96cac31791 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -894,9 +894,9 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
894 | struct ocfs2_super *osb = OCFS2_SB(sb); | 894 | struct ocfs2_super *osb = OCFS2_SB(sb); |
895 | struct buffer_head *bh = NULL; | 895 | struct buffer_head *bh = NULL; |
896 | handle_t *handle = NULL; | 896 | handle_t *handle = NULL; |
897 | int locked[MAXQUOTAS] = {0, 0}; | 897 | int qtype; |
898 | int credits, qtype; | 898 | struct dquot *transfer_from[MAXQUOTAS] = { }; |
899 | struct ocfs2_mem_dqinfo *oinfo; | 899 | struct dquot *transfer_to[MAXQUOTAS] = { }; |
900 | 900 | ||
901 | mlog_entry("(0x%p, '%.*s')\n", dentry, | 901 | mlog_entry("(0x%p, '%.*s')\n", dentry, |
902 | dentry->d_name.len, dentry->d_name.name); | 902 | dentry->d_name.len, dentry->d_name.name); |
@@ -969,30 +969,37 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
969 | 969 | ||
970 | if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || | 970 | if ((attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || |
971 | (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { | 971 | (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { |
972 | credits = OCFS2_INODE_UPDATE_CREDITS; | 972 | /* |
973 | * Gather pointers to quota structures so that allocation / | ||
974 | * freeing of quota structures happens here and not inside | ||
975 | * vfs_dq_transfer() where we have problems with lock ordering | ||
976 | */ | ||
973 | if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid | 977 | if (attr->ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid |
974 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, | 978 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, |
975 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { | 979 | OCFS2_FEATURE_RO_COMPAT_USRQUOTA)) { |
976 | oinfo = sb_dqinfo(sb, USRQUOTA)->dqi_priv; | 980 | transfer_to[USRQUOTA] = dqget(sb, attr->ia_uid, |
977 | status = ocfs2_lock_global_qf(oinfo, 1); | 981 | USRQUOTA); |
978 | if (status < 0) | 982 | transfer_from[USRQUOTA] = dqget(sb, inode->i_uid, |
983 | USRQUOTA); | ||
984 | if (!transfer_to[USRQUOTA] || !transfer_from[USRQUOTA]) { | ||
985 | status = -ESRCH; | ||
979 | goto bail_unlock; | 986 | goto bail_unlock; |
980 | credits += ocfs2_calc_qinit_credits(sb, USRQUOTA) + | 987 | } |
981 | ocfs2_calc_qdel_credits(sb, USRQUOTA); | ||
982 | locked[USRQUOTA] = 1; | ||
983 | } | 988 | } |
984 | if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid | 989 | if (attr->ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid |
985 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, | 990 | && OCFS2_HAS_RO_COMPAT_FEATURE(sb, |
986 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { | 991 | OCFS2_FEATURE_RO_COMPAT_GRPQUOTA)) { |
987 | oinfo = sb_dqinfo(sb, GRPQUOTA)->dqi_priv; | 992 | transfer_to[GRPQUOTA] = dqget(sb, attr->ia_gid, |
988 | status = ocfs2_lock_global_qf(oinfo, 1); | 993 | GRPQUOTA); |
989 | if (status < 0) | 994 | transfer_from[GRPQUOTA] = dqget(sb, inode->i_gid, |
995 | GRPQUOTA); | ||
996 | if (!transfer_to[GRPQUOTA] || !transfer_from[GRPQUOTA]) { | ||
997 | status = -ESRCH; | ||
990 | goto bail_unlock; | 998 | goto bail_unlock; |
991 | credits += ocfs2_calc_qinit_credits(sb, GRPQUOTA) + | 999 | } |
992 | ocfs2_calc_qdel_credits(sb, GRPQUOTA); | ||
993 | locked[GRPQUOTA] = 1; | ||
994 | } | 1000 | } |
995 | handle = ocfs2_start_trans(osb, credits); | 1001 | handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS + |
1002 | 2 * ocfs2_quota_trans_credits(sb)); | ||
996 | if (IS_ERR(handle)) { | 1003 | if (IS_ERR(handle)) { |
997 | status = PTR_ERR(handle); | 1004 | status = PTR_ERR(handle); |
998 | mlog_errno(status); | 1005 | mlog_errno(status); |
@@ -1030,12 +1037,6 @@ int ocfs2_setattr(struct dentry *dentry, struct iattr *attr) | |||
1030 | bail_commit: | 1037 | bail_commit: |
1031 | ocfs2_commit_trans(osb, handle); | 1038 | ocfs2_commit_trans(osb, handle); |
1032 | bail_unlock: | 1039 | bail_unlock: |
1033 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) { | ||
1034 | if (!locked[qtype]) | ||
1035 | continue; | ||
1036 | oinfo = sb_dqinfo(sb, qtype)->dqi_priv; | ||
1037 | ocfs2_unlock_global_qf(oinfo, 1); | ||
1038 | } | ||
1039 | ocfs2_inode_unlock(inode, 1); | 1040 | ocfs2_inode_unlock(inode, 1); |
1040 | bail_unlock_rw: | 1041 | bail_unlock_rw: |
1041 | if (size_change) | 1042 | if (size_change) |
@@ -1043,6 +1044,12 @@ bail_unlock_rw: | |||
1043 | bail: | 1044 | bail: |
1044 | brelse(bh); | 1045 | brelse(bh); |
1045 | 1046 | ||
1047 | /* Release quota pointers in case we acquired them */ | ||
1048 | for (qtype = 0; qtype < MAXQUOTAS; qtype++) { | ||
1049 | dqput(transfer_to[qtype]); | ||
1050 | dqput(transfer_from[qtype]); | ||
1051 | } | ||
1052 | |||
1046 | if (!status && attr->ia_valid & ATTR_MODE) { | 1053 | if (!status && attr->ia_valid & ATTR_MODE) { |
1047 | status = ocfs2_acl_chmod(inode); | 1054 | status = ocfs2_acl_chmod(inode); |
1048 | if (status < 0) | 1055 | if (status < 0) |