diff options
-rw-r--r-- | fs/xfs/xfs_inode.h | 13 | ||||
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 61 |
2 files changed, 47 insertions, 27 deletions
diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index 1c6514d73dc8..5c95fa8ec11d 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h | |||
@@ -376,12 +376,13 @@ static inline void xfs_ifunlock(xfs_inode_t *ip) | |||
376 | /* | 376 | /* |
377 | * In-core inode flags. | 377 | * In-core inode flags. |
378 | */ | 378 | */ |
379 | #define XFS_IRECLAIM 0x0001 /* we have started reclaiming this inode */ | 379 | #define XFS_IRECLAIM 0x0001 /* started reclaiming this inode */ |
380 | #define XFS_ISTALE 0x0002 /* inode has been staled */ | 380 | #define XFS_ISTALE 0x0002 /* inode has been staled */ |
381 | #define XFS_IRECLAIMABLE 0x0004 /* inode can be reclaimed */ | 381 | #define XFS_IRECLAIMABLE 0x0004 /* inode can be reclaimed */ |
382 | #define XFS_INEW 0x0008 /* inode has just been allocated */ | 382 | #define XFS_INEW 0x0008 /* inode has just been allocated */ |
383 | #define XFS_IFILESTREAM 0x0010 /* inode is in a filestream directory */ | 383 | #define XFS_IFILESTREAM 0x0010 /* inode is in a filestream directory */ |
384 | #define XFS_ITRUNCATED 0x0020 /* truncated down so flush-on-close */ | 384 | #define XFS_ITRUNCATED 0x0020 /* truncated down so flush-on-close */ |
385 | #define XFS_IDIRTY_RELEASE 0x0040 /* dirty release already seen */ | ||
385 | 386 | ||
386 | /* | 387 | /* |
387 | * Flags for inode locking. | 388 | * Flags for inode locking. |
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index 8e4a63c4151a..d8e6f8cd6f0c 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c | |||
@@ -964,29 +964,48 @@ xfs_release( | |||
964 | xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE); | 964 | xfs_flush_pages(ip, 0, -1, XBF_ASYNC, FI_NONE); |
965 | } | 965 | } |
966 | 966 | ||
967 | if (ip->i_d.di_nlink != 0) { | 967 | if (ip->i_d.di_nlink == 0) |
968 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && | 968 | return 0; |
969 | ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || | ||
970 | ip->i_delayed_blks > 0)) && | ||
971 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && | ||
972 | (!(ip->i_d.di_flags & | ||
973 | (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { | ||
974 | 969 | ||
975 | /* | 970 | if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && |
976 | * If we can't get the iolock just skip truncating | 971 | ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || |
977 | * the blocks past EOF because we could deadlock | 972 | ip->i_delayed_blks > 0)) && |
978 | * with the mmap_sem otherwise. We'll get another | 973 | (ip->i_df.if_flags & XFS_IFEXTENTS)) && |
979 | * chance to drop them once the last reference to | 974 | (!(ip->i_d.di_flags & (XFS_DIFLAG_PREALLOC | XFS_DIFLAG_APPEND)))) { |
980 | * the inode is dropped, so we'll never leak blocks | ||
981 | * permanently. | ||
982 | */ | ||
983 | error = xfs_free_eofblocks(mp, ip, | ||
984 | XFS_FREE_EOF_TRYLOCK); | ||
985 | if (error) | ||
986 | return error; | ||
987 | } | ||
988 | } | ||
989 | 975 | ||
976 | /* | ||
977 | * If we can't get the iolock just skip truncating the blocks | ||
978 | * past EOF because we could deadlock with the mmap_sem | ||
979 | * otherwise. We'll get another chance to drop them once the | ||
980 | * last reference to the inode is dropped, so we'll never leak | ||
981 | * blocks permanently. | ||
982 | * | ||
983 | * Further, check if the inode is being opened, written and | ||
984 | * closed frequently and we have delayed allocation blocks | ||
985 | * oustanding (e.g. streaming writes from the NFS server), | ||
986 | * truncating the blocks past EOF will cause fragmentation to | ||
987 | * occur. | ||
988 | * | ||
989 | * In this case don't do the truncation, either, but we have to | ||
990 | * be careful how we detect this case. Blocks beyond EOF show | ||
991 | * up as i_delayed_blks even when the inode is clean, so we | ||
992 | * need to truncate them away first before checking for a dirty | ||
993 | * release. Hence on the first dirty close we will still remove | ||
994 | * the speculative allocation, but after that we will leave it | ||
995 | * in place. | ||
996 | */ | ||
997 | if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE)) | ||
998 | return 0; | ||
999 | |||
1000 | error = xfs_free_eofblocks(mp, ip, | ||
1001 | XFS_FREE_EOF_TRYLOCK); | ||
1002 | if (error) | ||
1003 | return error; | ||
1004 | |||
1005 | /* delalloc blocks after truncation means it really is dirty */ | ||
1006 | if (ip->i_delayed_blks) | ||
1007 | xfs_iflags_set(ip, XFS_IDIRTY_RELEASE); | ||
1008 | } | ||
990 | return 0; | 1009 | return 0; |
991 | } | 1010 | } |
992 | 1011 | ||