]> granicus.if.org Git - zfs/commitdiff
Linux 3.12 compat: shrinker semantics
authorTim Chase <tim@chase2k.com>
Thu, 2 Oct 2014 12:21:08 +0000 (07:21 -0500)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 23 Dec 2014 00:13:04 +0000 (16:13 -0800)
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

module/zfs/arc.c

index 387faaf8d72625a3fa5087e44c2be95f60dff019..defcdd4bd83fcfb1508e3030545e301675abc84e 100644 (file)
@@ -2590,27 +2590,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
@@ -2619,10 +2631,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;
        }
 
        /*