|
@@ -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,
|