aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/quota/xfs_qm.c
diff options
context:
space:
mode:
authorDave Chinner <dchinner@redhat.com>2010-04-13 01:06:50 -0400
committerAlex Elder <aelder@sgi.com>2010-05-19 10:58:11 -0400
commit368e136174344c417bad6ff0380b7b3f574bf120 (patch)
tree1718f3e35b42adbaabf5a65062f2d3f5ecf1ac43 /fs/xfs/quota/xfs_qm.c
parent3a25404b3fccd41d36b2fda18d86011201608c38 (diff)
xfs: remove duplicate code from dquot reclaim
The dquot shaker and the free-list reclaim code use exactly the same algorithm but the code is duplicated and slightly different in each case. Make the shaker code use the single dquot reclaim code to remove the code duplication. Signed-off-by: Dave Chinner <dchinner@redhat.com> Reviewed-by: Christoph Hellwig <hch@lst.de>
Diffstat (limited to 'fs/xfs/quota/xfs_qm.c')
-rw-r--r--fs/xfs/quota/xfs_qm.c264
1 files changed, 73 insertions, 191 deletions
diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c
index 855827320ff6..5ca65c834bbd 100644
--- a/fs/xfs/quota/xfs_qm.c
+++ b/fs/xfs/quota/xfs_qm.c
@@ -1926,53 +1926,46 @@ xfs_qm_init_quotainos(
1926} 1926}
1927 1927
1928 1928
1929
1929/* 1930/*
1930 * Traverse the freelist of dquots and attempt to reclaim a maximum of 1931 * Just pop the least recently used dquot off the freelist and
1931 * 'howmany' dquots. This operation races with dqlookup(), and attempts to 1932 * recycle it. The returned dquot is locked.
1932 * favor the lookup function ...
1933 * XXXsup merge this with qm_reclaim_one().
1934 */ 1933 */
1935STATIC int 1934STATIC xfs_dquot_t *
1936xfs_qm_shake_freelist( 1935xfs_qm_dqreclaim_one(void)
1937 int howmany)
1938{ 1936{
1939 int nreclaimed; 1937 xfs_dquot_t *dqpout;
1940 xfs_dqhash_t *hash; 1938 xfs_dquot_t *dqp;
1941 xfs_dquot_t *dqp, *nextdqp;
1942 int restarts; 1939 int restarts;
1943 int nflushes;
1944 1940
1945 if (howmany <= 0)
1946 return 0;
1947
1948 nreclaimed = 0;
1949 restarts = 0; 1941 restarts = 0;
1950 nflushes = 0; 1942 dqpout = NULL;
1951 1943
1952#ifdef QUOTADEBUG 1944 /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
1953 cmn_err(CE_DEBUG, "Shake free 0x%x", howmany); 1945startagain:
1954#endif
1955 /* lock order is : hashchainlock, freelistlock, mplistlock */
1956 tryagain:
1957 xfs_qm_freelist_lock(xfs_Gqm); 1946 xfs_qm_freelist_lock(xfs_Gqm);
1958 1947
1959 for (dqp = xfs_Gqm->qm_dqfreelist.qh_next; 1948 FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {
1960 ((dqp != (xfs_dquot_t *) &xfs_Gqm->qm_dqfreelist) &&
1961 nreclaimed < howmany); ) {
1962 struct xfs_mount *mp = dqp->q_mount; 1949 struct xfs_mount *mp = dqp->q_mount;
1963 xfs_dqlock(dqp); 1950 xfs_dqlock(dqp);
1964 1951
1965 /* 1952 /*
1966 * We are racing with dqlookup here. Naturally we don't 1953 * We are racing with dqlookup here. Naturally we don't
1967 * want to reclaim a dquot that lookup wants. 1954 * want to reclaim a dquot that lookup wants. We release the
1955 * freelist lock and start over, so that lookup will grab
1956 * both the dquot and the freelistlock.
1968 */ 1957 */
1969 if (dqp->dq_flags & XFS_DQ_WANT) { 1958 if (dqp->dq_flags & XFS_DQ_WANT) {
1959 ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
1960
1961 trace_xfs_dqreclaim_want(dqp);
1962
1970 xfs_dqunlock(dqp); 1963 xfs_dqunlock(dqp);
1971 xfs_qm_freelist_unlock(xfs_Gqm); 1964 xfs_qm_freelist_unlock(xfs_Gqm);
1972 if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) 1965 if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
1973 return nreclaimed; 1966 return NULL;
1974 XQM_STATS_INC(xqmstats.xs_qm_dqwants); 1967 XQM_STATS_INC(xqmstats.xs_qm_dqwants);
1975 goto tryagain; 1968 goto startagain;
1976 } 1969 }
1977 1970
1978 /* 1971 /*
@@ -1985,19 +1978,22 @@ xfs_qm_shake_freelist(
1985 ASSERT(! XFS_DQ_IS_DIRTY(dqp)); 1978 ASSERT(! XFS_DQ_IS_DIRTY(dqp));
1986 ASSERT(dqp->HL_PREVP == NULL); 1979 ASSERT(dqp->HL_PREVP == NULL);
1987 ASSERT(list_empty(&dqp->q_mplist)); 1980 ASSERT(list_empty(&dqp->q_mplist));
1981 XQM_FREELIST_REMOVE(dqp);
1982 xfs_dqunlock(dqp);
1983 dqpout = dqp;
1988 XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims); 1984 XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
1989 nextdqp = dqp->dq_flnext; 1985 break;
1990 goto off_freelist;
1991 } 1986 }
1992 1987
1988 ASSERT(dqp->q_hash);
1993 ASSERT(!list_empty(&dqp->q_mplist)); 1989 ASSERT(!list_empty(&dqp->q_mplist));
1990
1994 /* 1991 /*
1995 * Try to grab the flush lock. If this dquot is in the process of 1992 * Try to grab the flush lock. If this dquot is in the process of
1996 * getting flushed to disk, we don't want to reclaim it. 1993 * getting flushed to disk, we don't want to reclaim it.
1997 */ 1994 */
1998 if (!xfs_dqflock_nowait(dqp)) { 1995 if (!xfs_dqflock_nowait(dqp)) {
1999 xfs_dqunlock(dqp); 1996 xfs_dqunlock(dqp);
2000 dqp = dqp->dq_flnext;
2001 continue; 1997 continue;
2002 } 1998 }
2003 1999
@@ -2010,21 +2006,21 @@ xfs_qm_shake_freelist(
2010 if (XFS_DQ_IS_DIRTY(dqp)) { 2006 if (XFS_DQ_IS_DIRTY(dqp)) {
2011 int error; 2007 int error;
2012 2008
2013 trace_xfs_dqshake_dirty(dqp); 2009 trace_xfs_dqreclaim_dirty(dqp);
2014 2010
2015 /* 2011 /*
2016 * We flush it delayed write, so don't bother 2012 * We flush it delayed write, so don't bother
2017 * releasing the mplock. 2013 * releasing the freelist lock.
2018 */ 2014 */
2019 error = xfs_qm_dqflush(dqp, 0); 2015 error = xfs_qm_dqflush(dqp, 0);
2020 if (error) { 2016 if (error) {
2021 xfs_fs_cmn_err(CE_WARN, mp, 2017 xfs_fs_cmn_err(CE_WARN, mp,
2022 "xfs_qm_dqflush_all: dquot %p flush failed", dqp); 2018 "xfs_qm_dqreclaim: dquot %p flush failed", dqp);
2023 } 2019 }
2024 xfs_dqunlock(dqp); /* dqflush unlocks dqflock */ 2020 xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
2025 dqp = dqp->dq_flnext;
2026 continue; 2021 continue;
2027 } 2022 }
2023
2028 /* 2024 /*
2029 * We're trying to get the hashlock out of order. This races 2025 * We're trying to get the hashlock out of order. This races
2030 * with dqlookup; so, we giveup and goto the next dquot if 2026 * with dqlookup; so, we giveup and goto the next dquot if
@@ -2033,57 +2029,71 @@ xfs_qm_shake_freelist(
2033 * waiting for the freelist lock. 2029 * waiting for the freelist lock.
2034 */ 2030 */
2035 if (!mutex_trylock(&dqp->q_hash->qh_lock)) { 2031 if (!mutex_trylock(&dqp->q_hash->qh_lock)) {
2036 xfs_dqfunlock(dqp); 2032 restarts++;
2037 xfs_dqunlock(dqp); 2033 goto dqfunlock;
2038 dqp = dqp->dq_flnext;
2039 continue;
2040 } 2034 }
2035
2041 /* 2036 /*
2042 * This races with dquot allocation code as well as dqflush_all 2037 * This races with dquot allocation code as well as dqflush_all
2043 * and reclaim code. So, if we failed to grab the mplist lock, 2038 * and reclaim code. So, if we failed to grab the mplist lock,
2044 * giveup everything and start over. 2039 * giveup everything and start over.
2045 */ 2040 */
2046 hash = dqp->q_hash;
2047 ASSERT(hash);
2048 if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) { 2041 if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
2049 /* XXX put a sentinel so that we can come back here */ 2042 restarts++;
2043 mutex_unlock(&dqp->q_hash->qh_lock);
2050 xfs_dqfunlock(dqp); 2044 xfs_dqfunlock(dqp);
2051 xfs_dqunlock(dqp); 2045 xfs_dqunlock(dqp);
2052 mutex_unlock(&hash->qh_lock);
2053 xfs_qm_freelist_unlock(xfs_Gqm); 2046 xfs_qm_freelist_unlock(xfs_Gqm);
2054 if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS) 2047 if (restarts++ >= XFS_QM_RECLAIM_MAX_RESTARTS)
2055 return nreclaimed; 2048 return NULL;
2056 goto tryagain; 2049 goto startagain;
2057 } 2050 }
2058 2051
2059 trace_xfs_dqshake_unlink(dqp);
2060
2061#ifdef QUOTADEBUG
2062 cmn_err(CE_DEBUG, "Shake 0x%p, ID 0x%x\n",
2063 dqp, be32_to_cpu(dqp->q_core.d_id));
2064#endif
2065 ASSERT(dqp->q_nrefs == 0); 2052 ASSERT(dqp->q_nrefs == 0);
2066 nextdqp = dqp->dq_flnext;
2067 XQM_HASHLIST_REMOVE(hash, dqp);
2068 list_del_init(&dqp->q_mplist); 2053 list_del_init(&dqp->q_mplist);
2069 mp->m_quotainfo->qi_dquots--; 2054 mp->m_quotainfo->qi_dquots--;
2070 mp->m_quotainfo->qi_dqreclaims++; 2055 mp->m_quotainfo->qi_dqreclaims++;
2071 xfs_dqfunlock(dqp); 2056 XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
2072 mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
2073 mutex_unlock(&hash->qh_lock);
2074
2075 off_freelist:
2076 XQM_FREELIST_REMOVE(dqp); 2057 XQM_FREELIST_REMOVE(dqp);
2058 dqpout = dqp;
2059 mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
2060 mutex_unlock(&dqp->q_hash->qh_lock);
2061dqfunlock:
2062 xfs_dqfunlock(dqp);
2077 xfs_dqunlock(dqp); 2063 xfs_dqunlock(dqp);
2078 nreclaimed++; 2064 if (dqpout)
2079 XQM_STATS_INC(xqmstats.xs_qm_dqshake_reclaims); 2065 break;
2080 xfs_qm_dqdestroy(dqp); 2066 if (restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
2081 dqp = nextdqp; 2067 return NULL;
2082 } 2068 }
2083 xfs_qm_freelist_unlock(xfs_Gqm); 2069 xfs_qm_freelist_unlock(xfs_Gqm);
2084 return nreclaimed; 2070 return dqpout;
2085} 2071}
2086 2072
2073/*
2074 * Traverse the freelist of dquots and attempt to reclaim a maximum of
2075 * 'howmany' dquots. This operation races with dqlookup(), and attempts to
2076 * favor the lookup function ...
2077 */
2078STATIC int
2079xfs_qm_shake_freelist(
2080 int howmany)
2081{
2082 int nreclaimed = 0;
2083 xfs_dquot_t *dqp;
2084
2085 if (howmany <= 0)
2086 return 0;
2087
2088 while (nreclaimed < howmany) {
2089 dqp = xfs_qm_dqreclaim_one();
2090 if (!dqp)
2091 return nreclaimed;
2092 xfs_qm_dqdestroy(dqp);
2093 nreclaimed++;
2094 }
2095 return nreclaimed;
2096}
2087 2097
2088/* 2098/*
2089 * The kmem_shake interface is invoked when memory is running low. 2099 * The kmem_shake interface is invoked when memory is running low.
@@ -2115,134 +2125,6 @@ xfs_qm_shake(int nr_to_scan, gfp_t gfp_mask)
2115} 2125}
2116 2126
2117 2127
2118/*
2119 * Just pop the least recently used dquot off the freelist and
2120 * recycle it. The returned dquot is locked.
2121 */
2122STATIC xfs_dquot_t *
2123xfs_qm_dqreclaim_one(void)
2124{
2125 xfs_dquot_t *dqpout;
2126 xfs_dquot_t *dqp;
2127 int restarts;
2128 int nflushes;
2129
2130 restarts = 0;
2131 dqpout = NULL;
2132 nflushes = 0;
2133
2134 /* lockorder: hashchainlock, freelistlock, mplistlock, dqlock, dqflock */
2135 startagain:
2136 xfs_qm_freelist_lock(xfs_Gqm);
2137
2138 FOREACH_DQUOT_IN_FREELIST(dqp, &(xfs_Gqm->qm_dqfreelist)) {
2139 struct xfs_mount *mp = dqp->q_mount;
2140 xfs_dqlock(dqp);
2141
2142 /*
2143 * We are racing with dqlookup here. Naturally we don't
2144 * want to reclaim a dquot that lookup wants. We release the
2145 * freelist lock and start over, so that lookup will grab
2146 * both the dquot and the freelistlock.
2147 */
2148 if (dqp->dq_flags & XFS_DQ_WANT) {
2149 ASSERT(! (dqp->dq_flags & XFS_DQ_INACTIVE));
2150
2151 trace_xfs_dqreclaim_want(dqp);
2152
2153 xfs_dqunlock(dqp);
2154 xfs_qm_freelist_unlock(xfs_Gqm);
2155 if (++restarts >= XFS_QM_RECLAIM_MAX_RESTARTS)
2156 return NULL;
2157 XQM_STATS_INC(xqmstats.xs_qm_dqwants);
2158 goto startagain;
2159 }
2160
2161 /*
2162 * If the dquot is inactive, we are assured that it is
2163 * not on the mplist or the hashlist, and that makes our
2164 * life easier.
2165 */
2166 if (dqp->dq_flags & XFS_DQ_INACTIVE) {
2167 ASSERT(mp == NULL);
2168 ASSERT(! XFS_DQ_IS_DIRTY(dqp));
2169 ASSERT(dqp->HL_PREVP == NULL);
2170 ASSERT(list_empty(&dqp->q_mplist));
2171 XQM_FREELIST_REMOVE(dqp);
2172 xfs_dqunlock(dqp);
2173 dqpout = dqp;
2174 XQM_STATS_INC(xqmstats.xs_qm_dqinact_reclaims);
2175 break;
2176 }
2177
2178 ASSERT(dqp->q_hash);
2179 ASSERT(!list_empty(&dqp->q_mplist));
2180
2181 /*
2182 * Try to grab the flush lock. If this dquot is in the process of
2183 * getting flushed to disk, we don't want to reclaim it.
2184 */
2185 if (!xfs_dqflock_nowait(dqp)) {
2186 xfs_dqunlock(dqp);
2187 continue;
2188 }
2189
2190 /*
2191 * We have the flush lock so we know that this is not in the
2192 * process of being flushed. So, if this is dirty, flush it
2193 * DELWRI so that we don't get a freelist infested with
2194 * dirty dquots.
2195 */
2196 if (XFS_DQ_IS_DIRTY(dqp)) {
2197 int error;
2198
2199 trace_xfs_dqreclaim_dirty(dqp);
2200
2201 /*
2202 * We flush it delayed write, so don't bother
2203 * releasing the freelist lock.
2204 */
2205 error = xfs_qm_dqflush(dqp, 0);
2206 if (error) {
2207 xfs_fs_cmn_err(CE_WARN, mp,
2208 "xfs_qm_dqreclaim: dquot %p flush failed", dqp);
2209 }
2210 xfs_dqunlock(dqp); /* dqflush unlocks dqflock */
2211 continue;
2212 }
2213
2214 if (!mutex_trylock(&mp->m_quotainfo->qi_dqlist_lock)) {
2215 xfs_dqfunlock(dqp);
2216 xfs_dqunlock(dqp);
2217 continue;
2218 }
2219
2220 if (!mutex_trylock(&dqp->q_hash->qh_lock))
2221 goto mplistunlock;
2222
2223 trace_xfs_dqreclaim_unlink(dqp);
2224
2225 ASSERT(dqp->q_nrefs == 0);
2226 list_del_init(&dqp->q_mplist);
2227 mp->m_quotainfo->qi_dquots--;
2228 mp->m_quotainfo->qi_dqreclaims++;
2229 XQM_HASHLIST_REMOVE(dqp->q_hash, dqp);
2230 XQM_FREELIST_REMOVE(dqp);
2231 dqpout = dqp;
2232 mutex_unlock(&dqp->q_hash->qh_lock);
2233 mplistunlock:
2234 mutex_unlock(&mp->m_quotainfo->qi_dqlist_lock);
2235 xfs_dqfunlock(dqp);
2236 xfs_dqunlock(dqp);
2237 if (dqpout)
2238 break;
2239 }
2240
2241 xfs_qm_freelist_unlock(xfs_Gqm);
2242 return dqpout;
2243}
2244
2245
2246/*------------------------------------------------------------------*/ 2128/*------------------------------------------------------------------*/
2247 2129
2248/* 2130/*