Skip to content
This repository has been archived by the owner on Feb 26, 2020. It is now read-only.

Commit

Permalink
Support post-3.12 shrinker semantics
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
dweeezil authored and ryao committed Oct 23, 2014
1 parent 9d43478 commit a46707e
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 19 deletions.
7 changes: 7 additions & 0 deletions include/linux/mm_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,4 +199,11 @@ fn ## _scan_objects(struct shrinker *shrink, struct shrink_control *sc) \
#error "Unknown shrinker callback"
#endif

#if defined(HAVE_SPLIT_SHRINKER_CALLBACK)
typedef unsigned long spl_shrinker_t;
#else
typedef int spl_shrinker_t;
#define SHRINK_STOP (-1)
#endif

#endif /* SPL_MM_COMPAT_H */
53 changes: 34 additions & 19 deletions module/spl/spl-kmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ MODULE_PARM_DESC(spl_kmem_cache_expire, "By age (0x1) or low memory (0x2)");
* setting this value to KMC_RECLAIM_ONCE limits how aggressively the cache
* is reclaimed. This may increase the likelihood of out of memory events.
*/
unsigned int spl_kmem_cache_reclaim = 0;
unsigned int spl_kmem_cache_reclaim = 0 /* KMC_RECLAIM_ONCE */;
module_param(spl_kmem_cache_reclaim, uint, 0644);
MODULE_PARM_DESC(spl_kmem_cache_reclaim, "Single reclaim pass (0x1)");

Expand Down Expand Up @@ -1977,14 +1977,24 @@ EXPORT_SYMBOL(spl_kmem_cache_free);
* report that they contain unused objects. Because of this we only
* register one shrinker function in the shim layer for all slab caches.
* We always attempt to shrink all caches when this generic shrinker
* is called. The shrinker should return the number of free objects
* in the cache when called with nr_to_scan == 0 but not attempt to
* free any objects. When nr_to_scan > 0 it is a request that nr_to_scan
* objects should be freed, which differs from Solaris semantics.
* Solaris semantics are to free all available objects which may (and
* probably will) be more objects than the requested nr_to_scan.
* is called.
*
* 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.
*
* Linux semantics differ from those under Solaris, which are to
* free all available objects which may (and * probably will) be more
* objects than the requested nr_to_scan.
*/
static int
static spl_shrinker_t
__spl_kmem_cache_generic_shrinker(struct shrinker *shrink,
struct shrink_control *sc)
{
Expand All @@ -1993,17 +2003,22 @@ __spl_kmem_cache_generic_shrinker(struct shrinker *shrink,

down_read(&spl_kmem_cache_sem);
list_for_each_entry(skc, &spl_kmem_cache_list, skc_list) {
if (sc->nr_to_scan)
if (sc->nr_to_scan) {
#ifdef HAVE_SPLIT_SHRINKER_CALLBACK
uint64_t oldalloc = skc->skc_obj_alloc;
spl_kmem_cache_reap_now(skc,
MAX(sc->nr_to_scan >> fls64(skc->skc_slab_objs), 1));

/*
* Presume everything alloc'ed is reclaimable, this ensures
* we are called again with nr_to_scan > 0 so can try and
* reclaim. The exact number is not important either so
* we forgo taking this already highly contented lock.
*/
alloc += skc->skc_obj_alloc;
if (oldalloc > skc->skc_obj_alloc)
alloc += oldalloc - skc->skc_obj_alloc;
#else
spl_kmem_cache_reap_now(skc,
MAX(sc->nr_to_scan >> fls64(skc->skc_slab_objs), 1));
alloc += skc->skc_obj_alloc;
#endif /* HAVE_SPLIT_SHRINKER_CALLBACK */
} else {
/* Request to query number of freeable objects */
alloc += skc->skc_obj_alloc;
}
}
up_read(&spl_kmem_cache_sem);

Expand All @@ -2014,7 +2029,7 @@ __spl_kmem_cache_generic_shrinker(struct shrinker *shrink,
* system to thrash.
*/
if ((spl_kmem_cache_reclaim & KMC_RECLAIM_ONCE) && sc->nr_to_scan)
return (-1);
return (SHRINK_STOP);

return (MAX(alloc, 0));
}
Expand Down Expand Up @@ -2125,7 +2140,7 @@ spl_kmem_reap(void)
sc.nr_to_scan = KMC_REAP_CHUNK;
sc.gfp_mask = GFP_KERNEL;

__spl_kmem_cache_generic_shrinker(NULL, &sc);
(void) __spl_kmem_cache_generic_shrinker(NULL, &sc);
}
EXPORT_SYMBOL(spl_kmem_reap);

Expand Down

0 comments on commit a46707e

Please sign in to comment.