Skip to content

Commit 5d3ca62

Browse files
Christoph HellwigChandan Babu R
authored andcommitted
xfs: refactor f_op->release handling
Currently f_op->release is split in not very obvious ways. Fix that by folding xfs_release into xfs_file_release. Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <djwong@kernel.org> Signed-off-by: Chandan Babu R <chandanbabu@kernel.org>
1 parent 6e13dbe commit 5d3ca62

3 files changed

Lines changed: 68 additions & 83 deletions

File tree

fs/xfs/xfs_file.c

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,10 +1177,75 @@ xfs_dir_open(
11771177

11781178
STATIC int
11791179
xfs_file_release(
1180-
struct inode *inode,
1181-
struct file *filp)
1180+
struct inode *inode,
1181+
struct file *file)
11821182
{
1183-
return xfs_release(XFS_I(inode));
1183+
struct xfs_inode *ip = XFS_I(inode);
1184+
struct xfs_mount *mp = ip->i_mount;
1185+
int error;
1186+
1187+
/* If this is a read-only mount, don't generate I/O */
1188+
if (xfs_is_readonly(mp))
1189+
return 0;
1190+
1191+
/*
1192+
* If we previously truncated this file and removed old data in the
1193+
* process, we want to initiate "early" writeout on the last close.
1194+
* This is an attempt to combat the notorious NULL files problem which
1195+
* is particularly noticeable from a truncate down, buffered (re-)write
1196+
* (delalloc), followed by a crash. What we are effectively doing here
1197+
* is significantly reducing the time window where we'd otherwise be
1198+
* exposed to that problem.
1199+
*/
1200+
if (!xfs_is_shutdown(mp) &&
1201+
xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED)) {
1202+
xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
1203+
if (ip->i_delayed_blks > 0) {
1204+
error = filemap_flush(inode->i_mapping);
1205+
if (error)
1206+
return error;
1207+
}
1208+
}
1209+
1210+
/*
1211+
* XFS aggressively preallocates post-EOF space to generate contiguous
1212+
* allocations for writers that append to the end of the file and we
1213+
* try to free these when an open file context is released.
1214+
*
1215+
* There is no point in freeing blocks here for open but unlinked files
1216+
* as they will be taken care of by the inactivation path soon.
1217+
*
1218+
* If we can't get the iolock just skip truncating the blocks past EOF
1219+
* because we could deadlock with the mmap_lock otherwise. We'll get
1220+
* another chance to drop them once the last reference to the inode is
1221+
* dropped, so we'll never leak blocks permanently.
1222+
*/
1223+
if (inode->i_nlink && xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
1224+
if (xfs_can_free_eofblocks(ip) &&
1225+
!xfs_iflags_test(ip, XFS_IDIRTY_RELEASE)) {
1226+
/*
1227+
* Check if the inode is being opened, written and
1228+
* closed frequently and we have delayed allocation
1229+
* blocks outstanding (e.g. streaming writes from the
1230+
* NFS server), truncating the blocks past EOF will
1231+
* cause fragmentation to occur.
1232+
*
1233+
* In this case don't do the truncation, but we have to
1234+
* be careful how we detect this case. Blocks beyond EOF
1235+
* show up as i_delayed_blks even when the inode is
1236+
* clean, so we need to truncate them away first before
1237+
* checking for a dirty release. Hence on the first
1238+
* dirty close we will still remove the speculative
1239+
* allocation, but after that we will leave it in place.
1240+
*/
1241+
error = xfs_free_eofblocks(ip);
1242+
if (!error && ip->i_delayed_blks)
1243+
xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
1244+
}
1245+
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1246+
}
1247+
1248+
return error;
11841249
}
11851250

11861251
STATIC int

fs/xfs/xfs_inode.c

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,85 +1079,6 @@ xfs_itruncate_extents_flags(
10791079
return error;
10801080
}
10811081

1082-
int
1083-
xfs_release(
1084-
xfs_inode_t *ip)
1085-
{
1086-
xfs_mount_t *mp = ip->i_mount;
1087-
int error = 0;
1088-
1089-
/* If this is a read-only mount, don't do this (would generate I/O) */
1090-
if (xfs_is_readonly(mp))
1091-
return 0;
1092-
1093-
if (!xfs_is_shutdown(mp)) {
1094-
int truncated;
1095-
1096-
/*
1097-
* If we previously truncated this file and removed old data
1098-
* in the process, we want to initiate "early" writeout on
1099-
* the last close. This is an attempt to combat the notorious
1100-
* NULL files problem which is particularly noticeable from a
1101-
* truncate down, buffered (re-)write (delalloc), followed by
1102-
* a crash. What we are effectively doing here is
1103-
* significantly reducing the time window where we'd otherwise
1104-
* be exposed to that problem.
1105-
*/
1106-
truncated = xfs_iflags_test_and_clear(ip, XFS_ITRUNCATED);
1107-
if (truncated) {
1108-
xfs_iflags_clear(ip, XFS_IDIRTY_RELEASE);
1109-
if (ip->i_delayed_blks > 0) {
1110-
error = filemap_flush(VFS_I(ip)->i_mapping);
1111-
if (error)
1112-
return error;
1113-
}
1114-
}
1115-
}
1116-
1117-
if (VFS_I(ip)->i_nlink == 0)
1118-
return 0;
1119-
1120-
/*
1121-
* If we can't get the iolock just skip truncating the blocks past EOF
1122-
* because we could deadlock with the mmap_lock otherwise. We'll get
1123-
* another chance to drop them once the last reference to the inode is
1124-
* dropped, so we'll never leak blocks permanently.
1125-
*/
1126-
if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
1127-
return 0;
1128-
1129-
if (xfs_can_free_eofblocks(ip)) {
1130-
/*
1131-
* Check if the inode is being opened, written and closed
1132-
* frequently and we have delayed allocation blocks outstanding
1133-
* (e.g. streaming writes from the NFS server), truncating the
1134-
* blocks past EOF will cause fragmentation to occur.
1135-
*
1136-
* In this case don't do the truncation, but we have to be
1137-
* careful how we detect this case. Blocks beyond EOF show up as
1138-
* i_delayed_blks even when the inode is clean, so we need to
1139-
* truncate them away first before checking for a dirty release.
1140-
* Hence on the first dirty close we will still remove the
1141-
* speculative allocation, but after that we will leave it in
1142-
* place.
1143-
*/
1144-
if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
1145-
goto out_unlock;
1146-
1147-
error = xfs_free_eofblocks(ip);
1148-
if (error)
1149-
goto out_unlock;
1150-
1151-
/* delalloc blocks after truncation means it really is dirty */
1152-
if (ip->i_delayed_blks)
1153-
xfs_iflags_set(ip, XFS_IDIRTY_RELEASE);
1154-
}
1155-
1156-
out_unlock:
1157-
xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1158-
return error;
1159-
}
1160-
11611082
/*
11621083
* Mark all the buffers attached to this directory stale. In theory we should
11631084
* never be freeing a directory with any blocks at all, but this covers the

fs/xfs/xfs_inode.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,6 @@ enum layout_break_reason {
513513
#define XFS_INHERIT_GID(pip) \
514514
(xfs_has_grpid((pip)->i_mount) || (VFS_I(pip)->i_mode & S_ISGID))
515515

516-
int xfs_release(struct xfs_inode *ip);
517516
int xfs_inactive(struct xfs_inode *ip);
518517
int xfs_lookup(struct xfs_inode *dp, const struct xfs_name *name,
519518
struct xfs_inode **ipp, struct xfs_name *ci_name);

0 commit comments

Comments
 (0)