This patch extends the list_lru interfaces to allow for a memcg parameter. Because most of its users won't need it, instead of modifying the function signatures we create a new set of _memcg() functions and write the old API on top of that. Signed-off-by: Glauber Costa <glommer@xxxxxxxxxx> Cc: Dave Chinner <dchinner@xxxxxxxxxx> Cc: Mel Gorman <mgorman@xxxxxxx> Cc: Rik van Riel <riel@xxxxxxxxxx> Cc: Johannes Weiner <hannes@xxxxxxxxxxx> Cc: Michal Hocko <mhocko@xxxxxxx> Cc: Hugh Dickins <hughd@xxxxxxxxxx> Cc: Kamezawa Hiroyuki <kamezawa.hiroyu@xxxxxxxxxxxxxx> Cc: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- include/linux/list_lru.h | 30 +++++++++++++++++++++++++----- include/linux/memcontrol.h | 2 ++ mm/list_lru.c | 25 ++++++++++++++++++------- 3 files changed, 45 insertions(+), 12 deletions(-) diff --git a/include/linux/list_lru.h b/include/linux/list_lru.h index e7a1199..57d0bb0 100644 --- a/include/linux/list_lru.h +++ b/include/linux/list_lru.h @@ -128,15 +128,24 @@ bool list_lru_add(struct list_lru *lru, struct list_head *item); bool list_lru_del(struct list_lru *lru, struct list_head *item); /** - * list_lru_count_node: return the number of objects currently held by @lru + * list_lru_count_node_memcg: return the number of objects currently held by @lru * @lru: the lru pointer. * @nid: the node id to count from. + * @memcg: restricts the count to this memcg, NULL for global. * * Always return a non-negative number, 0 for empty lists. There is no * guarantee that the list is not updated while the count is being computed. * Callers that want such a guarantee need to provide an outer lock. */ -unsigned long list_lru_count_node(struct list_lru *lru, int nid); +unsigned long list_lru_count_node_memcg(struct list_lru *lru, int nid, + struct mem_cgroup *memcg); + +static inline unsigned long +list_lru_count_node(struct list_lru *lru, int nid) +{ + return list_lru_count_node_memcg(lru, nid, NULL); +} + static inline unsigned long list_lru_count(struct list_lru *lru) { long count = 0; @@ -158,6 +167,7 @@ typedef enum lru_status * the item currently being scanned * @cb_arg: opaque type that will be passed to @isolate * @nr_to_walk: how many items to scan. + * @memcg: restricts the scan to this memcg, NULL for global. * * This function will scan all elements in a particular list_lru, calling the * @isolate callback for each of those items, along with the current list @@ -171,9 +181,19 @@ typedef enum lru_status * * Return value: the number of objects effectively removed from the LRU. */ -unsigned long list_lru_walk_node(struct list_lru *lru, int nid, - list_lru_walk_cb isolate, void *cb_arg, - unsigned long *nr_to_walk); +unsigned long +list_lru_walk_node_memcg(struct list_lru *lru, int nid, + list_lru_walk_cb isolate, void *cb_arg, + unsigned long *nr_to_walk, struct mem_cgroup *memcg); + +static inline unsigned long +list_lru_walk_node(struct list_lru *lru, int nid, + list_lru_walk_cb isolate, void *cb_arg, + unsigned long *nr_to_walk) +{ + return list_lru_walk_node_memcg(lru, nid, isolate, cb_arg, + nr_to_walk, NULL); +} static inline unsigned long list_lru_walk(struct list_lru *lru, list_lru_walk_cb isolate, diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h index e069d53..a8c5493 100644 --- a/include/linux/memcontrol.h +++ b/include/linux/memcontrol.h @@ -591,6 +591,8 @@ static inline bool memcg_kmem_is_active(struct mem_cgroup *memcg) #define for_each_memcg_cache_index(_idx) \ for (; NULL; ) +#define memcg_limited_groups_array_size 0 + static inline bool memcg_kmem_enabled(void) { return false; diff --git a/mm/list_lru.c b/mm/list_lru.c index bdd97cf..8ec51fa 100644 --- a/mm/list_lru.c +++ b/mm/list_lru.c @@ -128,10 +128,16 @@ bool list_lru_del(struct list_lru *lru, struct list_head *item) EXPORT_SYMBOL_GPL(list_lru_del); unsigned long -list_lru_count_node(struct list_lru *lru, int nid) +list_lru_count_node_memcg(struct list_lru *lru, int nid, + struct mem_cgroup *memcg) { unsigned long count = 0; - struct list_lru_node *nlru = &lru->node[nid]; + int memcg_id = memcg_cache_id(memcg); + struct list_lru_node *nlru; + + nlru = lru_node_of_index(lru, memcg_id, nid); + if (!nlru) + return 0; spin_lock(&nlru->lock); WARN_ON_ONCE(nlru->nr_items < 0); @@ -140,16 +146,18 @@ list_lru_count_node(struct list_lru *lru, int nid) return count; } -EXPORT_SYMBOL_GPL(list_lru_count_node); +EXPORT_SYMBOL_GPL(list_lru_count_node_memcg); unsigned long -list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate, - void *cb_arg, unsigned long *nr_to_walk) +list_lru_walk_node_memcg(struct list_lru *lru, int nid, + list_lru_walk_cb isolate, void *cb_arg, + unsigned long *nr_to_walk, struct mem_cgroup *memcg) { - struct list_lru_node *nlru = &lru->node[nid]; struct list_head *item, *n; unsigned long isolated = 0; + struct list_lru_node *nlru; + int memcg_id = memcg_cache_id(memcg); /* * If we don't keep state of at which pass we are, we can loop at * LRU_RETRY, since we have no guarantees that the caller will be able @@ -159,6 +167,9 @@ list_lru_walk_node(struct list_lru *lru, int nid, list_lru_walk_cb isolate, */ bool first_pass = true; + nlru = lru_node_of_index(lru, memcg_id, nid); + if (!nlru) + return 0; spin_lock(&nlru->lock); restart: list_for_each_safe(item, n, &nlru->list) { @@ -196,7 +207,7 @@ restart: spin_unlock(&nlru->lock); return isolated; } -EXPORT_SYMBOL_GPL(list_lru_walk_node); +EXPORT_SYMBOL_GPL(list_lru_walk_node_memcg); /* * Each list_lru that is memcg-aware is inserted into the all_memcgs_lrus, -- 1.8.2.1 -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html