mm: memcg/slab: introduce mem_cgroup_from_obj()
Subsystems (3)
PATCH 1/1 mm: memcg/slab: introduce mem_cgroup_from_obj()
Sometimes we need to get a memcg pointer from a charged kernel object. The right way to get it depends on whether it's a proper slab object or it's backed by raw pages (e.g. it's a vmalloc alloction). In the first case the kmem_cache->memcg_params.memcg indirection should be used; in other cases it's just page->mem_cgroup.
To simplify this task and hide the implementation details let's introduce a mem_cgroup_from_obj() helper, which takes a pointer to any kernel object and returns a valid memcg pointer or NULL.
Passing a kernel address rather than a pointer to a page will allow to use this helper for per-object (rather than per-page) tracked objects in the future.
The caller is still responsible to ensure that the returned memcg isn't going away underneath: take the rcu read lock, cgroup mutex etc; depending on the context.
mem_cgroup_from_kmem() defined in mm/list_lru.c is now obsolete and can be removed.
--- include/linux/memcontrol.h | 7 +++++++ mm/list_lru.c | 12 +----------- mm/memcontrol.c | 32 +++++++++++++++++++++++++++++--- 3 files changed, 37 insertions(+), 14 deletions(-)
include/linux/memcontrol.h +7 -0
@@ -420,6 +420,8 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *, struct pglist_data *);struct mem_cgroup *mem_cgroup_from_task (struct task_struct *p); +struct mem_cgroup *mem_cgroup_from_obj (void *p); +struct mem_cgroup *get_mem_cgroup_from_mm (struct mm_struct *mm);struct mem_cgroup *get_mem_cgroup_from_page (struct page *page);
@@ -912,6 +914,11 @@ static inline bool mm_match_cgroup(struct mm_struct *mm,return true; } +static inline struct mem_cgroup *mem_cgroup_from_obj (void *p) +{ +return NULL ; +} +static inline struct mem_cgroup *get_mem_cgroup_from_mm (struct mm_struct *mm) {return NULL ;
mm/list_lru.c +1 -11
@@ -57,16 +57,6 @@ list_lru_from_memcg_idx(struct list_lru_node *nlru, int idx)return &nlru->lru; } -static __always_inline struct mem_cgroup *mem_cgroup_from_kmem(void *ptr) -{ -struct page *page; - -if (!memcg_kmem_enabled ()) -return NULL ; - page =virt_to_head_page (ptr); -return memcg_from_slab_page (page); -} -static inline struct list_lru_one *list_lru_from_kmem (struct list_lru_node *nlru,void *ptr,struct mem_cgroup **memcg_ptr)
@@ -77,7 +67,7 @@ list_lru_from_kmem(struct list_lru_node *nlru, void *ptr,if (!nlru->memcg_lrus) goto out; - memcg =mem_cgroup_from_kmem (ptr); + memcg =mem_cgroup_from_obj (ptr);if (!memcg) goto out;
mm/memcontrol.c +29 -3
@@ -757,13 +757,12 @@ void __mod_lruvec_state(struct lruvec *lruvec, enum node_stat_item idx,void __mod_lruvec_slab_state (void *p,enum node_stat_item idx,int val) { -struct page *page =virt_to_head_page (p); -pg_data_t *pgdat =page_pgdat (page); +pg_data_t *pgdat =page_pgdat (virt_to_page (p));struct mem_cgroup *memcg;struct lruvec *lruvec;rcu_read_lock (); - memcg =memcg_from_slab_page (page); + memcg =mem_cgroup_from_obj (p);/* Untracked pages have no memcg, no lruvec. Update only the node */ if (!memcg || memcg == root_mem_cgroup) {
@@ -2635,6 +2634,33 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg,unlock_page_lru (page, isolated); } +/* +* Returns a pointer to the memory cgroup to which the kernel object is charged. +* +* The caller must ensure the memcg lifetime, e.g. by taking rcu_read_lock(), +* cgroup_mutex, etc. +*/ +struct mem_cgroup *mem_cgroup_from_obj (void *p) +{ +struct page *page; + +if (mem_cgroup_disabled ()) +return NULL ; + + page =virt_to_head_page (p); + +/* +* Slab pages don't have page->mem_cgroup set because corresponding +* kmem caches can be reparented during the lifetime. That's why +* memcg_from_slab_page() should be used instead. +*/ +if (PageSlab (page)) +return memcg_from_slab_page (page); + +/* All other pages use page->mem_cgroup */ +return page->mem_cgroup; +} +#ifdef CONFIG_MEMCG_KMEM static int memcg_alloc_cache_id (void ) {
Signature · 1 line
2.17.1
Quoted 19 lines · Roman Gushchin
Sometimes we need to get a memcg pointer from a charged kernel object. The right way to get it depends on whether it's a proper slab object or it's backed by raw pages (e.g. it's a vmalloc alloction). In the first case the
kmem_cache->memcg_params.memcgindirection should be used; in other cases it's justpage->mem_cgroup.To simplify this task and hide the implementation details let's introduce a
mem_cgroup_from_obj()helper, which takes a pointer to any kernel object and returns a valid memcg pointer or NULL.Passing a kernel address rather than a pointer to a page will allow to use this helper for per-object (rather than per-page) tracked objects in the future.
The caller is still responsible to ensure that the returned memcg isn't going away underneath: take the rcu read lock, cgroup mutex etc; depending on the context.
Quoted 5 lines
mem_cgroup_from_kmem()defined inmm/list_lru.cis now obsolete and can be removed.Signed-off-by Roman Gushchin <[email protected]>Acked-by Yafang Shao <[email protected]>