summaryrefslogtreecommitdiffstats
path: root/fs/xfs
diff options
context:
space:
mode:
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:
return ERR_PTR(error);
}
+/*
+ * extent size hint validation is somewhat cumbersome. Rules are:
+ *
+ * 1. extent size hint is only valid for directories and regular files
+ * 2. XFS_XFLAG_EXTSIZE is only valid for regular files
+ * 3. XFS_XFLAG_EXTSZINHERIT is only valid for directories.
+ * 4. can only be changed on regular files if no extents are allocated
+ * 5. can be changed on directories at any time
+ * 6. extsize hint of 0 turns off hints, clears inode flags.
+ * 7. Extent size must be a multiple of the appropriate block size.
+ * 8. for non-realtime files, the extent size hint must be limited
+ * to half the AG size to avoid alignment extending the extent beyond the
+ * limits of the AG.
+ */
int
xfs_ioctl_setattr_check_extsize(
struct xfs_inode *ip,
@@ -1105,20 +1119,17 @@ xfs_ioctl_setattr_check_extsize(
{
struct xfs_mount *mp = ip->i_mount;
- /* Can't change extent size if any extents are allocated. */
- if (ip->i_d.di_nextents &&
+ if ((fa->fsx_xflags & XFS_XFLAG_EXTSIZE) && !S_ISREG(ip->i_d.di_mode))
+ return -EINVAL;
+
+ if ((fa->fsx_xflags & XFS_XFLAG_EXTSZINHERIT) &&
+ !S_ISDIR(ip->i_d.di_mode))
+ return -EINVAL;
+
+ if (S_ISREG(ip->i_d.di_mode) && ip->i_d.di_nextents &&
((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) != fa->fsx_extsize))
return -EINVAL;
- /*
- * Extent size must be a multiple of the appropriate block size, if set
- * at all. It must also be smaller than the maximum extent size
- * supported by the filesystem.
- *
- * Also, for non-realtime files, limit the extent size hint to half the
- * size of the AGs in the filesystem so alignment doesn't result in
- * extents larger than an AG.
- */
if (fa->fsx_extsize != 0) {
xfs_extlen_t size;
xfs_fsblock_t extsize_fsb;
@@ -1138,7 +1149,9 @@ xfs_ioctl_setattr_check_extsize(
if (fa->fsx_extsize % size)
return -EINVAL;
- }
+ } else
+ fa->fsx_xflags &= ~(XFS_XFLAG_EXTSIZE | XFS_XFLAG_EXTSZINHERIT);
+
return 0;
}
@@ -1169,8 +1182,6 @@ xfs_ioctl_setattr_check_projid(
return 0;
}
-
-
STATIC int
xfs_ioctl_setattr(
xfs_inode_t *ip,