aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2017-01-28 02:22:55 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-04-08 03:30:30 -0400
commit798b1dc5cbdfbbb3ac0d45177a1fc1dd511e3469 (patch)
tree920b437caca55d7e992381e5a83f94cd00418276 /fs
parent08a2a26816825b2724fa6e2616df716b31e4a582 (diff)
xfs: pull up iolock from xfs_free_eofblocks()
commit a36b926180cda375ac2ec89e1748b47137cfc51c upstream. xfs_free_eofblocks() requires the IOLOCK_EXCL lock, but is called from different contexts where the lock may or may not be held. The need_iolock parameter exists for this reason, to indicate whether xfs_free_eofblocks() must acquire the iolock itself before it can proceed. This is ugly and confusing. Simplify the semantics of xfs_free_eofblocks() to require the caller to acquire the iolock appropriately and kill the need_iolock parameter. While here, the mp param can be removed as well as the xfs_mount is accessible from the xfs_inode structure. This patch does not change behavior. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Darrick J. Wong <darrick.wong@oracle.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs')
-rw-r--r--fs/xfs/xfs_bmap_util.c41
-rw-r--r--fs/xfs/xfs_bmap_util.h3
-rw-r--r--fs/xfs/xfs_icache.c24
-rw-r--r--fs/xfs/xfs_inode.c51
4 files changed, 60 insertions, 59 deletions
diff --git a/fs/xfs/xfs_bmap_util.c b/fs/xfs/xfs_bmap_util.c
index efb8ccd6bbf2..d8ac76ca05a2 100644
--- a/fs/xfs/xfs_bmap_util.c
+++ b/fs/xfs/xfs_bmap_util.c
@@ -917,17 +917,18 @@ xfs_can_free_eofblocks(struct xfs_inode *ip, bool force)
917 */ 917 */
918int 918int
919xfs_free_eofblocks( 919xfs_free_eofblocks(
920 xfs_mount_t *mp, 920 struct xfs_inode *ip)
921 xfs_inode_t *ip,
922 bool need_iolock)
923{ 921{
924 xfs_trans_t *tp; 922 struct xfs_trans *tp;
925 int error; 923 int error;
926 xfs_fileoff_t end_fsb; 924 xfs_fileoff_t end_fsb;
927 xfs_fileoff_t last_fsb; 925 xfs_fileoff_t last_fsb;
928 xfs_filblks_t map_len; 926 xfs_filblks_t map_len;
929 int nimaps; 927 int nimaps;
930 xfs_bmbt_irec_t imap; 928 struct xfs_bmbt_irec imap;
929 struct xfs_mount *mp = ip->i_mount;
930
931 ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL));
931 932
932 /* 933 /*
933 * Figure out if there are any blocks beyond the end 934 * Figure out if there are any blocks beyond the end
@@ -944,6 +945,10 @@ xfs_free_eofblocks(
944 error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0); 945 error = xfs_bmapi_read(ip, end_fsb, map_len, &imap, &nimaps, 0);
945 xfs_iunlock(ip, XFS_ILOCK_SHARED); 946 xfs_iunlock(ip, XFS_ILOCK_SHARED);
946 947
948 /*
949 * If there are blocks after the end of file, truncate the file to its
950 * current size to free them up.
951 */
947 if (!error && (nimaps != 0) && 952 if (!error && (nimaps != 0) &&
948 (imap.br_startblock != HOLESTARTBLOCK || 953 (imap.br_startblock != HOLESTARTBLOCK ||
949 ip->i_delayed_blks)) { 954 ip->i_delayed_blks)) {
@@ -954,22 +959,10 @@ xfs_free_eofblocks(
954 if (error) 959 if (error)
955 return error; 960 return error;
956 961
957 /*
958 * There are blocks after the end of file.
959 * Free them up now by truncating the file to
960 * its current size.
961 */
962 if (need_iolock) {
963 if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL))
964 return -EAGAIN;
965 }
966
967 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0, 962 error = xfs_trans_alloc(mp, &M_RES(mp)->tr_itruncate, 0, 0, 0,
968 &tp); 963 &tp);
969 if (error) { 964 if (error) {
970 ASSERT(XFS_FORCED_SHUTDOWN(mp)); 965 ASSERT(XFS_FORCED_SHUTDOWN(mp));
971 if (need_iolock)
972 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
973 return error; 966 return error;
974 } 967 }
975 968
@@ -997,8 +990,6 @@ xfs_free_eofblocks(
997 } 990 }
998 991
999 xfs_iunlock(ip, XFS_ILOCK_EXCL); 992 xfs_iunlock(ip, XFS_ILOCK_EXCL);
1000 if (need_iolock)
1001 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1002 } 993 }
1003 return error; 994 return error;
1004} 995}
@@ -1415,7 +1406,7 @@ xfs_shift_file_space(
1415 * into the accessible region of the file. 1406 * into the accessible region of the file.
1416 */ 1407 */
1417 if (xfs_can_free_eofblocks(ip, true)) { 1408 if (xfs_can_free_eofblocks(ip, true)) {
1418 error = xfs_free_eofblocks(mp, ip, false); 1409 error = xfs_free_eofblocks(ip);
1419 if (error) 1410 if (error)
1420 return error; 1411 return error;
1421 } 1412 }
diff --git a/fs/xfs/xfs_bmap_util.h b/fs/xfs/xfs_bmap_util.h
index 68a621a8e0c0..f1005393785c 100644
--- a/fs/xfs/xfs_bmap_util.h
+++ b/fs/xfs/xfs_bmap_util.h
@@ -63,8 +63,7 @@ int xfs_insert_file_space(struct xfs_inode *, xfs_off_t offset,
63 63
64/* EOF block manipulation functions */ 64/* EOF block manipulation functions */
65bool xfs_can_free_eofblocks(struct xfs_inode *ip, bool force); 65bool xfs_can_free_eofblocks(struct xfs_inode *ip, bool force);
66int xfs_free_eofblocks(struct xfs_mount *mp, struct xfs_inode *ip, 66int xfs_free_eofblocks(struct xfs_inode *ip);
67 bool need_iolock);
68 67
69int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip, 68int xfs_swap_extents(struct xfs_inode *ip, struct xfs_inode *tip,
70 struct xfs_swapext *sx); 69 struct xfs_swapext *sx);
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c
index 29cc9886a3cb..e4b382aabf9f 100644
--- a/fs/xfs/xfs_icache.c
+++ b/fs/xfs/xfs_icache.c
@@ -1324,7 +1324,7 @@ xfs_inode_free_eofblocks(
1324 int flags, 1324 int flags,
1325 void *args) 1325 void *args)
1326{ 1326{
1327 int ret; 1327 int ret = 0;
1328 struct xfs_eofblocks *eofb = args; 1328 struct xfs_eofblocks *eofb = args;
1329 bool need_iolock = true; 1329 bool need_iolock = true;
1330 int match; 1330 int match;
@@ -1360,19 +1360,25 @@ xfs_inode_free_eofblocks(
1360 return 0; 1360 return 0;
1361 1361
1362 /* 1362 /*
1363 * A scan owner implies we already hold the iolock. Skip it in 1363 * A scan owner implies we already hold the iolock. Skip it here
1364 * xfs_free_eofblocks() to avoid deadlock. This also eliminates 1364 * to avoid deadlock.
1365 * the possibility of EAGAIN being returned.
1366 */ 1365 */
1367 if (eofb->eof_scan_owner == ip->i_ino) 1366 if (eofb->eof_scan_owner == ip->i_ino)
1368 need_iolock = false; 1367 need_iolock = false;
1369 } 1368 }
1370 1369
1371 ret = xfs_free_eofblocks(ip->i_mount, ip, need_iolock); 1370 /*
1372 1371 * If the caller is waiting, return -EAGAIN to keep the background
1373 /* don't revisit the inode if we're not waiting */ 1372 * scanner moving and revisit the inode in a subsequent pass.
1374 if (ret == -EAGAIN && !(flags & SYNC_WAIT)) 1373 */
1375 ret = 0; 1374 if (need_iolock && !xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
1375 if (flags & SYNC_WAIT)
1376 ret = -EAGAIN;
1377 return ret;
1378 }
1379 ret = xfs_free_eofblocks(ip);
1380 if (need_iolock)
1381 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1376 1382
1377 return ret; 1383 return ret;
1378} 1384}
diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c
index a1c7e138dbca..f9f44cb56fe8 100644
--- a/fs/xfs/xfs_inode.c
+++ b/fs/xfs/xfs_inode.c
@@ -1701,32 +1701,34 @@ xfs_release(
1701 if (xfs_can_free_eofblocks(ip, false)) { 1701 if (xfs_can_free_eofblocks(ip, false)) {
1702 1702
1703 /* 1703 /*
1704 * Check if the inode is being opened, written and closed
1705 * frequently and we have delayed allocation blocks outstanding
1706 * (e.g. streaming writes from the NFS server), truncating the
1707 * blocks past EOF will cause fragmentation to occur.
1708 *
1709 * In this case don't do the truncation, but we have to be
1710 * careful how we detect this case. Blocks beyond EOF show up as
1711 * i_delayed_blks even when the inode is clean, so we need to
1712 * truncate them away first before checking for a dirty release.
1713 * Hence on the first dirty close we will still remove the
1714 * speculative allocation, but after that we will leave it in
1715 * place.
1716 */
1717 if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE))
1718 return 0;
1719 /*
1704 * If we can't get the iolock just skip truncating the blocks 1720 * If we can't get the iolock just skip truncating the blocks
1705 * past EOF because we could deadlock with the mmap_sem 1721 * past EOF because we could deadlock with the mmap_sem
1706 * otherwise. We'll get another chance to drop them once the 1722 * otherwise. We'll get another chance to drop them once the
1707 * last reference to the inode is dropped, so we'll never leak 1723 * last reference to the inode is dropped, so we'll never leak
1708 * blocks permanently. 1724 * blocks permanently.
1709 *
1710 * Further, check if the inode is being opened, written and
1711 * closed frequently and we have delayed allocation blocks
1712 * outstanding (e.g. streaming writes from the NFS server),
1713 * truncating the blocks past EOF will cause fragmentation to
1714 * occur.
1715 *
1716 * In this case don't do the truncation, either, but we have to
1717 * be careful how we detect this case. Blocks beyond EOF show
1718 * up as i_delayed_blks even when the inode is clean, so we
1719 * need to truncate them away first before checking for a dirty
1720 * release. Hence on the first dirty close we will still remove
1721 * the speculative allocation, but after that we will leave it
1722 * in place.
1723 */ 1725 */
1724 if (xfs_iflags_test(ip, XFS_IDIRTY_RELEASE)) 1726 if (xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) {
1725 return 0; 1727 error = xfs_free_eofblocks(ip);
1726 1728 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1727 error = xfs_free_eofblocks(mp, ip, true); 1729 if (error)
1728 if (error && error != -EAGAIN) 1730 return error;
1729 return error; 1731 }
1730 1732
1731 /* delalloc blocks after truncation means it really is dirty */ 1733 /* delalloc blocks after truncation means it really is dirty */
1732 if (ip->i_delayed_blks) 1734 if (ip->i_delayed_blks)
@@ -1913,8 +1915,11 @@ xfs_inactive(
1913 * cache. Post-eof blocks must be freed, lest we end up with 1915 * cache. Post-eof blocks must be freed, lest we end up with
1914 * broken free space accounting. 1916 * broken free space accounting.
1915 */ 1917 */
1916 if (xfs_can_free_eofblocks(ip, true)) 1918 if (xfs_can_free_eofblocks(ip, true)) {
1917 xfs_free_eofblocks(mp, ip, false); 1919 xfs_ilock(ip, XFS_IOLOCK_EXCL);
1920 xfs_free_eofblocks(ip);
1921 xfs_iunlock(ip, XFS_IOLOCK_EXCL);
1922 }
1918 1923
1919 return; 1924 return;
1920 } 1925 }