diff options
author | Alex Elder <aelder@sgi.com> | 2011-01-10 22:35:55 -0500 |
---|---|---|
committer | Alex Elder <aelder@sgi.com> | 2011-01-10 22:35:55 -0500 |
commit | 92f1c008ae79e32b83c0607d184b194f302bb3ee (patch) | |
tree | 070980c581ca39a050a1b86a50fe4c52437cdba1 /fs/xfs/xfs_vnodeops.c | |
parent | e54be894eae10eca9892e965cc9532f5d5a11767 (diff) | |
parent | d0eb2f38b250b7d6c993adf81b0e4ded0565497e (diff) |
Merge branch 'master' into for-linus-merged
This merge pulls the XFS master branch into the latest Linus master.
This results in a merge conflict whose best fix is not obvious.
I manually fixed the conflict, in "fs/xfs/xfs_iget.c".
Dave Chinner had done work that resulted in RCU freeing of inodes
separate from what Nick Piggin had done, and their results differed
slightly in xfs_inode_free(). The fix updates Nick's call_rcu()
with the use of VFS_I(), while incorporating needed updates to some
XFS inode fields implemented in Dave's series. Dave's RCU callback
function has also been removed.
Signed-off-by: Alex Elder <aelder@sgi.com>
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r-- | fs/xfs/xfs_vnodeops.c | 61 |
1 files changed, 40 insertions, 21 deletions
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 | ||