aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/xfs/xfs_ioctl.c90
1 files changed, 51 insertions, 39 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index b65817cbc318..9f808539fc61 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1098,6 +1098,51 @@ out_cancel:
1098 return ERR_PTR(error); 1098 return ERR_PTR(error);
1099} 1099}
1100 1100
1101int
1102xfs_ioctl_setattr_check_extsize(
1103 struct xfs_inode *ip,
1104 struct fsxattr *fa)
1105{
1106 struct xfs_mount *mp = ip->i_mount;
1107
1108 /* Can't change extent size if any extents are allocated. */
1109 if (ip->i_d.di_nextents &&
1110 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
1111 return -EINVAL;
1112
1113 /*
1114 * Extent size must be a multiple of the appropriate block size, if set
1115 * at all. It must also be smaller than the maximum extent size
1116 * supported by the filesystem.
1117 *
1118 * Also, for non-realtime files, limit the extent size hint to half the
1119 * size of the AGs in the filesystem so alignment doesn't result in
1120 * extents larger than an AG.
1121 */
1122 if (fa->fsx_extsize != 0) {
1123 xfs_extlen_t size;
1124 xfs_fsblock_t extsize_fsb;
1125
1126 extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize);
1127 if (extsize_fsb > MAXEXTLEN)
1128 return -EINVAL;
1129
1130 if (XFS_IS_REALTIME_INODE(ip) ||
1131 (fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1132 size = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog;
1133 } else {
1134 size = mp->m_sb.sb_blocksize;
1135 if (extsize_fsb > mp->m_sb.sb_agblocks / 2)
1136 return -EINVAL;
1137 }
1138
1139 if (fa->fsx_extsize % size)
1140 return -EINVAL;
1141 }
1142 return 0;
1143}
1144
1145
1101STATIC int 1146STATIC int
1102xfs_ioctl_setattr( 1147xfs_ioctl_setattr(
1103 xfs_inode_t *ip, 1148 xfs_inode_t *ip,
@@ -1160,49 +1205,16 @@ xfs_ioctl_setattr(
1160 code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, pdqp, 1205 code = xfs_qm_vop_chown_reserve(tp, ip, udqp, NULL, pdqp,
1161 capable(CAP_FOWNER) ? XFS_QMOPT_FORCE_RES : 0); 1206 capable(CAP_FOWNER) ? XFS_QMOPT_FORCE_RES : 0);
1162 if (code) /* out of quota */ 1207 if (code) /* out of quota */
1163 goto error_return; 1208 goto error_trans_cancel;
1164 }
1165
1166 /* Can't change extent size if any extents are allocated. */
1167 code = -EINVAL;
1168 if (ip->i_d.di_nextents &&
1169 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
1170 goto error_return;
1171
1172 /*
1173 * Extent size must be a multiple of the appropriate block size, if set
1174 * at all. It must also be smaller than the maximum extent size
1175 * supported by the filesystem.
1176 *
1177 * Also, for non-realtime files, limit the extent size hint to half the
1178 * size of the AGs in the filesystem so alignment doesn't result in
1179 * extents larger than an AG.
1180 */
1181 if (fa->fsx_extsize != 0) {
1182 xfs_extlen_t size;
1183 xfs_fsblock_t extsize_fsb;
1184
1185 extsize_fsb = XFS_B_TO_FSB(mp, fa->fsx_extsize);
1186 if (extsize_fsb > MAXEXTLEN)
1187 goto error_return;
1188
1189 if (XFS_IS_REALTIME_INODE(ip) ||
1190 (fa->fsx_xflags & XFS_XFLAG_REALTIME)) {
1191 size = mp->m_sb.sb_rextsize << mp->m_sb.sb_blocklog;
1192 } else {
1193 size = mp->m_sb.sb_blocksize;
1194 if (extsize_fsb > mp->m_sb.sb_agblocks / 2)
1195 goto error_return;
1196 }
1197
1198 if (fa->fsx_extsize % size)
1199 goto error_return;
1200 } 1209 }
1201 1210
1211 code = xfs_ioctl_setattr_check_extsize(ip, fa);
1212 if (code)
1213 goto error_trans_cancel;
1202 1214
1203 code = xfs_ioctl_setattr_xflags(tp, ip, fa); 1215 code = xfs_ioctl_setattr_xflags(tp, ip, fa);
1204 if (code) 1216 if (code)
1205 goto error_return; 1217 goto error_trans_cancel;
1206 1218
1207 /* 1219 /*
1208 * Change file ownership. Must be the owner or privileged. CAP_FSETID 1220 * Change file ownership. Must be the owner or privileged. CAP_FSETID
@@ -1247,7 +1259,7 @@ xfs_ioctl_setattr(
1247 1259
1248 return code; 1260 return code;
1249 1261
1250error_return: 1262error_trans_cancel:
1251 xfs_trans_cancel(tp, 0); 1263 xfs_trans_cancel(tp, 0);
1252error_free_dquots: 1264error_free_dquots:
1253 xfs_qm_dqrele(udqp); 1265 xfs_qm_dqrele(udqp);