aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_vnodeops.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xfs/xfs_vnodeops.c')
-rw-r--r--fs/xfs/xfs_vnodeops.c162
1 files changed, 41 insertions, 121 deletions
diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c
index c5dc7ea85260..077c86b6cb22 100644
--- a/fs/xfs/xfs_vnodeops.c
+++ b/fs/xfs/xfs_vnodeops.c
@@ -1708,111 +1708,6 @@ std_return:
1708} 1708}
1709 1709
1710#ifdef DEBUG 1710#ifdef DEBUG
1711/*
1712 * Some counters to see if (and how often) we are hitting some deadlock
1713 * prevention code paths.
1714 */
1715
1716int xfs_rm_locks;
1717int xfs_rm_lock_delays;
1718int xfs_rm_attempts;
1719#endif
1720
1721/*
1722 * The following routine will lock the inodes associated with the
1723 * directory and the named entry in the directory. The locks are
1724 * acquired in increasing inode number.
1725 *
1726 * If the entry is "..", then only the directory is locked. The
1727 * vnode ref count will still include that from the .. entry in
1728 * this case.
1729 *
1730 * There is a deadlock we need to worry about. If the locked directory is
1731 * in the AIL, it might be blocking up the log. The next inode we lock
1732 * could be already locked by another thread waiting for log space (e.g
1733 * a permanent log reservation with a long running transaction (see
1734 * xfs_itruncate_finish)). To solve this, we must check if the directory
1735 * is in the ail and use lock_nowait. If we can't lock, we need to
1736 * drop the inode lock on the directory and try again. xfs_iunlock will
1737 * potentially push the tail if we were holding up the log.
1738 */
1739STATIC int
1740xfs_lock_dir_and_entry(
1741 xfs_inode_t *dp,
1742 xfs_inode_t *ip) /* inode of entry 'name' */
1743{
1744 int attempts;
1745 xfs_ino_t e_inum;
1746 xfs_inode_t *ips[2];
1747 xfs_log_item_t *lp;
1748
1749#ifdef DEBUG
1750 xfs_rm_locks++;
1751#endif
1752 attempts = 0;
1753
1754again:
1755 xfs_ilock(dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
1756
1757 e_inum = ip->i_ino;
1758
1759 xfs_itrace_ref(ip);
1760
1761 /*
1762 * We want to lock in increasing inum. Since we've already
1763 * acquired the lock on the directory, we may need to release
1764 * if if the inum of the entry turns out to be less.
1765 */
1766 if (e_inum > dp->i_ino) {
1767 /*
1768 * We are already in the right order, so just
1769 * lock on the inode of the entry.
1770 * We need to use nowait if dp is in the AIL.
1771 */
1772
1773 lp = (xfs_log_item_t *)dp->i_itemp;
1774 if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
1775 if (!xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
1776 attempts++;
1777#ifdef DEBUG
1778 xfs_rm_attempts++;
1779#endif
1780
1781 /*
1782 * Unlock dp and try again.
1783 * xfs_iunlock will try to push the tail
1784 * if the inode is in the AIL.
1785 */
1786
1787 xfs_iunlock(dp, XFS_ILOCK_EXCL);
1788
1789 if ((attempts % 5) == 0) {
1790 delay(1); /* Don't just spin the CPU */
1791#ifdef DEBUG
1792 xfs_rm_lock_delays++;
1793#endif
1794 }
1795 goto again;
1796 }
1797 } else {
1798 xfs_ilock(ip, XFS_ILOCK_EXCL);
1799 }
1800 } else if (e_inum < dp->i_ino) {
1801 xfs_iunlock(dp, XFS_ILOCK_EXCL);
1802
1803 ips[0] = ip;
1804 ips[1] = dp;
1805 xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL);
1806 }
1807 /* else e_inum == dp->i_ino */
1808 /* This can happen if we're asked to lock /x/..
1809 * the entry is "..", which is also the parent directory.
1810 */
1811
1812 return 0;
1813}
1814
1815#ifdef DEBUG
1816int xfs_locked_n; 1711int xfs_locked_n;
1817int xfs_small_retries; 1712int xfs_small_retries;
1818int xfs_middle_retries; 1713int xfs_middle_retries;
@@ -1946,6 +1841,45 @@ again:
1946#endif 1841#endif
1947} 1842}
1948 1843
1844void
1845xfs_lock_two_inodes(
1846 xfs_inode_t *ip0,
1847 xfs_inode_t *ip1,
1848 uint lock_mode)
1849{
1850 xfs_inode_t *temp;
1851 int attempts = 0;
1852 xfs_log_item_t *lp;
1853
1854 ASSERT(ip0->i_ino != ip1->i_ino);
1855
1856 if (ip0->i_ino > ip1->i_ino) {
1857 temp = ip0;
1858 ip0 = ip1;
1859 ip1 = temp;
1860 }
1861
1862 again:
1863 xfs_ilock(ip0, xfs_lock_inumorder(lock_mode, 0));
1864
1865 /*
1866 * If the first lock we have locked is in the AIL, we must TRY to get
1867 * the second lock. If we can't get it, we must release the first one
1868 * and try again.
1869 */
1870 lp = (xfs_log_item_t *)ip0->i_itemp;
1871 if (lp && (lp->li_flags & XFS_LI_IN_AIL)) {
1872 if (!xfs_ilock_nowait(ip1, xfs_lock_inumorder(lock_mode, 1))) {
1873 xfs_iunlock(ip0, lock_mode);
1874 if ((++attempts % 5) == 0)
1875 delay(1); /* Don't just spin the CPU */
1876 goto again;
1877 }
1878 } else {
1879 xfs_ilock(ip1, xfs_lock_inumorder(lock_mode, 1));
1880 }
1881}
1882
1949int 1883int
1950xfs_remove( 1884xfs_remove(
1951 xfs_inode_t *dp, 1885 xfs_inode_t *dp,
@@ -2018,9 +1952,7 @@ xfs_remove(
2018 goto out_trans_cancel; 1952 goto out_trans_cancel;
2019 } 1953 }
2020 1954
2021 error = xfs_lock_dir_and_entry(dp, ip); 1955 xfs_lock_two_inodes(dp, ip, XFS_ILOCK_EXCL);
2022 if (error)
2023 goto out_trans_cancel;
2024 1956
2025 /* 1957 /*
2026 * At this point, we've gotten both the directory and the entry 1958 * At this point, we've gotten both the directory and the entry
@@ -2047,9 +1979,6 @@ xfs_remove(
2047 } 1979 }
2048 } 1980 }
2049 1981
2050 /*
2051 * Entry must exist since we did a lookup in xfs_lock_dir_and_entry.
2052 */
2053 XFS_BMAP_INIT(&free_list, &first_block); 1982 XFS_BMAP_INIT(&free_list, &first_block);
2054 error = xfs_dir_removename(tp, dp, name, ip->i_ino, 1983 error = xfs_dir_removename(tp, dp, name, ip->i_ino,
2055 &first_block, &free_list, resblks); 1984 &first_block, &free_list, resblks);
@@ -2155,7 +2084,6 @@ xfs_link(
2155{ 2084{
2156 xfs_mount_t *mp = tdp->i_mount; 2085 xfs_mount_t *mp = tdp->i_mount;
2157 xfs_trans_t *tp; 2086 xfs_trans_t *tp;
2158 xfs_inode_t *ips[2];
2159 int error; 2087 int error;
2160 xfs_bmap_free_t free_list; 2088 xfs_bmap_free_t free_list;
2161 xfs_fsblock_t first_block; 2089 xfs_fsblock_t first_block;
@@ -2203,15 +2131,7 @@ xfs_link(
2203 goto error_return; 2131 goto error_return;
2204 } 2132 }
2205 2133
2206 if (sip->i_ino < tdp->i_ino) { 2134 xfs_lock_two_inodes(sip, tdp, XFS_ILOCK_EXCL);
2207 ips[0] = sip;
2208 ips[1] = tdp;
2209 } else {
2210 ips[0] = tdp;
2211 ips[1] = sip;
2212 }
2213
2214 xfs_lock_inodes(ips, 2, XFS_ILOCK_EXCL);
2215 2135
2216 /* 2136 /*
2217 * Increment vnode ref counts since xfs_trans_commit & 2137 * Increment vnode ref counts since xfs_trans_commit &