Linux 3.12 compat: shrinker semantics

The new shrinker API as of Linux 3.12 modifies "struct shrinker" by
replacing the @shrink callback with the pair of @count_objects and
@scan_objects.  It also requires the return value of @count_objects to
return the number of objects actually freed whereas the previous @shrink
callback returned the number of remaining freeable objects.

This patch adds support for the new @scan_objects return value semantics.

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Tim Chase <tim@chase2k.com>
Closes #2837
This commit is contained in:
Tim Chase 2014-10-02 07:21:08 -05:00 committed by Brian Behlendorf
parent 9635861742
commit ed6e9cc235

View File

@ -2604,27 +2604,39 @@ arc_evictable_memory(void) {
return (ghost_clean + MAX((int64_t)arc_size - (int64_t)arc_c_min, 0)); return (ghost_clean + MAX((int64_t)arc_size - (int64_t)arc_c_min, 0));
} }
static int /*
* If sc->nr_to_scan is zero, the caller is requesting a query of the
* number of objects which can potentially be freed. If it is nonzero,
* the request is to free that many objects.
*
* Linux kernels >= 3.12 have the count_objects and scan_objects callbacks
* in struct shrinker and also require the shrinker to return the number
* of objects freed.
*
* Older kernels require the shrinker to return the number of freeable
* objects following the freeing of nr_to_free.
*/
static spl_shrinker_t
__arc_shrinker_func(struct shrinker *shrink, struct shrink_control *sc) __arc_shrinker_func(struct shrinker *shrink, struct shrink_control *sc)
{ {
uint64_t pages; int64_t pages;
/* The arc is considered warm once reclaim has occurred */ /* The arc is considered warm once reclaim has occurred */
if (unlikely(arc_warm == B_FALSE)) if (unlikely(arc_warm == B_FALSE))
arc_warm = B_TRUE; arc_warm = B_TRUE;
/* Return the potential number of reclaimable pages */ /* Return the potential number of reclaimable pages */
pages = btop(arc_evictable_memory()); pages = btop((int64_t)arc_evictable_memory());
if (sc->nr_to_scan == 0) if (sc->nr_to_scan == 0)
return (pages); return (pages);
/* Not allowed to perform filesystem reclaim */ /* Not allowed to perform filesystem reclaim */
if (!(sc->gfp_mask & __GFP_FS)) if (!(sc->gfp_mask & __GFP_FS))
return (-1); return (SHRINK_STOP);
/* Reclaim in progress */ /* Reclaim in progress */
if (mutex_tryenter(&arc_reclaim_thr_lock) == 0) if (mutex_tryenter(&arc_reclaim_thr_lock) == 0)
return (-1); return (SHRINK_STOP);
/* /*
* Evict the requested number of pages by shrinking arc_c the * Evict the requested number of pages by shrinking arc_c the
@ -2633,10 +2645,15 @@ __arc_shrinker_func(struct shrinker *shrink, struct shrink_control *sc)
*/ */
if (pages > 0) { if (pages > 0) {
arc_kmem_reap_now(ARC_RECLAIM_AGGR, ptob(sc->nr_to_scan)); arc_kmem_reap_now(ARC_RECLAIM_AGGR, ptob(sc->nr_to_scan));
#ifdef HAVE_SPLIT_SHRINKER_CALLBACK
pages = MAX(pages - btop(arc_evictable_memory()), 0);
#else
pages = btop(arc_evictable_memory()); pages = btop(arc_evictable_memory());
#endif
} else { } else {
arc_kmem_reap_now(ARC_RECLAIM_CONS, ptob(sc->nr_to_scan)); arc_kmem_reap_now(ARC_RECLAIM_CONS, ptob(sc->nr_to_scan));
pages = -1; pages = SHRINK_STOP;
} }
/* /*