mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-29 03:01:39 -04:00
list_lru: introduce list_lru_shrink_{count,walk}
Kmem accounting of memcg is unusable now, because it lacks slab shrinker
support. That means when we hit the limit we will get ENOMEM w/o any
chance to recover. What we should do then is to call shrink_slab, which
would reclaim old inode/dentry caches from this cgroup. This is what
this patch set is intended to do.
Basically, it does two things. First, it introduces the notion of
per-memcg slab shrinker. A shrinker that wants to reclaim objects per
cgroup should mark itself as SHRINKER_MEMCG_AWARE. Then it will be
passed the memory cgroup to scan from in shrink_control->memcg. For
such shrinkers shrink_slab iterates over the whole cgroup subtree under
the target cgroup and calls the shrinker for each kmem-active memory
cgroup.
Secondly, this patch set makes the list_lru structure per-memcg. It's
done transparently to list_lru users - everything they have to do is to
tell list_lru_init that they want memcg-aware list_lru. Then the
list_lru will automatically distribute objects among per-memcg lists
basing on which cgroup the object is accounted to. This way to make FS
shrinkers (icache, dcache) memcg-aware we only need to make them use
memcg-aware list_lru, and this is what this patch set does.
As before, this patch set only enables per-memcg kmem reclaim when the
pressure goes from memory.limit, not from memory.kmem.limit. Handling
memory.kmem.limit is going to be tricky due to GFP_NOFS allocations, and
it is still unclear whether we will have this knob in the unified
hierarchy.
This patch (of 9):
NUMA aware slab shrinkers use the list_lru structure to distribute
objects coming from different NUMA nodes to different lists. Whenever
such a shrinker needs to count or scan objects from a particular node,
it issues commands like this:
count = list_lru_count_node(lru, sc->nid);
freed = list_lru_walk_node(lru, sc->nid, isolate_func,
isolate_arg, &sc->nr_to_scan);
where sc is an instance of the shrink_control structure passed to it
from vmscan.
To simplify this, let's add special list_lru functions to be used by
shrinkers, list_lru_shrink_count() and list_lru_shrink_walk(), which
consolidate the nid and nr_to_scan arguments in the shrink_control
structure.
This will also allow us to avoid patching shrinkers that use list_lru
when we make shrink_slab() per-memcg - all we will have to do is extend
the shrink_control structure to include the target memcg and make
list_lru_shrink_{count,walk} handle this appropriately.
Signed-off-by: Vladimir Davydov <[email protected]>
Suggested-by: Dave Chinner <[email protected]>
Cc: Johannes Weiner <[email protected]>
Cc: Michal Hocko <[email protected]>
Cc: Greg Thelen <[email protected]>
Cc: Glauber Costa <[email protected]>
Cc: Alexander Viro <[email protected]>
Cc: Christoph Lameter <[email protected]>
Cc: Pekka Enberg <[email protected]>
Cc: David Rientjes <[email protected]>
Cc: Joonsoo Kim <[email protected]>
Cc: Tejun Heo <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
This commit is contained in:
parent
10c1045f28
commit
503c358cf1
9 changed files with 51 additions and 43 deletions
24
fs/super.c
24
fs/super.c
|
|
@ -77,8 +77,8 @@ static unsigned long super_cache_scan(struct shrinker *shrink,
|
|||
if (sb->s_op->nr_cached_objects)
|
||||
fs_objects = sb->s_op->nr_cached_objects(sb, sc->nid);
|
||||
|
||||
inodes = list_lru_count_node(&sb->s_inode_lru, sc->nid);
|
||||
dentries = list_lru_count_node(&sb->s_dentry_lru, sc->nid);
|
||||
inodes = list_lru_shrink_count(&sb->s_inode_lru, sc);
|
||||
dentries = list_lru_shrink_count(&sb->s_dentry_lru, sc);
|
||||
total_objects = dentries + inodes + fs_objects + 1;
|
||||
if (!total_objects)
|
||||
total_objects = 1;
|
||||
|
|
@ -86,20 +86,20 @@ static unsigned long super_cache_scan(struct shrinker *shrink,
|
|||
/* proportion the scan between the caches */
|
||||
dentries = mult_frac(sc->nr_to_scan, dentries, total_objects);
|
||||
inodes = mult_frac(sc->nr_to_scan, inodes, total_objects);
|
||||
fs_objects = mult_frac(sc->nr_to_scan, fs_objects, total_objects);
|
||||
|
||||
/*
|
||||
* prune the dcache first as the icache is pinned by it, then
|
||||
* prune the icache, followed by the filesystem specific caches
|
||||
*/
|
||||
freed = prune_dcache_sb(sb, dentries, sc->nid);
|
||||
freed += prune_icache_sb(sb, inodes, sc->nid);
|
||||
sc->nr_to_scan = dentries;
|
||||
freed = prune_dcache_sb(sb, sc);
|
||||
sc->nr_to_scan = inodes;
|
||||
freed += prune_icache_sb(sb, sc);
|
||||
|
||||
if (fs_objects) {
|
||||
fs_objects = mult_frac(sc->nr_to_scan, fs_objects,
|
||||
total_objects);
|
||||
if (fs_objects)
|
||||
freed += sb->s_op->free_cached_objects(sb, fs_objects,
|
||||
sc->nid);
|
||||
}
|
||||
|
||||
drop_super(sb);
|
||||
return freed;
|
||||
|
|
@ -118,17 +118,15 @@ static unsigned long super_cache_count(struct shrinker *shrink,
|
|||
* scalability bottleneck. The counts could get updated
|
||||
* between super_cache_count and super_cache_scan anyway.
|
||||
* Call to super_cache_count with shrinker_rwsem held
|
||||
* ensures the safety of call to list_lru_count_node() and
|
||||
* ensures the safety of call to list_lru_shrink_count() and
|
||||
* s_op->nr_cached_objects().
|
||||
*/
|
||||
if (sb->s_op && sb->s_op->nr_cached_objects)
|
||||
total_objects = sb->s_op->nr_cached_objects(sb,
|
||||
sc->nid);
|
||||
|
||||
total_objects += list_lru_count_node(&sb->s_dentry_lru,
|
||||
sc->nid);
|
||||
total_objects += list_lru_count_node(&sb->s_inode_lru,
|
||||
sc->nid);
|
||||
total_objects += list_lru_shrink_count(&sb->s_dentry_lru, sc);
|
||||
total_objects += list_lru_shrink_count(&sb->s_inode_lru, sc);
|
||||
|
||||
total_objects = vfs_pressure_ratio(total_objects);
|
||||
return total_objects;
|
||||
|
|
|
|||
Loading…
Reference in a new issue