aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_ioctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_ioctl.c')
-rw-r--r--fs/xfs/xfs_ioctl.c121
1 files changed, 106 insertions, 15 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 478d04e07f95..bcb6c19ce3ea 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -114,7 +114,7 @@ xfs_find_handle(
114 handle.ha_fid.fid_len = sizeof(xfs_fid_t) - 114 handle.ha_fid.fid_len = sizeof(xfs_fid_t) -
115 sizeof(handle.ha_fid.fid_len); 115 sizeof(handle.ha_fid.fid_len);
116 handle.ha_fid.fid_pad = 0; 116 handle.ha_fid.fid_pad = 0;
117 handle.ha_fid.fid_gen = ip->i_d.di_gen; 117 handle.ha_fid.fid_gen = inode->i_generation;
118 handle.ha_fid.fid_ino = ip->i_ino; 118 handle.ha_fid.fid_ino = ip->i_ino;
119 119
120 hsize = XFS_HSIZE(handle); 120 hsize = XFS_HSIZE(handle);
@@ -963,7 +963,7 @@ xfs_set_diflags(
963 di_flags |= XFS_DIFLAG_NODEFRAG; 963 di_flags |= XFS_DIFLAG_NODEFRAG;
964 if (xflags & FS_XFLAG_FILESTREAM) 964 if (xflags & FS_XFLAG_FILESTREAM)
965 di_flags |= XFS_DIFLAG_FILESTREAM; 965 di_flags |= XFS_DIFLAG_FILESTREAM;
966 if (S_ISDIR(ip->i_d.di_mode)) { 966 if (S_ISDIR(VFS_I(ip)->i_mode)) {
967 if (xflags & FS_XFLAG_RTINHERIT) 967 if (xflags & FS_XFLAG_RTINHERIT)
968 di_flags |= XFS_DIFLAG_RTINHERIT; 968 di_flags |= XFS_DIFLAG_RTINHERIT;
969 if (xflags & FS_XFLAG_NOSYMLINKS) 969 if (xflags & FS_XFLAG_NOSYMLINKS)
@@ -972,7 +972,7 @@ xfs_set_diflags(
972 di_flags |= XFS_DIFLAG_EXTSZINHERIT; 972 di_flags |= XFS_DIFLAG_EXTSZINHERIT;
973 if (xflags & FS_XFLAG_PROJINHERIT) 973 if (xflags & FS_XFLAG_PROJINHERIT)
974 di_flags |= XFS_DIFLAG_PROJINHERIT; 974 di_flags |= XFS_DIFLAG_PROJINHERIT;
975 } else if (S_ISREG(ip->i_d.di_mode)) { 975 } else if (S_ISREG(VFS_I(ip)->i_mode)) {
976 if (xflags & FS_XFLAG_REALTIME) 976 if (xflags & FS_XFLAG_REALTIME)
977 di_flags |= XFS_DIFLAG_REALTIME; 977 di_flags |= XFS_DIFLAG_REALTIME;
978 if (xflags & FS_XFLAG_EXTSIZE) 978 if (xflags & FS_XFLAG_EXTSIZE)
@@ -1060,23 +1060,86 @@ xfs_ioctl_setattr_xflags(
1060} 1060}
1061 1061
1062/* 1062/*
1063 * If we are changing DAX flags, we have to ensure the file is clean and any
1064 * cached objects in the address space are invalidated and removed. This
1065 * requires us to lock out other IO and page faults similar to a truncate
1066 * operation. The locks need to be held until the transaction has been committed
1067 * so that the cache invalidation is atomic with respect to the DAX flag
1068 * manipulation.
1069 */
1070static int
1071xfs_ioctl_setattr_dax_invalidate(
1072 struct xfs_inode *ip,
1073 struct fsxattr *fa,
1074 int *join_flags)
1075{
1076 struct inode *inode = VFS_I(ip);
1077 int error;
1078
1079 *join_flags = 0;
1080
1081 /*
1082 * It is only valid to set the DAX flag on regular files and
1083 * directories on filesystems where the block size is equal to the page
1084 * size. On directories it serves as an inherit hint.
1085 */
1086 if (fa->fsx_xflags & FS_XFLAG_DAX) {
1087 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)))
1088 return -EINVAL;
1089 if (ip->i_mount->m_sb.sb_blocksize != PAGE_SIZE)
1090 return -EINVAL;
1091 }
1092
1093 /* If the DAX state is not changing, we have nothing to do here. */
1094 if ((fa->fsx_xflags & FS_XFLAG_DAX) && IS_DAX(inode))
1095 return 0;
1096 if (!(fa->fsx_xflags & FS_XFLAG_DAX) && !IS_DAX(inode))
1097 return 0;
1098
1099 /* lock, flush and invalidate mapping in preparation for flag change */
1100 xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
1101 error = filemap_write_and_wait(inode->i_mapping);
1102 if (error)
1103 goto out_unlock;
1104 error = invalidate_inode_pages2(inode->i_mapping);
1105 if (error)
1106 goto out_unlock;
1107
1108 *join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL;
1109 return 0;
1110
1111out_unlock:
1112 xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL);
1113 return error;
1114
1115}
1116
1117/*
1063 * Set up the transaction structure for the setattr operation, checking that we 1118 * Set up the transaction structure for the setattr operation, checking that we
1064 * have permission to do so. On success, return a clean transaction and the 1119 * have permission to do so. On success, return a clean transaction and the
1065 * inode locked exclusively ready for further operation specific checks. On 1120 * inode locked exclusively ready for further operation specific checks. On
1066 * failure, return an error without modifying or locking the inode. 1121 * failure, return an error without modifying or locking the inode.
1122 *
1123 * The inode might already be IO locked on call. If this is the case, it is
1124 * indicated in @join_flags and we take full responsibility for ensuring they
1125 * are unlocked from now on. Hence if we have an error here, we still have to
1126 * unlock them. Otherwise, once they are joined to the transaction, they will
1127 * be unlocked on commit/cancel.
1067 */ 1128 */
1068static struct xfs_trans * 1129static struct xfs_trans *
1069xfs_ioctl_setattr_get_trans( 1130xfs_ioctl_setattr_get_trans(
1070 struct xfs_inode *ip) 1131 struct xfs_inode *ip,
1132 int join_flags)
1071{ 1133{
1072 struct xfs_mount *mp = ip->i_mount; 1134 struct xfs_mount *mp = ip->i_mount;
1073 struct xfs_trans *tp; 1135 struct xfs_trans *tp;
1074 int error; 1136 int error = -EROFS;
1075 1137
1076 if (mp->m_flags & XFS_MOUNT_RDONLY) 1138 if (mp->m_flags & XFS_MOUNT_RDONLY)
1077 return ERR_PTR(-EROFS); 1139 goto out_unlock;
1140 error = -EIO;
1078 if (XFS_FORCED_SHUTDOWN(mp)) 1141 if (XFS_FORCED_SHUTDOWN(mp))
1079 return ERR_PTR(-EIO); 1142 goto out_unlock;
1080 1143
1081 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); 1144 tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE);
1082 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0); 1145 error = xfs_trans_reserve(tp, &M_RES(mp)->tr_ichange, 0, 0);
@@ -1084,7 +1147,8 @@ xfs_ioctl_setattr_get_trans(
1084 goto out_cancel; 1147 goto out_cancel;
1085 1148
1086 xfs_ilock(ip, XFS_ILOCK_EXCL); 1149 xfs_ilock(ip, XFS_ILOCK_EXCL);
1087 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL); 1150 xfs_trans_ijoin(tp, ip, XFS_ILOCK_EXCL | join_flags);
1151 join_flags = 0;
1088 1152
1089 /* 1153 /*
1090 * CAP_FOWNER overrides the following restrictions: 1154 * CAP_FOWNER overrides the following restrictions:
@@ -1104,6 +1168,9 @@ xfs_ioctl_setattr_get_trans(
1104 1168
1105out_cancel: 1169out_cancel:
1106 xfs_trans_cancel(tp); 1170 xfs_trans_cancel(tp);
1171out_unlock:
1172 if (join_flags)
1173 xfs_iunlock(ip, join_flags);
1107 return ERR_PTR(error); 1174 return ERR_PTR(error);
1108} 1175}
1109 1176
@@ -1128,14 +1195,14 @@ xfs_ioctl_setattr_check_extsize(
1128{ 1195{
1129 struct xfs_mount *mp = ip->i_mount; 1196 struct xfs_mount *mp = ip->i_mount;
1130 1197
1131 if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(ip->i_d.di_mode)) 1198 if ((fa->fsx_xflags & FS_XFLAG_EXTSIZE) && !S_ISREG(VFS_I(ip)->i_mode))
1132 return -EINVAL; 1199 return -EINVAL;
1133 1200
1134 if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) && 1201 if ((fa->fsx_xflags & FS_XFLAG_EXTSZINHERIT) &&
1135 !S_ISDIR(ip->i_d.di_mode)) 1202 !S_ISDIR(VFS_I(ip)->i_mode))
1136 return -EINVAL; 1203 return -EINVAL;
1137 1204
1138 if (S_ISREG(ip->i_d.di_mode) && ip->i_d.di_nextents && 1205 if (S_ISREG(VFS_I(ip)->i_mode) && ip->i_d.di_nextents &&
1139 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize)) 1206 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
1140 return -EINVAL; 1207 return -EINVAL;
1141 1208
@@ -1202,6 +1269,7 @@ xfs_ioctl_setattr(
1202 struct xfs_dquot *pdqp = NULL; 1269 struct xfs_dquot *pdqp = NULL;
1203 struct xfs_dquot *olddquot = NULL; 1270 struct xfs_dquot *olddquot = NULL;
1204 int code; 1271 int code;
1272 int join_flags = 0;
1205 1273
1206 trace_xfs_ioctl_setattr(ip); 1274 trace_xfs_ioctl_setattr(ip);
1207 1275
@@ -1225,7 +1293,18 @@ xfs_ioctl_setattr(
1225 return code; 1293 return code;
1226 } 1294 }
1227 1295
1228 tp = xfs_ioctl_setattr_get_trans(ip); 1296 /*
1297 * Changing DAX config may require inode locking for mapping
1298 * invalidation. These need to be held all the way to transaction commit
1299 * or cancel time, so need to be passed through to
1300 * xfs_ioctl_setattr_get_trans() so it can apply them to the join call
1301 * appropriately.
1302 */
1303 code = xfs_ioctl_setattr_dax_invalidate(ip, fa, &join_flags);
1304 if (code)
1305 goto error_free_dquots;
1306
1307 tp = xfs_ioctl_setattr_get_trans(ip, join_flags);
1229 if (IS_ERR(tp)) { 1308 if (IS_ERR(tp)) {
1230 code = PTR_ERR(tp); 1309 code = PTR_ERR(tp);
1231 goto error_free_dquots; 1310 goto error_free_dquots;
@@ -1256,9 +1335,9 @@ xfs_ioctl_setattr(
1256 * successful return from chown() 1335 * successful return from chown()
1257 */ 1336 */
1258 1337
1259 if ((ip->i_d.di_mode & (S_ISUID|S_ISGID)) && 1338 if ((VFS_I(ip)->i_mode & (S_ISUID|S_ISGID)) &&
1260 !capable_wrt_inode_uidgid(VFS_I(ip), CAP_FSETID)) 1339 !capable_wrt_inode_uidgid(VFS_I(ip), CAP_FSETID))
1261 ip->i_d.di_mode &= ~(S_ISUID|S_ISGID); 1340 VFS_I(ip)->i_mode &= ~(S_ISUID|S_ISGID);
1262 1341
1263 /* Change the ownerships and register project quota modifications */ 1342 /* Change the ownerships and register project quota modifications */
1264 if (xfs_get_projid(ip) != fa->fsx_projid) { 1343 if (xfs_get_projid(ip) != fa->fsx_projid) {
@@ -1341,6 +1420,7 @@ xfs_ioc_setxflags(
1341 struct xfs_trans *tp; 1420 struct xfs_trans *tp;
1342 struct fsxattr fa; 1421 struct fsxattr fa;
1343 unsigned int flags; 1422 unsigned int flags;
1423 int join_flags = 0;
1344 int error; 1424 int error;
1345 1425
1346 if (copy_from_user(&flags, arg, sizeof(flags))) 1426 if (copy_from_user(&flags, arg, sizeof(flags)))
@@ -1357,7 +1437,18 @@ xfs_ioc_setxflags(
1357 if (error) 1437 if (error)
1358 return error; 1438 return error;
1359 1439
1360 tp = xfs_ioctl_setattr_get_trans(ip); 1440 /*
1441 * Changing DAX config may require inode locking for mapping
1442 * invalidation. These need to be held all the way to transaction commit
1443 * or cancel time, so need to be passed through to
1444 * xfs_ioctl_setattr_get_trans() so it can apply them to the join call
1445 * appropriately.
1446 */
1447 error = xfs_ioctl_setattr_dax_invalidate(ip, &fa, &join_flags);
1448 if (error)
1449 goto out_drop_write;
1450
1451 tp = xfs_ioctl_setattr_get_trans(ip, join_flags);
1361 if (IS_ERR(tp)) { 1452 if (IS_ERR(tp)) {
1362 error = PTR_ERR(tp); 1453 error = PTR_ERR(tp);
1363 goto out_drop_write; 1454 goto out_drop_write;