diff options
| -rw-r--r-- | fs/xfs/xfs_ioctl.c | 101 |
1 files changed, 55 insertions, 46 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index b0064bdb7a6e..0f62f5b3e221 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c | |||
| @@ -1042,7 +1042,6 @@ xfs_ioctl_setattr_xflags( | |||
| 1042 | !capable(CAP_LINUX_IMMUTABLE)) | 1042 | !capable(CAP_LINUX_IMMUTABLE)) |
| 1043 | return -EPERM; | 1043 | return -EPERM; |
| 1044 | 1044 | ||
| 1045 | xfs_trans_ijoin(tp, ip, 0); | ||
| 1046 | xfs_set_diflags(ip, fa->fsx_xflags); | 1045 | xfs_set_diflags(ip, fa->fsx_xflags); |
| 1047 | xfs_diflags_to_linux(ip); | 1046 | xfs_diflags_to_linux(ip); |
| 1048 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); | 1047 | xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG); |
| @@ -1051,6 +1050,54 @@ xfs_ioctl_setattr_xflags( | |||
| 1051 | return 0; | 1050 | return 0; |
| 1052 | } | 1051 | } |
| 1053 | 1052 | ||
| 1053 | /* | ||
| 1054 | * Set up the transaction structure for the setattr operation, checking that we | ||
| 1055 | * have permission to do so. On success, return a clean transaction and the | ||
| 1056 | * inode locked exclusively ready for further operation specific checks. On | ||
| 1057 | * failure, return an error without modifying or locking the inode. | ||
| 1058 | */ | ||
| 1059 | static struct xfs_trans * | ||
| 1060 | xfs_ioctl_setattr_get_trans( | ||
| 1061 | struct xfs_inode *ip) | ||
| 1062 | { | ||
| 1063 | struct xfs_mount *mp = ip->i_mount; | ||
| 1064 | struct xfs_trans *tp; | ||
| 1065 | int error; | ||
| 1066 | |||
| 1067 | if (mp->m_flags & XFS_MOUNT_RDONLY) | ||
| 1068 | return ERR_PTR(-EROFS); | ||
| 1069 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
| 1070 | return ERR_PTR(-EIO); | ||
| 1071 | |||
| 1072 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); | ||
| 1073 | error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); | ||
| 1074 | if (error) | ||
| 1075 | goto out_cancel; | ||
| 1076 | |||
| 1077 | xfs_ilock(ip, XFS_ILOCK_EXCL); | ||
| 1078 | xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); | ||
| 1079 | |||
| 1080 | /* | ||
| 1081 | * CAP_FOWNER overrides the following restrictions: | ||
| 1082 | * | ||
| 1083 | * The user ID of the calling process must be equal to the file owner | ||
| 1084 | * ID, except in cases where the CAP_FSETID capability is applicable. | ||
| 1085 | */ | ||
| 1086 | if (!inode_owner_or_capable(VFS_I(ip))) { | ||
| 1087 | error = -EPERM; | ||
| 1088 | goto out_cancel; | ||
| 1089 | } | ||
| 1090 | |||
| 1091 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
| 1092 | xfs_trans_set_sync(tp); | ||
| 1093 | |||
| 1094 | return tp; | ||
| 1095 | |||
| 1096 | out_cancel: | ||
| 1097 | xfs_trans_cancel(tp, 0); | ||
| 1098 | return ERR_PTR(error); | ||
| 1099 | } | ||
| 1100 | |||
| 1054 | #define FSX_PROJID 1 | 1101 | #define FSX_PROJID 1 |
| 1055 | #define FSX_EXTSIZE 2 | 1102 | #define FSX_EXTSIZE 2 |
| 1056 | #define FSX_XFLAGS 4 | 1103 | #define FSX_XFLAGS 4 |
| @@ -1063,7 +1110,6 @@ xfs_ioctl_setattr( | |||
| 1063 | { | 1110 | { |
| 1064 | struct xfs_mount *mp = ip->i_mount; | 1111 | struct xfs_mount *mp = ip->i_mount; |
| 1065 | struct xfs_trans *tp; | 1112 | struct xfs_trans *tp; |
| 1066 | unsigned int lock_flags = 0; | ||
| 1067 | struct xfs_dquot *udqp = NULL; | 1113 | struct xfs_dquot *udqp = NULL; |
| 1068 | struct xfs_dquot *pdqp = NULL; | 1114 | struct xfs_dquot *pdqp = NULL; |
| 1069 | struct xfs_dquot *olddquot = NULL; | 1115 | struct xfs_dquot *olddquot = NULL; |
| @@ -1071,11 +1117,6 @@ xfs_ioctl_setattr( | |||
| 1071 | 1117 | ||
| 1072 | trace_xfs_ioctl_setattr(ip); | 1118 | trace_xfs_ioctl_setattr(ip); |
| 1073 | 1119 | ||
| 1074 | if (mp->m_flags & XFS_MOUNT_RDONLY) | ||
| 1075 | return -EROFS; | ||
| 1076 | if (XFS_FORCED_SHUTDOWN(mp)) | ||
| 1077 | return -EIO; | ||
| 1078 | |||
| 1079 | /* | 1120 | /* |
| 1080 | * Disallow 32bit project ids when projid32bit feature is not enabled. | 1121 | * Disallow 32bit project ids when projid32bit feature is not enabled. |
| 1081 | */ | 1122 | */ |
| @@ -1099,28 +1140,10 @@ xfs_ioctl_setattr( | |||
| 1099 | return code; | 1140 | return code; |
| 1100 | } | 1141 | } |
| 1101 | 1142 | ||
| 1102 | /* | 1143 | tp = xfs_ioctl_setattr_get_trans(ip); |
| 1103 | * For the other attributes, we acquire the inode lock and | 1144 | if (IS_ERR(tp)) { |
| 1104 | * first do an error checking pass. | 1145 | code = PTR_ERR(tp); |
| 1105 | */ | 1146 | goto error_free_dquots; |
| 1106 | tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); | ||
| 1107 | code = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); | ||
| 1108 | if (code) | ||
| 1109 | goto error_return; | ||
| 1110 | |||
| 1111 | lock_flags = XFS_ILOCK_EXCL; | ||
| 1112 | xfs_ilock(ip, lock_flags); | ||
| 1113 | |||
| 1114 | /* | ||
| 1115 | * CAP_FOWNER overrides the following restrictions: | ||
| 1116 | * | ||
| 1117 | * The user ID of the calling process must be equal | ||
| 1118 | * to the file owner ID, except in cases where the | ||
| 1119 | * CAP_FSETID capability is applicable. | ||
| 1120 | */ | ||
| 1121 | if (!inode_owner_or_capable(VFS_I(ip))) { | ||
| 1122 | code = -EPERM; | ||
| 1123 | goto error_return; | ||
| 1124 | } | 1147 | } |
| 1125 | 1148 | ||
| 1126 | /* | 1149 | /* |
| @@ -1244,20 +1267,7 @@ xfs_ioctl_setattr( | |||
| 1244 | ip->i_d.di_extsize = extsize; | 1267 | ip->i_d.di_extsize = extsize; |
| 1245 | } | 1268 | } |
| 1246 | 1269 | ||
| 1247 | /* | ||
| 1248 | * If this is a synchronous mount, make sure that the | ||
| 1249 | * transaction goes to disk before returning to the user. | ||
| 1250 | * This is slightly sub-optimal in that truncates require | ||
| 1251 | * two sync transactions instead of one for wsync filesystems. | ||
| 1252 | * One for the truncate and one for the timestamps since we | ||
| 1253 | * don't want to change the timestamps unless we're sure the | ||
| 1254 | * truncate worked. Truncates are less than 1% of the laddis | ||
| 1255 | * mix so this probably isn't worth the trouble to optimize. | ||
| 1256 | */ | ||
| 1257 | if (mp->m_flags & XFS_MOUNT_WSYNC) | ||
| 1258 | xfs_trans_set_sync(tp); | ||
| 1259 | code = xfs_trans_commit(tp, 0); | 1270 | code = xfs_trans_commit(tp, 0); |
| 1260 | xfs_iunlock(ip, lock_flags); | ||
| 1261 | 1271 | ||
| 1262 | /* | 1272 | /* |
| 1263 | * Release any dquot(s) the inode had kept before chown. | 1273 | * Release any dquot(s) the inode had kept before chown. |
| @@ -1268,12 +1278,11 @@ xfs_ioctl_setattr( | |||
| 1268 | 1278 | ||
| 1269 | return code; | 1279 | return code; |
| 1270 | 1280 | ||
| 1271 | error_return: | 1281 | error_return: |
| 1282 | xfs_trans_cancel(tp, 0); | ||
| 1283 | error_free_dquots: | ||
| 1272 | xfs_qm_dqrele(udqp); | 1284 | xfs_qm_dqrele(udqp); |
| 1273 | xfs_qm_dqrele(pdqp); | 1285 | xfs_qm_dqrele(pdqp); |
| 1274 | xfs_trans_cancel(tp, 0); | ||
| 1275 | if (lock_flags) | ||
| 1276 | xfs_iunlock(ip, lock_flags); | ||
| 1277 | return code; | 1286 | return code; |
| 1278 | } | 1287 | } |
| 1279 | 1288 | ||
