@@ -1019,12 +1019,23 @@ xfs_dir_open(
return error;
}
+/*
+ * When we release the file, we don't want it to trim EOF blocks for synchronous
+ * write contexts as this leads to severe fragmentation when applications do
+ * repeated open/appending sync write/close to a file amongst other file IO.
+ */
STATIC int
xfs_file_release(
struct inode *inode,
- struct file *filp)
+ struct file *file)
{
- return xfs_release(XFS_I(inode));
+ bool free_eof_blocks = true;
+
+ if ((file->f_mode & FMODE_WRITE) &&
+ (file->f_flags & O_DSYNC))
+ free_eof_blocks = false;
+
+ return xfs_release(XFS_I(inode), free_eof_blocks);
}
STATIC int
@@ -1603,10 +1603,11 @@ xfs_itruncate_extents_flags(
int
xfs_release(
- xfs_inode_t *ip)
+ struct xfs_inode *ip,
+ bool can_free_eofblocks)
{
- xfs_mount_t *mp = ip->i_mount;
- int error;
+ struct xfs_mount *mp = ip->i_mount;
+ int error;
if (!S_ISREG(VFS_I(ip)->i_mode) || (VFS_I(ip)->i_mode == 0))
return 0;
@@ -1642,7 +1643,7 @@ xfs_release(
if (VFS_I(ip)->i_nlink == 0)
return 0;
- if (xfs_can_free_eofblocks(ip, false)) {
+ if (can_free_eofblocks && xfs_can_free_eofblocks(ip, false)) {
/*
* Check if the inode is being opened, written and closed
@@ -397,7 +397,7 @@ enum layout_break_reason {
(((pip)->i_mount->m_flags & XFS_MOUNT_GRPID) || \
(VFS_I(pip)->i_mode & S_ISGID))
-int xfs_release(struct xfs_inode *ip);
+int xfs_release(struct xfs_inode *ip, bool can_free_eofblocks);
void xfs_inactive(struct xfs_inode *ip);
int xfs_lookup(struct xfs_inode *dp, struct xfs_name *name,
struct xfs_inode **ipp, struct xfs_name *ci_name);