diff options
Diffstat (limited to 'fs/xfs/quota/xfs_qm.c')
-rw-r--r-- | fs/xfs/quota/xfs_qm.c | 264 |
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 | */ |
1935 | STATIC int | 1934 | STATIC xfs_dquot_t * |
1936 | xfs_qm_shake_freelist( | 1935 | xfs_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); | 1945 | startagain: |
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); | ||
2061 | dqfunlock: | ||
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 | */ | ||
2078 | STATIC int | ||
2079 | xfs_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 | */ | ||
2122 | STATIC xfs_dquot_t * | ||
2123 | xfs_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 | /* |