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 by only checking for allocated extents for regular
files; it leaves undefined what it means to set an extent size on a
non-regular, non-directory inode. Additionally, when setting a non-zero
extent size, the appropriate flags (EXTSIZE, respectively EXTSZINHERIT)
are enforced for regular files and directories.
Signed-off-by: Iustin Pop <iusty@xxxxxxxxx>
---
A patch against xfstests to test for the fixed behaviour will follow
shortly.
fs/xfs/xfs_ioctl.c | 34 ++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 8bc1bbc..5b9acd2 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -1116,14 +1116,32 @@ xfs_ioctl_setattr(
}
if (mask & FSX_EXTSIZE) {
- /*
- * Can't change extent size if any extents are allocated.
- */
- if (ip->i_d.di_nextents &&
- ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
- fa->fsx_extsize)) {
- code = XFS_ERROR(EINVAL); /* EFBIG? */
- goto error_return;
+ if (S_ISDIR(ip->i_d.di_mode)) {
+ /*
+ * Enforce setting the EXTSZINHERIT flag when
+ * a non-zero extent size has been specified.
+ */
+ if (fa->fsx_extsize) {
+ fa->fsx_xflags |= XFS_XFLAG_EXTSZINHERIT;
+ }
+ } else if (S_ISREG(ip->i_d.di_mode)) {
+ /*
+ * For a regular file, we can't change extent
+ * size if any extents are allocated.
+ */
+ if (ip->i_d.di_nextents &&
+ ((ip->i_d.di_extsize << mp->m_sb.sb_blocklog) !=
+ fa->fsx_extsize)) {
+ code = XFS_ERROR(EINVAL); /* EFBIG? */
+ goto error_return;
+ }
+ /*
+ * Enforce setting the EXTSIZE flag when
+ * a non-zero extent size has been specified.
+ */
+ if (fa->fsx_extsize) {
+ fa->fsx_xflags |= XFS_XFLAG_EXTSIZE;
+ }
}
/*
--
2.1.0
|