diff options
Diffstat (limited to 'fs')
| -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) |
