diff options
-rw-r--r-- | fs/xfs/xfs_file.c | 13 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.c | 45 | ||||
-rw-r--r-- | fs/xfs/xfs_icache.h | 2 |
3 files changed, 16 insertions, 44 deletions
diff --git a/fs/xfs/xfs_file.c b/fs/xfs/xfs_file.c index 9a5d64b5f35a..81b7fee40b54 100644 --- a/fs/xfs/xfs_file.c +++ b/fs/xfs/xfs_file.c | |||
@@ -675,8 +675,10 @@ xfs_file_buffered_aio_write( | |||
675 | struct xfs_inode *ip = XFS_I(inode); | 675 | struct xfs_inode *ip = XFS_I(inode); |
676 | ssize_t ret; | 676 | ssize_t ret; |
677 | int enospc = 0; | 677 | int enospc = 0; |
678 | int iolock = XFS_IOLOCK_EXCL; | 678 | int iolock; |
679 | 679 | ||
680 | write_retry: | ||
681 | iolock = XFS_IOLOCK_EXCL; | ||
680 | xfs_rw_ilock(ip, iolock); | 682 | xfs_rw_ilock(ip, iolock); |
681 | 683 | ||
682 | ret = xfs_file_aio_write_checks(iocb, from, &iolock); | 684 | ret = xfs_file_aio_write_checks(iocb, from, &iolock); |
@@ -686,7 +688,6 @@ xfs_file_buffered_aio_write( | |||
686 | /* We can write back this queue in page reclaim */ | 688 | /* We can write back this queue in page reclaim */ |
687 | current->backing_dev_info = inode_to_bdi(inode); | 689 | current->backing_dev_info = inode_to_bdi(inode); |
688 | 690 | ||
689 | write_retry: | ||
690 | trace_xfs_file_buffered_write(ip, iov_iter_count(from), iocb->ki_pos); | 691 | trace_xfs_file_buffered_write(ip, iov_iter_count(from), iocb->ki_pos); |
691 | ret = iomap_file_buffered_write(iocb, from, &xfs_iomap_ops); | 692 | ret = iomap_file_buffered_write(iocb, from, &xfs_iomap_ops); |
692 | if (likely(ret >= 0)) | 693 | if (likely(ret >= 0)) |
@@ -702,18 +703,21 @@ write_retry: | |||
702 | * running at the same time. | 703 | * running at the same time. |
703 | */ | 704 | */ |
704 | if (ret == -EDQUOT && !enospc) { | 705 | if (ret == -EDQUOT && !enospc) { |
706 | xfs_rw_iunlock(ip, iolock); | ||
705 | enospc = xfs_inode_free_quota_eofblocks(ip); | 707 | enospc = xfs_inode_free_quota_eofblocks(ip); |
706 | if (enospc) | 708 | if (enospc) |
707 | goto write_retry; | 709 | goto write_retry; |
708 | enospc = xfs_inode_free_quota_cowblocks(ip); | 710 | enospc = xfs_inode_free_quota_cowblocks(ip); |
709 | if (enospc) | 711 | if (enospc) |
710 | goto write_retry; | 712 | goto write_retry; |
713 | iolock = 0; | ||
711 | } else if (ret == -ENOSPC && !enospc) { | 714 | } else if (ret == -ENOSPC && !enospc) { |
712 | struct xfs_eofblocks eofb = {0}; | 715 | struct xfs_eofblocks eofb = {0}; |
713 | 716 | ||
714 | enospc = 1; | 717 | enospc = 1; |
715 | xfs_flush_inodes(ip->i_mount); | 718 | xfs_flush_inodes(ip->i_mount); |
716 | eofb.eof_scan_owner = ip->i_ino; /* for locking */ | 719 | |
720 | xfs_rw_iunlock(ip, iolock); | ||
717 | eofb.eof_flags = XFS_EOF_FLAGS_SYNC; | 721 | eofb.eof_flags = XFS_EOF_FLAGS_SYNC; |
718 | xfs_icache_free_eofblocks(ip->i_mount, &eofb); | 722 | xfs_icache_free_eofblocks(ip->i_mount, &eofb); |
719 | goto write_retry; | 723 | goto write_retry; |
@@ -721,7 +725,8 @@ write_retry: | |||
721 | 725 | ||
722 | current->backing_dev_info = NULL; | 726 | current->backing_dev_info = NULL; |
723 | out: | 727 | out: |
724 | xfs_rw_iunlock(ip, iolock); | 728 | if (iolock) |
729 | xfs_rw_iunlock(ip, iolock); | ||
725 | return ret; | 730 | return ret; |
726 | } | 731 | } |
727 | 732 | ||
diff --git a/fs/xfs/xfs_icache.c b/fs/xfs/xfs_icache.c index e4b382aabf9f..78708d001a63 100644 --- a/fs/xfs/xfs_icache.c +++ b/fs/xfs/xfs_icache.c | |||
@@ -1326,11 +1326,8 @@ xfs_inode_free_eofblocks( | |||
1326 | { | 1326 | { |
1327 | int ret = 0; | 1327 | int ret = 0; |
1328 | struct xfs_eofblocks *eofb = args; | 1328 | struct xfs_eofblocks *eofb = args; |
1329 | bool need_iolock = true; | ||
1330 | int match; | 1329 | int match; |
1331 | 1330 | ||
1332 | ASSERT(!eofb || (eofb && eofb->eof_scan_owner != 0)); | ||
1333 | |||
1334 | if (!xfs_can_free_eofblocks(ip, false)) { | 1331 | if (!xfs_can_free_eofblocks(ip, false)) { |
1335 | /* inode could be preallocated or append-only */ | 1332 | /* inode could be preallocated or append-only */ |
1336 | trace_xfs_inode_free_eofblocks_invalid(ip); | 1333 | trace_xfs_inode_free_eofblocks_invalid(ip); |
@@ -1358,27 +1355,19 @@ xfs_inode_free_eofblocks( | |||
1358 | if (eofb->eof_flags & XFS_EOF_FLAGS_MINFILESIZE && | 1355 | if (eofb->eof_flags & XFS_EOF_FLAGS_MINFILESIZE && |
1359 | XFS_ISIZE(ip) < eofb->eof_min_file_size) | 1356 | XFS_ISIZE(ip) < eofb->eof_min_file_size) |
1360 | return 0; | 1357 | return 0; |
1361 | |||
1362 | /* | ||
1363 | * A scan owner implies we already hold the iolock. Skip it here | ||
1364 | * to avoid deadlock. | ||
1365 | */ | ||
1366 | if (eofb->eof_scan_owner == ip->i_ino) | ||
1367 | need_iolock = false; | ||
1368 | } | 1358 | } |
1369 | 1359 | ||
1370 | /* | 1360 | /* |
1371 | * If the caller is waiting, return -EAGAIN to keep the background | 1361 | * If the caller is waiting, return -EAGAIN to keep the background |
1372 | * scanner moving and revisit the inode in a subsequent pass. | 1362 | * scanner moving and revisit the inode in a subsequent pass. |
1373 | */ | 1363 | */ |
1374 | if (need_iolock && !xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { | 1364 | if (!xfs_ilock_nowait(ip, XFS_IOLOCK_EXCL)) { |
1375 | if (flags & SYNC_WAIT) | 1365 | if (flags & SYNC_WAIT) |
1376 | ret = -EAGAIN; | 1366 | ret = -EAGAIN; |
1377 | return ret; | 1367 | return ret; |
1378 | } | 1368 | } |
1379 | ret = xfs_free_eofblocks(ip); | 1369 | ret = xfs_free_eofblocks(ip); |
1380 | if (need_iolock) | 1370 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
1381 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
1382 | 1371 | ||
1383 | return ret; | 1372 | return ret; |
1384 | } | 1373 | } |
@@ -1425,15 +1414,10 @@ __xfs_inode_free_quota_eofblocks( | |||
1425 | struct xfs_eofblocks eofb = {0}; | 1414 | struct xfs_eofblocks eofb = {0}; |
1426 | struct xfs_dquot *dq; | 1415 | struct xfs_dquot *dq; |
1427 | 1416 | ||
1428 | ASSERT(xfs_isilocked(ip, XFS_IOLOCK_EXCL)); | ||
1429 | |||
1430 | /* | 1417 | /* |
1431 | * Set the scan owner to avoid a potential livelock. Otherwise, the scan | 1418 | * Run a sync scan to increase effectiveness and use the union filter to |
1432 | * can repeatedly trylock on the inode we're currently processing. We | ||
1433 | * run a sync scan to increase effectiveness and use the union filter to | ||
1434 | * cover all applicable quotas in a single scan. | 1419 | * cover all applicable quotas in a single scan. |
1435 | */ | 1420 | */ |
1436 | eofb.eof_scan_owner = ip->i_ino; | ||
1437 | eofb.eof_flags = XFS_EOF_FLAGS_UNION|XFS_EOF_FLAGS_SYNC; | 1421 | eofb.eof_flags = XFS_EOF_FLAGS_UNION|XFS_EOF_FLAGS_SYNC; |
1438 | 1422 | ||
1439 | if (XFS_IS_UQUOTA_ENFORCED(ip->i_mount)) { | 1423 | if (XFS_IS_UQUOTA_ENFORCED(ip->i_mount)) { |
@@ -1585,12 +1569,9 @@ xfs_inode_free_cowblocks( | |||
1585 | { | 1569 | { |
1586 | int ret; | 1570 | int ret; |
1587 | struct xfs_eofblocks *eofb = args; | 1571 | struct xfs_eofblocks *eofb = args; |
1588 | bool need_iolock = true; | ||
1589 | int match; | 1572 | int match; |
1590 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); | 1573 | struct xfs_ifork *ifp = XFS_IFORK_PTR(ip, XFS_COW_FORK); |
1591 | 1574 | ||
1592 | ASSERT(!eofb || (eofb && eofb->eof_scan_owner != 0)); | ||
1593 | |||
1594 | /* | 1575 | /* |
1595 | * Just clear the tag if we have an empty cow fork or none at all. It's | 1576 | * Just clear the tag if we have an empty cow fork or none at all. It's |
1596 | * possible the inode was fully unshared since it was originally tagged. | 1577 | * possible the inode was fully unshared since it was originally tagged. |
@@ -1623,28 +1604,16 @@ xfs_inode_free_cowblocks( | |||
1623 | if (eofb->eof_flags & XFS_EOF_FLAGS_MINFILESIZE && | 1604 | if (eofb->eof_flags & XFS_EOF_FLAGS_MINFILESIZE && |
1624 | XFS_ISIZE(ip) < eofb->eof_min_file_size) | 1605 | XFS_ISIZE(ip) < eofb->eof_min_file_size) |
1625 | return 0; | 1606 | return 0; |
1626 | |||
1627 | /* | ||
1628 | * A scan owner implies we already hold the iolock. Skip it in | ||
1629 | * xfs_free_eofblocks() to avoid deadlock. This also eliminates | ||
1630 | * the possibility of EAGAIN being returned. | ||
1631 | */ | ||
1632 | if (eofb->eof_scan_owner == ip->i_ino) | ||
1633 | need_iolock = false; | ||
1634 | } | 1607 | } |
1635 | 1608 | ||
1636 | /* Free the CoW blocks */ | 1609 | /* Free the CoW blocks */ |
1637 | if (need_iolock) { | 1610 | xfs_ilock(ip, XFS_IOLOCK_EXCL); |
1638 | xfs_ilock(ip, XFS_IOLOCK_EXCL); | 1611 | xfs_ilock(ip, XFS_MMAPLOCK_EXCL); |
1639 | xfs_ilock(ip, XFS_MMAPLOCK_EXCL); | ||
1640 | } | ||
1641 | 1612 | ||
1642 | ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF); | 1613 | ret = xfs_reflink_cancel_cow_range(ip, 0, NULLFILEOFF); |
1643 | 1614 | ||
1644 | if (need_iolock) { | 1615 | xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); |
1645 | xfs_iunlock(ip, XFS_MMAPLOCK_EXCL); | 1616 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
1646 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | ||
1647 | } | ||
1648 | 1617 | ||
1649 | return ret; | 1618 | return ret; |
1650 | } | 1619 | } |
diff --git a/fs/xfs/xfs_icache.h b/fs/xfs/xfs_icache.h index a1e02f4708ab..8a7c849b4dea 100644 --- a/fs/xfs/xfs_icache.h +++ b/fs/xfs/xfs_icache.h | |||
@@ -27,7 +27,6 @@ struct xfs_eofblocks { | |||
27 | kgid_t eof_gid; | 27 | kgid_t eof_gid; |
28 | prid_t eof_prid; | 28 | prid_t eof_prid; |
29 | __u64 eof_min_file_size; | 29 | __u64 eof_min_file_size; |
30 | xfs_ino_t eof_scan_owner; | ||
31 | }; | 30 | }; |
32 | 31 | ||
33 | #define SYNC_WAIT 0x0001 /* wait for i/o to complete */ | 32 | #define SYNC_WAIT 0x0001 /* wait for i/o to complete */ |
@@ -102,7 +101,6 @@ xfs_fs_eofblocks_from_user( | |||
102 | dst->eof_flags = src->eof_flags; | 101 | dst->eof_flags = src->eof_flags; |
103 | dst->eof_prid = src->eof_prid; | 102 | dst->eof_prid = src->eof_prid; |
104 | dst->eof_min_file_size = src->eof_min_file_size; | 103 | dst->eof_min_file_size = src->eof_min_file_size; |
105 | dst->eof_scan_owner = NULLFSINO; | ||
106 | 104 | ||
107 | dst->eof_uid = INVALID_UID; | 105 | dst->eof_uid = INVALID_UID; |
108 | if (src->eof_flags & XFS_EOF_FLAGS_UID) { | 106 | if (src->eof_flags & XFS_EOF_FLAGS_UID) { |