From ed6e9cc235b47b5c940178926715f871bd36dc5e Mon Sep 17 00:00:00 2001 From: Tim Chase Date: Thu, 2 Oct 2014 07:21:08 -0500 Subject: [PATCH] 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 Signed-off-by: Tim Chase Closes #2837 --- module/zfs/arc.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/module/zfs/arc.c b/module/zfs/arc.c index b42bb4050..96e17b61e 100644 --- a/module/zfs/arc.c +++ b/module/zfs/arc.c @@ -2604,27 +2604,39 @@ arc_evictable_memory(void) { 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) { - uint64_t pages; + int64_t pages; /* The arc is considered warm once reclaim has occurred */ if (unlikely(arc_warm == B_FALSE)) arc_warm = B_TRUE; /* 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) return (pages); /* Not allowed to perform filesystem reclaim */ if (!(sc->gfp_mask & __GFP_FS)) - return (-1); + return (SHRINK_STOP); /* Reclaim in progress */ if (mutex_tryenter(&arc_reclaim_thr_lock) == 0) - return (-1); + return (SHRINK_STOP); /* * 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) { 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()); +#endif } else { arc_kmem_reap_now(ARC_RECLAIM_CONS, ptob(sc->nr_to_scan)); - pages = -1; + pages = SHRINK_STOP; } /*