diff options
Diffstat (limited to 'fs/xfs/xfs_ioctl.c')
-rw-r--r-- | fs/xfs/xfs_ioctl.c | 90 |
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 | ||
1101 | int | ||
1102 | xfs_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 | |||
1101 | STATIC int | 1146 | STATIC int |
1102 | xfs_ioctl_setattr( | 1147 | xfs_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 | ||
1250 | error_return: | 1262 | error_trans_cancel: |
1251 | xfs_trans_cancel(tp, 0); | 1263 | xfs_trans_cancel(tp, 0); |
1252 | error_free_dquots: | 1264 | error_free_dquots: |
1253 | xfs_qm_dqrele(udqp); | 1265 | xfs_qm_dqrele(udqp); |