diff options
author | Dave Chinner <dchinner@redhat.com> | 2015-02-01 18:15:35 -0500 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2015-02-01 18:15:35 -0500 |
commit | 8f3d17ab060ec21cead88b81c65050a6ff77e9be (patch) | |
tree | bc26a18e07bb3e0bf4fd44abd7903f9e60f25f79 /fs | |
parent | 29a17c00d4b1b8eab61b85b71cb5a83455a7dc5e (diff) |
xfs: factor out xfs_ioctl_setattr transaciton preamble
The setup of the transaction is done after a random smattering of
checks and before another bunch of ioperations specific
validity checks. Pull all the preamble out into a helper function
that returns a transaction or error.
Signed-off-by: Dave Chinner <dchinner@redhat.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs')
-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 | ||