aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
authorIustin Pop <iustin@k1024.org>2015-02-01 18:26:26 -0500
committerDave Chinner <david@fromorbit.com>2015-02-01 18:26:26 -0500
commit9b94fcc39822b450af823b3d8cbef6b53ce87ed9 (patch)
tree1b663a4ca38574d135b903c2242728234db23a49 /fs/xfs
parent23bd0735cfdf5322170a9ef48c7d47c2e6567ba8 (diff)
xfs: fix behaviour of XFS_IOC_FSSETXATTR on directories
Currently, the ioctl handling code for XFS_IOC_FSSETXATTR treats all targets as regular files: it refuses to change the extent size if extents are allocated. This is wrong for directories, as there the extent size is only used as a default for children. The patch fixes this issue and improves validation of flag combinations: - only disallow extent size changes after extents have been allocated for regular files - only allow XFS_XFLAG_EXTSIZE for regular files - only allow XFS_XFLAG_EXTSZINHERIT for directories - automatically clear the flags if the extent size is zero Thanks to Dave Chinner for guidance on the proper fix for this issue. [dchinner: ported changes onto cleanup series. Makes changes clear and obvious.] [dchinner: added comments documenting validity checking rules.] Signed-off-by: Iustin Pop <iustin@k1024.org> 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/xfs')
-rw-r--r--fs/xfs/xfs_ioctl.c39
1 files changed, 25 insertions, 14 deletions
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 1f186d2eec06..0f6b6abb7c7a 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1098,6 +1098,20 @@ out_cancel:
1098 return ERR_PTR(error); 1098 return ERR_PTR(error);
1099} 1099}
1100 1100
1101/*
1102 * extent size hint validation is somewhat cumbersome. Rules are:
1103 *
1104 * 1. extent size hint is only valid for directories and regular files
1105 * 2. XFS_XFLAG_EXTSIZE is only valid for regular files
1106 * 3. XFS_XFLAG_EXTSZINHERIT is only valid for directories.
1107 * 4. can only be changed on regular files if no extents are allocated
1108 * 5. can be changed on directories at any time
1109 * 6. extsize hint of 0 turns off hints, clears inode flags.
1110 * 7. Extent size must be a multiple of the appropriate block size.
1111 * 8. for non-realtime files, the extent size hint must be limited
1112 * to half the AG size to avoid alignment extending the extent beyond the
1113 * limits of the AG.
1114 */
1101int 1115int
1102xfs_ioctl_setattr_check_extsize( 1116xfs_ioctl_setattr_check_extsize(
1103 struct xfs_inode *ip, 1117 struct xfs_inode *ip,
@@ -1105,20 +1119,17 @@ xfs_ioctl_setattr_check_extsize(
1105{ 1119{
1106 struct xfs_mount *mp = ip->i_mount; 1120 struct xfs_mount *mp = ip->i_mount;
1107 1121
1108 /* Can't change extent size if any extents are allocated. */ 1122 if ((fa->fsx_xflags & XFS_XFLAG_EXTSIZE) && !S_ISREG(ip->i_d.di_mode))
1109 if (ip->i_d.di_nextents && 1123 return -EINVAL;
1124
1125 if ((fa->fsx_xflags & XFS_XFLAG_EXTSZINHERIT) &&
1126 !S_ISDIR(ip->i_d.di_mode))
1127 return -EINVAL;
1128
1129 if (S_ISREG(ip->i_d.di_mode) && ip->i_d.di_nextents &&
1110 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize)) 1130 ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
1111 return -EINVAL; 1131 return -EINVAL;
1112 1132
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) { 1133 if (fa->fsx_extsize != 0) {
1123 xfs_extlen_t size; 1134 xfs_extlen_t size;
1124 xfs_fsblock_t extsize_fsb; 1135 xfs_fsblock_t extsize_fsb;
@@ -1138,7 +1149,9 @@ xfs_ioctl_setattr_check_extsize(
1138 1149
1139 if (fa->fsx_extsize % size) 1150 if (fa->fsx_extsize % size)
1140 return -EINVAL; 1151 return -EINVAL;
1141 } 1152 } else
1153 fa->fsx_xflags &= ~(XFS_XFLAG_EXTSIZE | XFS_XFLAG_EXTSZINHERIT);
1154
1142 return 0; 1155 return 0;
1143} 1156}
1144 1157
@@ -1169,8 +1182,6 @@ xfs_ioctl_setattr_check_projid(
1169 return 0; 1182 return 0;
1170} 1183}
1171 1184
1172
1173
1174STATIC int 1185STATIC int
1175xfs_ioctl_setattr( 1186xfs_ioctl_setattr(
1176 xfs_inode_t *ip, 1187 xfs_inode_t *ip,