Skip to contentSkip to conversation

Directed kmem charging

PATCH Superseded Shakeel Butt 5 participants 20 messages Jun 19, 2018 – Jun 23, 2018

Subsystems (12)

v6 of 8 Superseded Latest is v8 →

lore
Share & tools
lore
#0 lore raw

v6 cover Directed kmem charging

This patchset introduces memcg variant memory allocation functions. The caller can explicitly pass the memcg to charge for kmem allocations. Currently the kernel, for __GFP_ACCOUNT memory allocation requests, extract the memcg of the current task to charge for the kmem allocation. This patch series introduces kmem allocation functions where the caller can pass the pointer to the remote memcg. The remote memcg will be charged for the allocation instead of the memcg of the caller. However the caller must have a reference to the remote memcg. This patch series also introduces scope API for targeted memcg charging. So, all the __GFP_ACCOUNT alloctions within the specified scope will be charged to the given target memcg.

Shakeel Butt (3):
mm: memcg: remote memcg charging for kmem allocations
fs: fsnotify: account fsnotify metadata to kmemcg fs, mm: account buffer_head to kmemcg

 fs/buffer.c                          | 14 ++++-
 fs/notify/dnotify/dnotify.c          |  5 +-
 fs/notify/fanotify/fanotify.c        |  6 +-
 fs/notify/fanotify/fanotify_user.c   |  5 +-
 fs/notify/group.c                    |  6 ++
 fs/notify/inotify/inotify_fsnotify.c |  2 +-
 fs/notify/inotify/inotify_user.c     |  5 +-
 include/linux/fsnotify_backend.h     | 12 ++--
 include/linux/memcontrol.h           | 14 +++++
 include/linux/sched.h                |  3 +
 include/linux/sched/mm.h             | 24 ++++++++
 include/linux/slab.h                 | 83 ++++++++++++++++++++++++++++
 kernel/fork.c                        |  3 +
 mm/memcontrol.c                      | 54 ++++++++++++++++--
 14 files changed, 220 insertions(+), 16 deletions(-)
Signature · 1 line
2.18.0.rc1.244.gcf134e6275-goog
#1 lore raw

PATCH v6 1/3 mm: memcg: remote memcg charging for kmem allocations

Introduce the memcg variant for kmalloc[_node] and kmem_cache_alloc[_node]. For kmem_cache_alloc, the kernel switches the root kmem cache with the memcg specific kmem cache for __GFP_ACCOUNT allocations to charge those allocations to the memcg. However, the memcg to charge is extracted from the current task_struct. This patch introduces the variant of kmem cache allocation functions where the memcg can be provided explicitly by the caller instead of deducing the memcg from the current task.

The kmalloc allocations are underlying served using the kmem caches unless the size of the allocation request is larger than KMALLOC_MAX_CACHE_SIZE, in which case, the kmem caches are bypassed and the request is routed directly to page allocator. So, for __GFP_ACCOUNT kmalloc allocations, the memcg of current task is charged. This patch introduces memcg variant of kmalloc functions to allow callers to provide memcg for charging.

These functions are useful for use-cases where the allocations should be charged to the memcg different from the memcg of the caller. One such concrete use-case is the allocations for fsnotify event objects where the objects should be charged to the listener instead of the producer.

One requirement to call these functions is that the caller must have the reference to the memcg provided to these functions. If reference acquition on the given memcg is failed (it can fail if memcg is offline) then the current's memcg is tried. These functions implicitly assumes that the caller wants a __GFP_ACCOUNT allocation.

This patch also introduces scope API for targeted memcg charging. All the __GFP_ACCOUNT allocations between memalloc_memcg_save(target_memcg) and memalloc_memcg_restore(old_memcg) will be charged to target_memcg.

Traditionally kmem charging is skipped for allocations by kthreads and allocations during interrupts. The reason is that the current's memcg might not be the right owner for such allocations. However targeted memcg charging does not have such limitation and can work even for allocations by kthreads and for allocations during interrupts. For now due to lack of actual use-case, targeted memcg charging for such allocations is not added. Though this might change in future.

Cc Michal Hocko <[email protected]>
Cc Jan Kara <[email protected]>
Cc Amir Goldstein <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc David Rientjes <[email protected]>
Cc Joonsoo Kim <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>

---
Changelog sinve v5:
- Added more explanation in commit message.
- Added handling of NULL memcg for targeted memcg allocation functions.

Changelog since v4:
- Removed branch from hot path of memory charging.

Changelog since v3:
- Added node variant of directed kmem allocation functions.

Changelog since v2:
- Merge the kmalloc_memcg patch into this patch.
- Instead of plumbing memcg throughout, use field in task_struct to pass the target_memcg.

Changelog since v1:
- Fixed build for SLOB

 include/linux/sched.h    |  3 ++
 include/linux/sched/mm.h | 24 ++++++++++++
 include/linux/slab.h     | 83 ++++++++++++++++++++++++++++++++++++++++
 kernel/fork.c            |  3 ++
 mm/memcontrol.c          | 18 ++++++++-
 5 files changed, 129 insertions(+), 2 deletions(-)
include/linux/sched.h +3 -0
index 87bf02d93a27..cbd0def60fd4 100644
@@ -1149,6 +1149,9 @@ struct task_struct {
 
 	/* Number of pages to reclaim on returning to userland: */
 	unsigned int			memcg_nr_pages_over_high;
+
+	/* Used by memcontrol for targeted memcg charge: */
+	struct mem_cgroup		*target_memcg;
 #endif
 
 #ifdef CONFIG_UPROBES
include/linux/sched/mm.h +24 -0
index 44d356f5e47c..2ffb194f3f32 100644
@@ -248,6 +248,30 @@ static inline void memalloc_noreclaim_restore(unsigned int flags)
 	current->flags = (current->flags & ~PF_MEMALLOC) | flags;
 }
 
+#ifdef CONFIG_MEMCG
+static inline struct mem_cgroup *memalloc_memcg_save(struct mem_cgroup *memcg)
+{
+	struct mem_cgroup *old_memcg = current->target_memcg;
+
+	current->target_memcg = memcg;
+	return old_memcg;
+}
+
+static inline void memalloc_memcg_restore(struct mem_cgroup *memcg)
+{
+	current->target_memcg = memcg;
+}
+#else
+static inline struct mem_cgroup *memalloc_memcg_save(struct mem_cgroup *memcg)
+{
+	return NULL;
+}
+
+static inline void memalloc_memcg_restore(struct mem_cgroup *memcg)
+{
+}
+#endif /* CONFIG_MEMCG */
+
 #ifdef CONFIG_MEMBARRIER
 enum {
 	MEMBARRIER_STATE_PRIVATE_EXPEDITED_READY		= (1U << 0),
include/linux/slab.h +83 -0

113 lines not on this page · raw message

kernel/fork.c +3 -0
index a64d0a19f174..5bf300015790 100644
@@ -843,6 +843,9 @@ static struct task_struct *dup_task_struct(struct task_struct *orig, int node)
 	tsk->fail_nth = 0;
 #endif
 
+#ifdef CONFIG_MEMCG
+	tsk->target_memcg = NULL;
+#endif
 	return tsk;
 
 free_stack:
mm/memcontrol.c +16 -2
index 02e77c88967a..08bfb8c2411b 100644
@@ -701,6 +701,20 @@ static struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
 	return memcg;
 }
 
+static __always_inline struct mem_cgroup *get_mem_cgroup(
+				struct mem_cgroup *memcg, struct mm_struct *mm)
+{
+	if (unlikely(memcg)) {
+		rcu_read_lock();
+		if (css_tryget_online(&memcg->css)) {
+			rcu_read_unlock();
+			return memcg;
+		}
+		rcu_read_unlock();
+	}
+	return get_mem_cgroup_from_mm(mm);
+}
+
 /**
  * mem_cgroup_iter - iterate over memory cgroup hierarchy
  * @root: hierarchy root
@@ -2260,7 +2274,7 @@ struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep)
 	if (current->memcg_kmem_skip_account)
 		return cachep;
 
-	memcg = get_mem_cgroup_from_mm(current->mm);
+	memcg = get_mem_cgroup(current->target_memcg, current->mm);
 	kmemcg_id = READ_ONCE(memcg->kmemcg_id);
 	if (kmemcg_id < 0)
 		goto out;
@@ -2344,7 +2358,7 @@ int memcg_kmem_charge(struct page *page, gfp_t gfp, int order)
 	if (memcg_kmem_bypass())
 		return 0;
 
-	memcg = get_mem_cgroup_from_mm(current->mm);
+	memcg = get_mem_cgroup(current->target_memcg, current->mm);
 	if (!mem_cgroup_is_root(memcg)) {
 		ret = memcg_kmem_charge_memcg(page, gfp, order, memcg);
 		if (!ret)
Signature · 1 line
2.18.0.rc1.244.gcf134e6275-goog
maintainer
#2 lore raw

Re: [PATCH 1/3] mm: memcg: remote memcg charging for kmem allocations

Quoted 7 lines · Shakeel Butt
include/linux/sched/mm.h +3 -0
@@ -248,6 +248,30 @@ static inline void memalloc_noreclaim_restore(unsigned int flags)
 	current->flags = (current->flags & ~PF_MEMALLOC) | flags;
 }
 
+#ifdef CONFIG_MEMCG
+static inline struct mem_cgroup *memalloc_memcg_save(struct mem_cgroup *memcg)
+{

include/linux/sched/mm.h static inline void memalloc_noreclaim_restore(unsigned int flags) · line 263

Quoted 10 lines
include/linux/sched/mm.h +10 -0
+	struct mem_cgroup *old_memcg = current->target_memcg;
+
+	current->target_memcg = memcg;
+	return old_memcg;
+}
+
+static inline void memalloc_memcg_restore(struct mem_cgroup *memcg)
+{
+	current->target_memcg = memcg;
+}

The use_mm() and friends naming scheme would be better here:
memalloc_use_memcg(), memalloc_unuse_memcg(), current->active_memcg

Quoted 13 lines
include/linux/slab.h +9 -0
@@ -375,6 +376,27 @@ static __always_inline void kfree_bulk(size_t size, void **p)
 	kmem_cache_free_bulk(NULL, size, p);
 }
 
+/*
+ * Calling kmem_cache_alloc_memcg implicitly assumes that the caller wants
+ * a __GFP_ACCOUNT allocation. However if memcg is NULL then
+ * kmem_cache_alloc_memcg is same as kmem_cache_alloc.
+ */
+static __always_inline void *kmem_cache_alloc_memcg(struct kmem_cache *cachep,
+						    gfp_t flags,
+						    struct mem_cgroup *memcg)
+{

include/linux/slab.h static __always_inline void kfree_bulk(size_t size, void **p) · line 397

Quoted 10 lines
include/linux/slab.h +10 -0
+	struct mem_cgroup *old_memcg;
+	void *ptr;
+
+	if (!memcg)
+		return kmem_cache_alloc(cachep, flags);
+
+	old_memcg = memalloc_memcg_save(memcg);
+	ptr = kmem_cache_alloc(cachep, flags | __GFP_ACCOUNT);
+	memalloc_memcg_restore(old_memcg);
+	return ptr;

I'm not a big fan of these functions as an interface because it implies that kmem_cache_alloc() et al wouldn't charge a memcg - but they do, just using current's memcg.

It's also a lot of churn to duplicate all the various slab functions.

Can you please inline the save/restore (or use/unuse) functions into the callsites? If you make them handle NULL as parameters, it merely adds two bracketing lines around the allocation call in the callsites, which I think would be better to understand - in particular with a comment on why we are charging *that* group instead of current's.

Quoted 18 lines
mm/memcontrol.c +14 -0
+static __always_inline struct mem_cgroup *get_mem_cgroup(
+				struct mem_cgroup *memcg, struct mm_struct *mm)
+{
+	if (unlikely(memcg)) {
+		rcu_read_lock();
+		if (css_tryget_online(&memcg->css)) {
+			rcu_read_unlock();
+			return memcg;
+		}
+		rcu_read_unlock();
+	}
+	return get_mem_cgroup_from_mm(mm);
+}
+
 /**
  * mem_cgroup_iter - iterate over memory cgroup hierarchy
  * @root: hierarchy root

mm/memcontrol.c struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep) · line 2277

Quoted 5 lines
mm/memcontrol.c +1 -1
@@ -2260,7 +2274,7 @@ struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep)
 	if (current->memcg_kmem_skip_account)
 		return cachep;
 
-	memcg = get_mem_cgroup_from_mm(current->mm);
+	memcg = get_mem_cgroup(current->target_memcg, current->mm);

get_mem_cgroup_from_current(), which uses current->active_memcg if set and current->mm->memcg otherwise, would be a nicer abstraction IMO.

#3 lore raw

Re: [PATCH 1/3] mm: memcg: remote memcg charging for kmem allocations

Quoted 6 lines · Johannes Weiner
Quoted 4 lines · Shakeel Butt
include/linux/sched/mm.h +0 -0
@@ -248,6 +248,30 @@ static inline void memalloc_noreclaim_restore(unsigned int flags)
      current->flags = (current->flags & ~PF_MEMALLOC) | flags;
 }
 
Quoted 17 lines

include/linux/sched/mm.h static inline void memalloc_noreclaim_restore(unsigned int flags) · line 263

Quoted 13 lines
include/linux/sched/mm.h +13 -0
+#ifdef CONFIG_MEMCG
+static inline struct mem_cgroup *memalloc_memcg_save(struct mem_cgroup *memcg)
+{
+     struct mem_cgroup *old_memcg = current->target_memcg;
+
+     current->target_memcg = memcg;
+     return old_memcg;
+}
+
+static inline void memalloc_memcg_restore(struct mem_cgroup *memcg)
+{
+     current->target_memcg = memcg;
+}

The use_mm() and friends naming scheme would be better here:
memalloc_use_memcg(), memalloc_unuse_memcg(), current->active_memcg

Ack. Though do you still think <linux/sched/mm.h> is the right place for these functions?

Quoted 28 lines
Quoted 13 lines
include/linux/slab.h +9 -0
@@ -375,6 +376,27 @@ static __always_inline void kfree_bulk(size_t size, void **p)
      kmem_cache_free_bulk(NULL, size, p);
 }
 
+/*
+ * Calling kmem_cache_alloc_memcg implicitly assumes that the caller wants
+ * a __GFP_ACCOUNT allocation. However if memcg is NULL then
+ * kmem_cache_alloc_memcg is same as kmem_cache_alloc.
+ */
+static __always_inline void *kmem_cache_alloc_memcg(struct kmem_cache *cachep,
+                                                 gfp_t flags,
+                                                 struct mem_cgroup *memcg)
+{

include/linux/slab.h static __always_inline void kfree_bulk(size_t size, void **p) · line 397

Quoted 10 lines
include/linux/slab.h +10 -0
+     struct mem_cgroup *old_memcg;
+     void *ptr;
+
+     if (!memcg)
+             return kmem_cache_alloc(cachep, flags);
+
+     old_memcg = memalloc_memcg_save(memcg);
+     ptr = kmem_cache_alloc(cachep, flags | __GFP_ACCOUNT);
+     memalloc_memcg_restore(old_memcg);
+     return ptr;

I'm not a big fan of these functions as an interface because it implies that kmem_cache_alloc() et al wouldn't charge a memcg - but they do, just using current's memcg.

Quoted 8 lines

It's also a lot of churn to duplicate all the various slab functions.

Can you please inline the save/restore (or use/unuse) functions into the callsites? If you make them handle NULL as parameters, it merely adds two bracketing lines around the allocation call in the callsites, which I think would be better to understand - in particular with a comment on why we are charging *that* group instead of current's.

Ack.

Quoted 21 lines
Quoted 21 lines
mm/memcontrol.c +14 -0
+static __always_inline struct mem_cgroup *get_mem_cgroup(
+                             struct mem_cgroup *memcg, struct mm_struct *mm)
+{
+     if (unlikely(memcg)) {
+             rcu_read_lock();
+             if (css_tryget_online(&memcg->css)) {
+                     rcu_read_unlock();
+                     return memcg;
+             }
+             rcu_read_unlock();
+     }
+     return get_mem_cgroup_from_mm(mm);
+}
+
 /**
  * mem_cgroup_iter - iterate over memory cgroup hierarchy
  * @root: hierarchy root
@@ -2260,7 +2274,7 @@ struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep)
      if (current->memcg_kmem_skip_account)
              return cachep;
 
Quoted 5 lines

Review struct kmem_cache *memcg_kmem_get_cache(struct kmem_cache *cachep) · line 2277

Quoted 2 lines
(quoted diff) +1 -1
-     memcg = get_mem_cgroup_from_mm(current->mm);
+     memcg = get_mem_cgroup(current->target_memcg, current->mm);

get_mem_cgroup_from_current(), which uses current->active_memcg if set and current->mm->memcg otherwise, would be a nicer abstraction IMO.

Ack.

thanks,
Shakeel

maintainer
#4 lore raw

Re: [PATCH 1/3] mm: memcg: remote memcg charging for kmem allocations

Quoted 25 lines · Shakeel Butt
Quoted 6 lines · Johannes Weiner
Quoted 4 lines · Shakeel Butt
include/linux/sched/mm.h +0 -0
@@ -248,6 +248,30 @@ static inline void memalloc_noreclaim_restore(unsigned int flags)
      current->flags = (current->flags & ~PF_MEMALLOC) | flags;
 }
 
Quoted 17 lines

include/linux/sched/mm.h static inline void memalloc_noreclaim_restore(unsigned int flags) · line 263

Quoted 13 lines
include/linux/sched/mm.h +13 -0
+#ifdef CONFIG_MEMCG
+static inline struct mem_cgroup *memalloc_memcg_save(struct mem_cgroup *memcg)
+{
+     struct mem_cgroup *old_memcg = current->target_memcg;
+
+     current->target_memcg = memcg;
+     return old_memcg;
+}
+
+static inline void memalloc_memcg_restore(struct mem_cgroup *memcg)
+{
+     current->target_memcg = memcg;
+}

The use_mm() and friends naming scheme would be better here:
memalloc_use_memcg(), memalloc_unuse_memcg(), current->active_memcg

Quoted 2 lines

Ack. Though do you still think <linux/sched/mm.h> is the right place for these functions?

Yeah, since it has the memalloc_* prefix, we should keep it there.

If we did use_memcg(), unuse_memcg(), I'd put it into memcontrol.h, but it seems a little terse; memalloc adds valuable context, IMO.

Thanks Shakeel!

#5 lore raw

PATCH v6 2/3 fs: fsnotify: account fsnotify metadata to kmemcg

In reply to Shakeel Butt

A lot of memory can be consumed by the events generated for the huge or unlimited queues if there is either no or slow listener. This can cause system level memory pressure or OOMs. So, it's better to account the fsnotify kmem caches to the memcg of the listener.

There are seven fsnotify kmem caches and among them allocations from dnotify_struct_cache, dnotify_mark_cache, fanotify_mark_cache and inotify_inode_mark_cachep happens in the context of syscall from the listener. So, SLAB_ACCOUNT is enough for these caches.

The objects from fsnotify_mark_connector_cachep are not accounted as they are small compared to the notification mark or events and it is unclear whom to account connector to since it is shared by all events attached to the inode.

The allocations from the event caches happen in the context of the event producer. For such caches we will need to remote charge the allocations to the listener's memcg. Thus we save the memcg reference in the fsnotify_group structure of the listener.

This patch has also moved the members of fsnotify_group to keep the size same, at least for 64 bit build, even with additional member by filling the holes.

Cc Michal Hocko <[email protected]>
Cc Amir Goldstein <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc David Rientjes <[email protected]>
Cc Joonsoo Kim <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>

---
Changelog since v5:
- None

Changelog since v4:
- Fixed the build for CONFIG_MEMCG=n

Changelog since v3:
- Rebased over Jan's patches.
- Some cleanup based on Amir's comments.

Changelog since v2:
- None

Changelog since v1:
- no more charging fsnotify_mark_connector objects
- Fixed the build for SLOB

 fs/notify/dnotify/dnotify.c          |  5 +++--
 fs/notify/fanotify/fanotify.c        |  6 ++++--
 fs/notify/fanotify/fanotify_user.c   |  5 ++++-
 fs/notify/group.c                    |  6 ++++++
 fs/notify/inotify/inotify_fsnotify.c |  2 +-
 fs/notify/inotify/inotify_user.c     |  5 ++++-
 include/linux/fsnotify_backend.h     | 12 ++++++++----
 include/linux/memcontrol.h           |  7 +++++++
 mm/memcontrol.c                      | 15 +++++++++++++--
 9 files changed, 50 insertions(+), 13 deletions(-)
fs/notify/dnotify/dnotify.c +3 -2
index e2bea2ac5dfb..a6365e6bc047 100644
@@ -384,8 +384,9 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
 
 static int __init dnotify_init(void)
 {
-	dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC);
-	dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC);
+	dnotify_struct_cache = KMEM_CACHE(dnotify_struct,
+					  SLAB_PANIC|SLAB_ACCOUNT);
+	dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT);
 
 	dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops);
 	if (IS_ERR(dnotify_group))
fs/notify/fanotify/fanotify.c +4 -2
index f90842efea13..c8d6e37a4855 100644
@@ -154,14 +154,16 @@ struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group,
 	if (fanotify_is_perm_event(mask)) {
 		struct fanotify_perm_event_info *pevent;
 
-		pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
+		pevent = kmem_cache_alloc_memcg(fanotify_perm_event_cachep, gfp,
+						group->memcg);
 		if (!pevent)
 			return NULL;
 		event = &pevent->fae;
 		pevent->response = 0;
 		goto init;
 	}
-	event = kmem_cache_alloc(fanotify_event_cachep, gfp);
+	event = kmem_cache_alloc_memcg(fanotify_event_cachep, gfp,
+				       group->memcg);
 	if (!event)
 		return NULL;
 init: __maybe_unused
fs/notify/fanotify/fanotify_user.c +4 -1
index ec4d8c59d0e3..0cf45041dc32 100644
@@ -16,6 +16,7 @@
 #include <linux/uaccess.h>
 #include <linux/compat.h>
 #include <linux/sched/signal.h>
+#include <linux/memcontrol.h>
 
 #include <asm/ioctls.h>
 
@@ -756,6 +757,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 
 	group->fanotify_data.user = user;
 	atomic_inc(&user->fanotify_listeners);
+	group->memcg = get_mem_cgroup_from_mm(current->mm);
 
 	oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL);
 	if (unlikely(!oevent)) {
@@ -957,7 +959,8 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
  */
 static int __init fanotify_user_setup(void)
 {
-	fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
+	fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
+					 SLAB_PANIC|SLAB_ACCOUNT);
 	fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC);
 	if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) {
 		fanotify_perm_event_cachep =
fs/notify/group.c +6 -0
index aa5468f23e45..300fc0f62115 100644
@@ -22,6 +22,7 @@
 #include <linux/srcu.h>
 #include <linux/rculist.h>
 #include <linux/wait.h>
+#include <linux/memcontrol.h>
 
 #include <linux/fsnotify_backend.h>
 #include "fsnotify.h"
@@ -36,6 +37,11 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
 	if (group->ops->free_group_priv)
 		group->ops->free_group_priv(group);
 
+#ifdef CONFIG_MEMCG
+	if (group->memcg)
+		css_put(&group->memcg->css);
+#endif
+
 	kfree(group);
 }
 
fs/notify/inotify/inotify_fsnotify.c +1 -1
index 9ab6dde38a14..749e76ea7793 100644
@@ -98,7 +98,7 @@ int inotify_handle_event(struct fsnotify_group *group,
 	i_mark = container_of(inode_mark, struct inotify_inode_mark,
 			      fsn_mark);
 
-	event = kmalloc(alloc_len, GFP_KERNEL);
+	event = kmalloc_memcg(alloc_len, GFP_KERNEL, group->memcg);
 	if (unlikely(!event)) {
 		/*
 		 * Treat lost event due to ENOMEM the same way as queue
fs/notify/inotify/inotify_user.c +4 -1
index 1cf5b779d862..749c46ababa0 100644
@@ -38,6 +38,7 @@
 #include <linux/uaccess.h>
 #include <linux/poll.h>
 #include <linux/wait.h>
+#include <linux/memcontrol.h>
 
 #include "inotify.h"
 #include "../fdinfo.h"
@@ -636,6 +637,7 @@ static struct fsnotify_group *inotify_new_group(unsigned int max_events)
 	oevent->name_len = 0;
 
 	group->max_events = max_events;
+	group->memcg = get_mem_cgroup_from_mm(current->mm);
 
 	spin_lock_init(&group->inotify_data.idr_lock);
 	idr_init(&group->inotify_data.idr);
@@ -808,7 +810,8 @@ static int __init inotify_user_setup(void)
 
 	BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
 
-	inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
+	inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark,
+					       SLAB_PANIC|SLAB_ACCOUNT);
 
 	inotify_max_queued_events = 16384;
 	init_user_ns.ucount_max[UCOUNT_INOTIFY_INSTANCES] = 128;
include/linux/fsnotify_backend.h +8 -4
index b38964a7a521..a0c4790c5302 100644
@@ -84,6 +84,8 @@ struct fsnotify_event_private_data;
 struct fsnotify_fname;
 struct fsnotify_iter_info;
 
+struct mem_cgroup;
+
 /*
  * Each group much define these ops.  The fsnotify infrastructure will call
  * these operations for each relevant group.
@@ -127,6 +129,8 @@ struct fsnotify_event {
  * everything will be cleaned up.
  */
 struct fsnotify_group {
+	const struct fsnotify_ops *ops;	/* how this group handles things */
+
 	/*
 	 * How the refcnt is used is up to each group.  When the refcnt hits 0
 	 * fsnotify will clean up all of the resources associated with this group.
@@ -137,8 +141,6 @@ struct fsnotify_group {
 	 */
 	refcount_t refcnt;		/* things with interest in this group */
 
-	const struct fsnotify_ops *ops;	/* how this group handles things */
-
 	/* needed to send notification to userspace */
 	spinlock_t notification_lock;		/* protect the notification_list */
 	struct list_head notification_list;	/* list of event_holder this group needs to send to userspace */
@@ -160,6 +162,8 @@ struct fsnotify_group {
 	atomic_t num_marks;		/* 1 for each mark and 1 for not being
 					 * past the point of no return when freeing
 					 * a group */
+	atomic_t user_waits;		/* Number of tasks waiting for user
+					 * response */
 	struct list_head marks_list;	/* all inode marks for this group */
 
 	struct fasync_struct *fsn_fa;    /* async notification */
@@ -167,8 +171,8 @@ struct fsnotify_group {
 	struct fsnotify_event *overflow_event;	/* Event we queue when the
 						 * notification list is too
 						 * full */
-	atomic_t user_waits;		/* Number of tasks waiting for user
-					 * response */
+
+	struct mem_cgroup *memcg;	/* memcg to charge allocations */
 
 	/* groups can define private fields here or use the void *private */
 	union {
include/linux/memcontrol.h +7 -0
index 3607913032be..6c857be8a9b7 100644
@@ -378,6 +378,8 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *, struct pglist_data *);
 bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);
 struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
 
+struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm);
+
 static inline
 struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
 	return css ? container_of(css, struct mem_cgroup, css) : NULL;
@@ -857,6 +859,11 @@ static inline bool task_in_mem_cgroup(struct task_struct *task,
 	return true;
 }
 
+static inline struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
+{
+	return NULL;
+}
+
 static inline void mem_cgroup_put(struct mem_cgroup *memcg)
 {
 }
mm/memcontrol.c +13 -2
index 08bfb8c2411b..c481e661e051 100644
@@ -678,9 +678,20 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p)
 }
 EXPORT_SYMBOL(mem_cgroup_from_task);
 
-static struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
+/**
+ * get_mem_cgroup_from_mm: Obtain a reference on given mm_struct's memcg.
+ * @mm: mm from which memcg should be extracted. It can be NULL.
+ *
+ * Obtain a reference on mm->memcg and returns it if successful. Otherwise
+ * root_mem_cgroup is returned. However if mem_cgroup is disabled, NULL is
+ * returned.
+ */
+struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
 {
-	struct mem_cgroup *memcg = NULL;
+	struct mem_cgroup *memcg;
+
+	if (mem_cgroup_disabled())
+		return NULL;
 
 	rcu_read_lock();
 	do {
Signature · 1 line
2.18.0.rc1.244.gcf134e6275-goog
#6 lore raw

Re: [PATCH 2/3] fs: fsnotify: account fsnotify metadata to kmemcg

Quoted 120 lines · Shakeel Butt

A lot of memory can be consumed by the events generated for the huge or unlimited queues if there is either no or slow listener. This can cause system level memory pressure or OOMs. So, it's better to account the fsnotify kmem caches to the memcg of the listener.

There are seven fsnotify kmem caches and among them allocations from dnotify_struct_cache, dnotify_mark_cache, fanotify_mark_cache and inotify_inode_mark_cachep happens in the context of syscall from the listener. So, SLAB_ACCOUNT is enough for these caches.

The objects from fsnotify_mark_connector_cachep are not accounted as they are small compared to the notification mark or events and it is unclear whom to account connector to since it is shared by all events attached to the inode.

The allocations from the event caches happen in the context of the event producer. For such caches we will need to remote charge the allocations to the listener's memcg. Thus we save the memcg reference in the fsnotify_group structure of the listener.

This patch has also moved the members of fsnotify_group to keep the size same, at least for 64 bit build, even with additional member by filling the holes.

Cc Michal Hocko <[email protected]>
Cc Amir Goldstein <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc David Rientjes <[email protected]>
Cc Joonsoo Kim <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>

---
Changelog since v5:
- None

Changelog since v4:
- Fixed the build for CONFIG_MEMCG=n

Changelog since v3:
- Rebased over Jan's patches.
- Some cleanup based on Amir's comments.

Changelog since v2:
- None

Changelog since v1:
- no more charging fsnotify_mark_connector objects
- Fixed the build for SLOB

 fs/notify/dnotify/dnotify.c          |  5 +++--
 fs/notify/fanotify/fanotify.c        |  6 ++++--
 fs/notify/fanotify/fanotify_user.c   |  5 ++++-
 fs/notify/group.c                    |  6 ++++++
 fs/notify/inotify/inotify_fsnotify.c |  2 +-
 fs/notify/inotify/inotify_user.c     |  5 ++++-
 include/linux/fsnotify_backend.h     | 12 ++++++++----
 include/linux/memcontrol.h           |  7 +++++++
 mm/memcontrol.c                      | 15 +++++++++++++--
 9 files changed, 50 insertions(+), 13 deletions(-)
fs/notify/dnotify/dnotify.c +3 -2
index e2bea2ac5dfb..a6365e6bc047 100644
@@ -384,8 +384,9 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
 
 static int __init dnotify_init(void)
 {
-       dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC);
-       dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC);
+       dnotify_struct_cache = KMEM_CACHE(dnotify_struct,
+                                         SLAB_PANIC|SLAB_ACCOUNT);
+       dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT);
 
        dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops);
        if (IS_ERR(dnotify_group))
fs/notify/fanotify/fanotify.c +4 -2
index f90842efea13..c8d6e37a4855 100644
@@ -154,14 +154,16 @@ struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group,
        if (fanotify_is_perm_event(mask)) {
                struct fanotify_perm_event_info *pevent;
 
-               pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
+               pevent = kmem_cache_alloc_memcg(fanotify_perm_event_cachep, gfp,
+                                               group->memcg);
                if (!pevent)
                        return NULL;
                event = &pevent->fae;
                pevent->response = 0;
                goto init;
        }
-       event = kmem_cache_alloc(fanotify_event_cachep, gfp);
+       event = kmem_cache_alloc_memcg(fanotify_event_cachep, gfp,
+                                      group->memcg);
        if (!event)
                return NULL;
 init: __maybe_unused
fs/notify/fanotify/fanotify_user.c +1 -0
index ec4d8c59d0e3..0cf45041dc32 100644
@@ -16,6 +16,7 @@
 #include <linux/uaccess.h>
 #include <linux/compat.h>
 #include <linux/sched/signal.h>
+#include <linux/memcontrol.h>
 
 #include <asm/ioctls.h>
 

fs/notify/fanotify/fanotify_user.c SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) · line 761

Quoted 5 lines
fs/notify/fanotify/fanotify_user.c +1 -0
@@ -756,6 +757,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 
        group->fanotify_data.user = user;
        atomic_inc(&user->fanotify_listeners);
+       group->memcg = get_mem_cgroup_from_mm(current->mm);
 

It seem to me that you should export a wrapper to modules with the mem_cgroup_ prefix and not sure that need to pass current->mm to this wrapper.

Quoted 25 lines
fs/notify/fanotify/fanotify_user.c +2 -1
        oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL);
        if (unlikely(!oevent)) {
@@ -957,7 +959,8 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
  */
 static int __init fanotify_user_setup(void)
 {
-       fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
+       fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
+                                        SLAB_PANIC|SLAB_ACCOUNT);
        fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC);
        if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) {
                fanotify_perm_event_cachep =
fs/notify/group.c +1 -0
index aa5468f23e45..300fc0f62115 100644
@@ -22,6 +22,7 @@
 #include <linux/srcu.h>
 #include <linux/rculist.h>
 #include <linux/wait.h>
+#include <linux/memcontrol.h>
 
 #include <linux/fsnotify_backend.h>
 #include "fsnotify.h"

fs/notify/group.c static void fsnotify_final_destroy_group(struct fsnotify_group *group) · line 44

Quoted 8 lines
fs/notify/group.c +5 -0
@@ -36,6 +37,11 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
        if (group->ops->free_group_priv)
                group->ops->free_group_priv(group);
 
+#ifdef CONFIG_MEMCG
+       if (group->memcg)
+               css_put(&group->memcg->css);
+#endif
+

This looks very much like an internal implementation detail that has no business in an external module. I see evidence that you have used mem_cgroup_put() in the patch at some point and I agree that you need to export a pair of matching helpers to external modules.

Thanks,
Amir.

#7 lore raw

Re: [PATCH 2/3] fs: fsnotify: account fsnotify metadata to kmemcg

Quoted 123 lines · Amir Goldstein
Quoted 121 lines · Shakeel Butt

A lot of memory can be consumed by the events generated for the huge or unlimited queues if there is either no or slow listener. This can cause system level memory pressure or OOMs. So, it's better to account the fsnotify kmem caches to the memcg of the listener.

There are seven fsnotify kmem caches and among them allocations from dnotify_struct_cache, dnotify_mark_cache, fanotify_mark_cache and inotify_inode_mark_cachep happens in the context of syscall from the listener. So, SLAB_ACCOUNT is enough for these caches.

The objects from fsnotify_mark_connector_cachep are not accounted as they are small compared to the notification mark or events and it is unclear whom to account connector to since it is shared by all events attached to the inode.

The allocations from the event caches happen in the context of the event producer. For such caches we will need to remote charge the allocations to the listener's memcg. Thus we save the memcg reference in the fsnotify_group structure of the listener.

This patch has also moved the members of fsnotify_group to keep the size same, at least for 64 bit build, even with additional member by filling the holes.

Cc Michal Hocko <[email protected]>
Cc Amir Goldstein <[email protected]>
Cc Christoph Lameter <[email protected]>
Cc Pekka Enberg <[email protected]>
Cc David Rientjes <[email protected]>
Cc Joonsoo Kim <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Mel Gorman <[email protected]>
Cc Vlastimil Babka <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>

---
Changelog since v5:
- None

Changelog since v4:
- Fixed the build for CONFIG_MEMCG=n

Changelog since v3:
- Rebased over Jan's patches.
- Some cleanup based on Amir's comments.

Changelog since v2:
- None

Changelog since v1:
- no more charging fsnotify_mark_connector objects
- Fixed the build for SLOB

 fs/notify/dnotify/dnotify.c          |  5 +++--
 fs/notify/fanotify/fanotify.c        |  6 ++++--
 fs/notify/fanotify/fanotify_user.c   |  5 ++++-
 fs/notify/group.c                    |  6 ++++++
 fs/notify/inotify/inotify_fsnotify.c |  2 +-
 fs/notify/inotify/inotify_user.c     |  5 ++++-
 include/linux/fsnotify_backend.h     | 12 ++++++++----
 include/linux/memcontrol.h           |  7 +++++++
 mm/memcontrol.c                      | 15 +++++++++++++--
 9 files changed, 50 insertions(+), 13 deletions(-)
fs/notify/dnotify/dnotify.c +3 -2
index e2bea2ac5dfb..a6365e6bc047 100644
@@ -384,8 +384,9 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
 
 static int __init dnotify_init(void)
 {
-       dnotify_struct_cache = KMEM_CACHE(dnotify_struct, SLAB_PANIC);
-       dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC);
+       dnotify_struct_cache = KMEM_CACHE(dnotify_struct,
+                                         SLAB_PANIC|SLAB_ACCOUNT);
+       dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT);
 
        dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops);
        if (IS_ERR(dnotify_group))
fs/notify/fanotify/fanotify.c +4 -2
index f90842efea13..c8d6e37a4855 100644
@@ -154,14 +154,16 @@ struct fanotify_event_info *fanotify_alloc_event(struct fsnotify_group *group,
        if (fanotify_is_perm_event(mask)) {
                struct fanotify_perm_event_info *pevent;
 
-               pevent = kmem_cache_alloc(fanotify_perm_event_cachep, gfp);
+               pevent = kmem_cache_alloc_memcg(fanotify_perm_event_cachep, gfp,
+                                               group->memcg);
                if (!pevent)
                        return NULL;
                event = &pevent->fae;
                pevent->response = 0;
                goto init;
        }
-       event = kmem_cache_alloc(fanotify_event_cachep, gfp);
+       event = kmem_cache_alloc_memcg(fanotify_event_cachep, gfp,
+                                      group->memcg);
        if (!event)
                return NULL;
 init: __maybe_unused
fs/notify/fanotify/fanotify_user.c +1 -0
index ec4d8c59d0e3..0cf45041dc32 100644
@@ -16,6 +16,7 @@
 #include <linux/uaccess.h>
 #include <linux/compat.h>
 #include <linux/sched/signal.h>
+#include <linux/memcontrol.h>
 
 #include <asm/ioctls.h>
 
@@ -756,6 +757,7 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
 
Quoted 9 lines

fs/notify/fanotify/fanotify_user.c SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags) · line 761

Quoted 4 lines
fs/notify/fanotify/fanotify_user.c +1 -0
        group->fanotify_data.user = user;
        atomic_inc(&user->fanotify_listeners);
+       group->memcg = get_mem_cgroup_from_mm(current->mm);
 

It seem to me that you should export a wrapper to modules with the mem_cgroup_ prefix and not sure that need to pass current->mm to this wrapper.

Thanks, I will test with fsnotify as module.

Quoted 28 lines
Quoted 28 lines
fs/notify/fanotify/fanotify_user.c +2 -1
        oevent = fanotify_alloc_event(group, NULL, FS_Q_OVERFLOW, NULL);
        if (unlikely(!oevent)) {
@@ -957,7 +959,8 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
  */
 static int __init fanotify_user_setup(void)
 {
-       fanotify_mark_cache = KMEM_CACHE(fsnotify_mark, SLAB_PANIC);
+       fanotify_mark_cache = KMEM_CACHE(fsnotify_mark,
+                                        SLAB_PANIC|SLAB_ACCOUNT);
        fanotify_event_cachep = KMEM_CACHE(fanotify_event_info, SLAB_PANIC);
        if (IS_ENABLED(CONFIG_FANOTIFY_ACCESS_PERMISSIONS)) {
                fanotify_perm_event_cachep =
fs/notify/group.c +1 -0
index aa5468f23e45..300fc0f62115 100644
@@ -22,6 +22,7 @@
 #include <linux/srcu.h>
 #include <linux/rculist.h>
 #include <linux/wait.h>
+#include <linux/memcontrol.h>
 
 #include <linux/fsnotify_backend.h>
 #include "fsnotify.h"
@@ -36,6 +37,11 @@ static void fsnotify_final_destroy_group(struct fsnotify_group *group)
        if (group->ops->free_group_priv)
                group->ops->free_group_priv(group);
 
Quoted 11 lines

fs/notify/group.c static void fsnotify_final_destroy_group(struct fsnotify_group *group) · line 44

Quoted 5 lines
fs/notify/group.c +5 -0
+#ifdef CONFIG_MEMCG
+       if (group->memcg)
+               css_put(&group->memcg->css);
+#endif
+

This looks very much like an internal implementation detail that has no business in an external module. I see evidence that you have used mem_cgroup_put() in the patch at some point and I agree that you need to export a pair of matching helpers to external modules.

Do not worry. Andrew will change this to mem_cgroup_put(). Basically mem_cgroup_put() was defined by still-in-review patch series by Roman. There were build failure reports where someone was taking this series either without Roman's series or applying series out of order.

thanks,
Shakeel

#8 lore raw

PATCH v6 3/3 fs, mm: account buffer_head to kmemcg

In reply to Shakeel Butt

The buffer_head can consume a significant amount of system memory and is directly related to the amount of page cache. In our production environment we have observed that a lot of machines are spending a significant amount of memory as buffer_head and can not be left as system memory overhead.

Charging buffer_head is not as simple as adding __GFP_ACCOUNT to the allocation. The buffer_heads can be allocated in a memcg different from the memcg of the page for which buffer_heads are being allocated. One concrete example is memory reclaim. The reclaim can trigger I/O of pages of any memcg on the system. So, the right way to charge buffer_head is to extract the memcg from the page for which buffer_heads are being allocated and then use targeted memcg charging API.

Cc Jan Kara <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>
---
 fs/buffer.c                | 14 +++++++++++++-
 include/linux/memcontrol.h |  7 +++++++
 mm/memcontrol.c            | 21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
fs/buffer.c +14 -0
index 8194e3049fc5..26389b7a3cab 100644
@@ -815,10 +815,17 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
 	struct buffer_head *bh, *head;
 	gfp_t gfp = GFP_NOFS;
 	long offset;
+	struct mem_cgroup *old_memcg;
+	struct mem_cgroup *memcg = get_mem_cgroup_from_page(page);
 
 	if (retry)
 		gfp |= __GFP_NOFAIL;
 
+	if (memcg) {
+		gfp |= __GFP_ACCOUNT;
+		old_memcg = memalloc_memcg_save(memcg);
+	}
+
 	head = NULL;
 	offset = PAGE_SIZE;
 	while ((offset -= size) >= 0) {
@@ -835,6 +842,11 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
 		/* Link the buffer to its page */
 		set_bh_page(bh, page, offset);
 	}
+out:
+	if (memcg) {
+		memalloc_memcg_restore(old_memcg);
+#ifdef CONFIG_MEMCG
+		css_put(&memcg->css);
+#endif
+	}
 	return head;

/*
* In case anything failed, we just free everything we got.
@@ -848,7 +860,7 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
} while (head);
}

- return NULL;
+ goto out;
}
EXPORT_SYMBOL_GPL(alloc_page_buffers);

include/linux/memcontrol.h +7 -0
index 6c857be8a9b7..d53609978eb7 100644
@@ -380,6 +380,8 @@ struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
 
 struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm);
 
+struct mem_cgroup *get_mem_cgroup_from_page(struct page *page);
+
 static inline
 struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
 	return css ? container_of(css, struct mem_cgroup, css) : NULL;
@@ -864,6 +866,11 @@ static inline struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
 	return NULL;
 }
 
+static inline struct mem_cgroup *get_mem_cgroup_from_page(struct page *page)
+{
+	return NULL;
+}
+
 static inline void mem_cgroup_put(struct mem_cgroup *memcg)
 {
 }
mm/memcontrol.c +21 -0
index c481e661e051..f9a9a79117b9 100644
@@ -712,6 +712,27 @@ struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
 	return memcg;
 }
 
+/**
+ * get_mem_cgroup_from_page: Obtain a reference on given page's memcg.
+ * @page: page from which memcg should be extracted.
+ *
+ * Obtain a reference on page->memcg and returns it if successful. Otherwise
+ * NULL is returned.
+ */
+struct mem_cgroup *get_mem_cgroup_from_page(struct page *page)
+{
+	struct mem_cgroup *memcg = page->mem_cgroup;
+
+	if (mem_cgroup_disabled() || !memcg)
+		return NULL;
+
+	rcu_read_lock();
+	if (!css_tryget_online(&memcg->css))
+		memcg = NULL;
+	rcu_read_unlock();
+	return memcg;
+}
+
 static __always_inline struct mem_cgroup *get_mem_cgroup(
 				struct mem_cgroup *memcg, struct mm_struct *mm)
 {
Signature · 1 line
2.18.0.rc1.244.gcf134e6275-goog
maintainer
#9 lore raw

Re: [PATCH 3/3] fs, mm: account buffer_head to kmemcg

Quoted 36 lines · Shakeel Butt

The buffer_head can consume a significant amount of system memory and is directly related to the amount of page cache. In our production environment we have observed that a lot of machines are spending a significant amount of memory as buffer_head and can not be left as system memory overhead.

Charging buffer_head is not as simple as adding __GFP_ACCOUNT to the allocation. The buffer_heads can be allocated in a memcg different from the memcg of the page for which buffer_heads are being allocated. One concrete example is memory reclaim. The reclaim can trigger I/O of pages of any memcg on the system. So, the right way to charge buffer_head is to extract the memcg from the page for which buffer_heads are being allocated and then use targeted memcg charging API.

Cc Jan Kara <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>
---
 fs/buffer.c                | 14 +++++++++++++-
 include/linux/memcontrol.h |  7 +++++++
 mm/memcontrol.c            | 21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
fs/buffer.c +0 -0
index 8194e3049fc5..26389b7a3cab 100644
@@ -815,10 +815,17 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
 	struct buffer_head *bh, *head;
 	gfp_t gfp = GFP_NOFS;
 	long offset;

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 827

Quoted 10 lines
fs/buffer.c +6 -0
+	struct mem_cgroup *old_memcg;
+	struct mem_cgroup *memcg = get_mem_cgroup_from_page(page);
 
 	if (retry)
 		gfp |= __GFP_NOFAIL;
 
+	if (memcg) {
+		gfp |= __GFP_ACCOUNT;
+		old_memcg = memalloc_memcg_save(memcg);
+	}

Please move the get_mem_cgroup_from_page() call out of the declarations and down to right before the if (memcg) branch.

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 850

Quoted 13 lines
fs/buffer.c +6 -0
 	head = NULL;
 	offset = PAGE_SIZE;
 	while ((offset -= size) >= 0) {
@@ -835,6 +842,11 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
 		/* Link the buffer to its page */
 		set_bh_page(bh, page, offset);
 	}
+out:
+	if (memcg) {
+		memalloc_memcg_restore(old_memcg);
+#ifdef CONFIG_MEMCG
+		css_put(&memcg->css);
+#endif

Please add a put_mem_cgroup() ;)

Otherwise this looks fine to me.

#10 lore raw

Re: [PATCH 3/3] fs, mm: account buffer_head to kmemcg

Quoted 51 lines · Johannes Weiner
Quoted 36 lines · Shakeel Butt

The buffer_head can consume a significant amount of system memory and is directly related to the amount of page cache. In our production environment we have observed that a lot of machines are spending a significant amount of memory as buffer_head and can not be left as system memory overhead.

Charging buffer_head is not as simple as adding __GFP_ACCOUNT to the allocation. The buffer_heads can be allocated in a memcg different from the memcg of the page for which buffer_heads are being allocated. One concrete example is memory reclaim. The reclaim can trigger I/O of pages of any memcg on the system. So, the right way to charge buffer_head is to extract the memcg from the page for which buffer_heads are being allocated and then use targeted memcg charging API.

Cc Jan Kara <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>
---
 fs/buffer.c                | 14 +++++++++++++-
 include/linux/memcontrol.h |  7 +++++++
 mm/memcontrol.c            | 21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
fs/buffer.c +0 -0
index 8194e3049fc5..26389b7a3cab 100644
@@ -815,10 +815,17 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
 	struct buffer_head *bh, *head;
 	gfp_t gfp = GFP_NOFS;
 	long offset;

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 827

Quoted 10 lines
fs/buffer.c +6 -0
+	struct mem_cgroup *old_memcg;
+	struct mem_cgroup *memcg = get_mem_cgroup_from_page(page);
 
 	if (retry)
 		gfp |= __GFP_NOFAIL;
 
+	if (memcg) {
+		gfp |= __GFP_ACCOUNT;
+		old_memcg = memalloc_memcg_save(memcg);
+	}

Please move the get_mem_cgroup_from_page() call out of the declarations and down to right before the if (memcg) branch.

Quoted 15 lines

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 850

Quoted 13 lines
fs/buffer.c +6 -0
 	head = NULL;
 	offset = PAGE_SIZE;
 	while ((offset -= size) >= 0) {
@@ -835,6 +842,11 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
 		/* Link the buffer to its page */
 		set_bh_page(bh, page, offset);
 	}
+out:
+	if (memcg) {
+		memalloc_memcg_restore(old_memcg);
+#ifdef CONFIG_MEMCG
+		css_put(&memcg->css);
+#endif

Please add a put_mem_cgroup() ;)

I've added such helper by commit 8a34a8b7fd62 ("mm, oom: cgroup-aware OOM killer"). It's in the mm tree.

Thanks!

#11 lore raw

Re: [PATCH 3/3] fs, mm: account buffer_head to kmemcg

Quoted 69 lines · Roman Gushchin
Quoted 51 lines · Johannes Weiner
Quoted 36 lines · Shakeel Butt

The buffer_head can consume a significant amount of system memory and is directly related to the amount of page cache. In our production environment we have observed that a lot of machines are spending a significant amount of memory as buffer_head and can not be left as system memory overhead.

Charging buffer_head is not as simple as adding __GFP_ACCOUNT to the allocation. The buffer_heads can be allocated in a memcg different from the memcg of the page for which buffer_heads are being allocated. One concrete example is memory reclaim. The reclaim can trigger I/O of pages of any memcg on the system. So, the right way to charge buffer_head is to extract the memcg from the page for which buffer_heads are being allocated and then use targeted memcg charging API.

Cc Jan Kara <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>
---
 fs/buffer.c                | 14 +++++++++++++-
 include/linux/memcontrol.h |  7 +++++++
 mm/memcontrol.c            | 21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
fs/buffer.c +0 -0
index 8194e3049fc5..26389b7a3cab 100644
@@ -815,10 +815,17 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
    struct buffer_head *bh, *head;
    gfp_t gfp = GFP_NOFS;
    long offset;

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 827

Quoted 10 lines
fs/buffer.c +6 -0
+   struct mem_cgroup *old_memcg;
+   struct mem_cgroup *memcg = get_mem_cgroup_from_page(page);
 
    if (retry)
            gfp |= __GFP_NOFAIL;
 
+   if (memcg) {
+           gfp |= __GFP_ACCOUNT;
+           old_memcg = memalloc_memcg_save(memcg);
+   }

Please move the get_mem_cgroup_from_page() call out of the declarations and down to right before the if (memcg) branch.

Quoted 15 lines

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 850

Quoted 13 lines
fs/buffer.c +6 -0
    head = NULL;
    offset = PAGE_SIZE;
    while ((offset -= size) >= 0) {
@@ -835,6 +842,11 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
            /* Link the buffer to its page */
            set_bh_page(bh, page, offset);
    }
+out:
+   if (memcg) {
+           memalloc_memcg_restore(old_memcg);
+#ifdef CONFIG_MEMCG
+           css_put(&memcg->css);
+#endif

Please add a put_mem_cgroup() ;)

Quoted 3 lines

I've added such helper by commit 8a34a8b7fd62 ("mm, oom: cgroup-aware OOM killer"). It's in the mm tree.

I was using mem_cgroup_put() defined by Roman's patch but there were a lot of build failure reports where someone was taking this series without Roman's series or applying the series out of order. Andrew asked me to keep it like this and then he will convert these callsites into mem_cgroup_put() after making making sure Roman's series is applied in mm tree. I will recheck with him, how he wants to handle it now.

thanks,
Shakeel

#12 lore raw

Re: [PATCH 3/3] fs, mm: account buffer_head to kmemcg

Quoted 74 lines · Shakeel Butt
Quoted 69 lines · Roman Gushchin
Quoted 51 lines · Johannes Weiner
Quoted 36 lines · Shakeel Butt

The buffer_head can consume a significant amount of system memory and is directly related to the amount of page cache. In our production environment we have observed that a lot of machines are spending a significant amount of memory as buffer_head and can not be left as system memory overhead.

Charging buffer_head is not as simple as adding __GFP_ACCOUNT to the allocation. The buffer_heads can be allocated in a memcg different from the memcg of the page for which buffer_heads are being allocated. One concrete example is memory reclaim. The reclaim can trigger I/O of pages of any memcg on the system. So, the right way to charge buffer_head is to extract the memcg from the page for which buffer_heads are being allocated and then use targeted memcg charging API.

Cc Jan Kara <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>
---
 fs/buffer.c                | 14 +++++++++++++-
 include/linux/memcontrol.h |  7 +++++++
 mm/memcontrol.c            | 21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
fs/buffer.c +0 -0
index 8194e3049fc5..26389b7a3cab 100644
@@ -815,10 +815,17 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
    struct buffer_head *bh, *head;
    gfp_t gfp = GFP_NOFS;
    long offset;

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 827

Quoted 10 lines
fs/buffer.c +6 -0
+   struct mem_cgroup *old_memcg;
+   struct mem_cgroup *memcg = get_mem_cgroup_from_page(page);
 
    if (retry)
            gfp |= __GFP_NOFAIL;
 
+   if (memcg) {
+           gfp |= __GFP_ACCOUNT;
+           old_memcg = memalloc_memcg_save(memcg);
+   }

Please move the get_mem_cgroup_from_page() call out of the declarations and down to right before the if (memcg) branch.

Quoted 15 lines

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 850

Quoted 13 lines
fs/buffer.c +6 -0
    head = NULL;
    offset = PAGE_SIZE;
    while ((offset -= size) >= 0) {
@@ -835,6 +842,11 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
            /* Link the buffer to its page */
            set_bh_page(bh, page, offset);
    }
+out:
+   if (memcg) {
+           memalloc_memcg_restore(old_memcg);
+#ifdef CONFIG_MEMCG
+           css_put(&memcg->css);
+#endif

Please add a put_mem_cgroup() ;)

Quoted 3 lines

I've added such helper by commit 8a34a8b7fd62 ("mm, oom: cgroup-aware OOM killer"). It's in the mm tree.

Quoted 7 lines

I was using mem_cgroup_put() defined by Roman's patch but there were a lot of build failure reports where someone was taking this series without Roman's series or applying the series out of order. Andrew asked me to keep it like this and then he will convert these callsites into mem_cgroup_put() after making making sure Roman's series is applied in mm tree. I will recheck with him, how he wants to handle it now.

I can also split the introduction of mem_cgroup_put() into a separate commit, as it seems to be usable not only by the cgroup oom stuff. Please, let me know, if it's a preferred way to go.

Thanks!

#13 lore raw

Re: [PATCH 3/3] fs, mm: account buffer_head to kmemcg

Quoted 84 lines · Roman Gushchin
Quoted 74 lines · Shakeel Butt
Quoted 69 lines · Roman Gushchin
Quoted 51 lines · Johannes Weiner
Quoted 36 lines · Shakeel Butt

The buffer_head can consume a significant amount of system memory and is directly related to the amount of page cache. In our production environment we have observed that a lot of machines are spending a significant amount of memory as buffer_head and can not be left as system memory overhead.

Charging buffer_head is not as simple as adding __GFP_ACCOUNT to the allocation. The buffer_heads can be allocated in a memcg different from the memcg of the page for which buffer_heads are being allocated. One concrete example is memory reclaim. The reclaim can trigger I/O of pages of any memcg on the system. So, the right way to charge buffer_head is to extract the memcg from the page for which buffer_heads are being allocated and then use targeted memcg charging API.

Cc Jan Kara <[email protected]>
Cc Greg Thelen <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Vladimir Davydov <[email protected]>
Cc Alexander Viro <[email protected]>
Cc Andrew Morton <[email protected]>
---
 fs/buffer.c                | 14 +++++++++++++-
 include/linux/memcontrol.h |  7 +++++++
 mm/memcontrol.c            | 21 +++++++++++++++++++++
 3 files changed, 41 insertions(+), 1 deletion(-)
fs/buffer.c +0 -0
index 8194e3049fc5..26389b7a3cab 100644
@@ -815,10 +815,17 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
    struct buffer_head *bh, *head;
    gfp_t gfp = GFP_NOFS;
    long offset;

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 827

Quoted 10 lines
fs/buffer.c +6 -0
+   struct mem_cgroup *old_memcg;
+   struct mem_cgroup *memcg = get_mem_cgroup_from_page(page);
 
    if (retry)
            gfp |= __GFP_NOFAIL;
 
+   if (memcg) {
+           gfp |= __GFP_ACCOUNT;
+           old_memcg = memalloc_memcg_save(memcg);
+   }

Please move the get_mem_cgroup_from_page() call out of the declarations and down to right before the if (memcg) branch.

Quoted 15 lines

fs/buffer.c struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size, · line 850

Quoted 13 lines
fs/buffer.c +6 -0
    head = NULL;
    offset = PAGE_SIZE;
    while ((offset -= size) >= 0) {
@@ -835,6 +842,11 @@ struct buffer_head *alloc_page_buffers(struct page *page, unsigned long size,
            /* Link the buffer to its page */
            set_bh_page(bh, page, offset);
    }
+out:
+   if (memcg) {
+           memalloc_memcg_restore(old_memcg);
+#ifdef CONFIG_MEMCG
+           css_put(&memcg->css);
+#endif

Please add a put_mem_cgroup() ;)

Quoted 3 lines

I've added such helper by commit 8a34a8b7fd62 ("mm, oom: cgroup-aware OOM killer"). It's in the mm tree.

Quoted 7 lines

I was using mem_cgroup_put() defined by Roman's patch but there were a lot of build failure reports where someone was taking this series without Roman's series or applying the series out of order. Andrew asked me to keep it like this and then he will convert these callsites into mem_cgroup_put() after making making sure Roman's series is applied in mm tree. I will recheck with him, how he wants to handle it now.

Quoted 4 lines

I can also split the introduction of mem_cgroup_put() into a separate commit, as it seems to be usable not only by the cgroup oom stuff. Please, let me know, if it's a preferred way to go.

Oh I forgot to reply. Yes, let's do that, a separate patch to introduce mem_cgroup_put() which can used by remote charging and memcg aware oom-killer patches.

Shakeel

#14 lore raw

PATCH 1/2 mm: revert mem_cgroup_put() introduction

This patch should be folded into "mm, oom: cgroup-aware OOM killer".

---
 include/linux/memcontrol.h | 9 ---------
 1 file changed, 9 deletions(-)
include/linux/memcontrol.h +0 -9
index 3607913032be..cf1c3555328f 100644
@@ -383,11 +383,6 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
 	return css ? container_of(css, struct mem_cgroup, css) : NULL;
 }
 
-static inline void mem_cgroup_put(struct mem_cgroup *memcg)
-{
-	css_put(&memcg->css);
-}
-
 #define mem_cgroup_from_counter(counter, member)	\
 	container_of(counter, struct mem_cgroup, member)
 
@@ -857,10 +852,6 @@ static inline bool task_in_mem_cgroup(struct task_struct *task,
 	return true;
 }
 
-static inline void mem_cgroup_put(struct mem_cgroup *memcg)
-{
-}
-
 static inline struct mem_cgroup *
 mem_cgroup_iter(struct mem_cgroup *root,
 		struct mem_cgroup *prev,
Signature · 1 line
2.14.4
#15 lore raw

PATCH 2/2 mm: introduce mem_cgroup_put() helper

Introduce the mem_cgroup_put() helper, which helps to eliminate guarding memcg css release with "#ifdef CONFIG_MEMCG" in multiple places.

Cc Shakeel Butt <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Andrew Morton <[email protected]>
---
 include/linux/memcontrol.h | 9 +++++++++
 1 file changed, 9 insertions(+)
include/linux/memcontrol.h +9 -0
index cf1c3555328f..3607913032be 100644
@@ -383,6 +383,11 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
 	return css ? container_of(css, struct mem_cgroup, css) : NULL;
 }
 
+static inline void mem_cgroup_put(struct mem_cgroup *memcg)
+{
+	css_put(&memcg->css);
+}
+
 #define mem_cgroup_from_counter(counter, member)	\
 	container_of(counter, struct mem_cgroup, member)
 
@@ -852,6 +857,10 @@ static inline bool task_in_mem_cgroup(struct task_struct *task,
 	return true;
 }
 
+static inline void mem_cgroup_put(struct mem_cgroup *memcg)
+{
+}
+
 static inline struct mem_cgroup *
 mem_cgroup_iter(struct mem_cgroup *root,
 		struct mem_cgroup *prev,
Signature · 1 line
2.14.4
author Reviewed-by on v1 2/2
#16 lore raw

Re: [PATCH 2/2] mm: introduce mem_cgroup_put() helper

Quoted 6 lines · Roman Gushchin

Introduce the mem_cgroup_put() helper, which helps to eliminate guarding memcg css release with "#ifdef CONFIG_MEMCG" in multiple places.

Quoted 38 lines
Cc Shakeel Butt <[email protected]>
Cc Johannes Weiner <[email protected]>
Cc Michal Hocko <[email protected]>
Cc Andrew Morton <[email protected]>
---
 include/linux/memcontrol.h | 9 +++++++++
 1 file changed, 9 insertions(+)
include/linux/memcontrol.h +9 -1
index cf1c3555328f..3607913032be 100644
@@ -383,6 +383,11 @@ struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css){
        return css ? container_of(css, struct mem_cgroup, css) : NULL;
 }
 
+static inline void mem_cgroup_put(struct mem_cgroup *memcg)
+{
+       css_put(&memcg->css);
+}
+
 #define mem_cgroup_from_counter(counter, member)       \
        container_of(counter, struct mem_cgroup, member)
 
@@ -852,6 +857,10 @@ static inline bool task_in_mem_cgroup(struct task_struct *task,
        return true;
 }
 
+static inline void mem_cgroup_put(struct mem_cgroup *memcg)
+{
+}
+
 static inline struct mem_cgroup *
 mem_cgroup_iter(struct mem_cgroup *root,
                struct mem_cgroup *prev,
--

2.14.4

#17 lore raw

Re: [PATCH 1/2] mm: revert mem_cgroup_put() introduction

In reply to Roman Gushchin
Thank you for the patch! Yet something to improve:

Hi Roman,

Thank you for the patch! Yet something to improve:

[auto build test ERROR on next-20180622]
[cannot apply to linus/master v4.18-rc1 v4.17 v4.17-rc7 v4.18-rc1]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]

url: https://github.com/0day-ci/linux/commits/Roman-Gushchin/mm-revert-mem_cgroup_put-introduction/20180623-080942
config: i386-tinyconfig (attached as .config)
compiler: gcc-7 (Debian 7.3.0-16) 7.3.0
reproduce:

        # save the attached .config to linux build tree
        make ARCH=i386 

Note: the linux-review/Roman-Gushchin/mm-revert-mem_cgroup_put-introduction/20180623-080942 HEAD 76214420a3e55c42797f5f22cb04d1a3331c1ece builds fine.
It only hurts bisectibility.

All errors (new ones prefixed by >>):

mm/oom_kill.c: In function 'oom_kill_memcg_victim':

>> mm/oom_kill.c:1026:2: error: implicit declaration of function 'mem_cgroup_put'; did you mean 'mem_cgroup_id'? [-Werror=implicit-function-declaration]
     mem_cgroup_put(oc->chosen_memcg);
     ^~~~~~~~~~~~~~
     mem_cgroup_id

cc1: some warnings being treated as errors

vim +1026 mm/oom_kill.c

4ac2c83a Roman Gushchin 2018-06-15   997  
7388c5c4 Roman Gushchin 2018-06-15   998  static bool oom_kill_memcg_victim(struct oom_control *oc)
7388c5c4 Roman Gushchin 2018-06-15   999  {
4ac2c83a Roman Gushchin 2018-06-15  1000  	if (oc->chosen_memcg == NULL || oc->chosen_memcg == INFLIGHT_VICTIM)
4ac2c83a Roman Gushchin 2018-06-15  1001  		return oc->chosen_memcg;
4ac2c83a Roman Gushchin 2018-06-15  1002  
7388c5c4 Roman Gushchin 2018-06-15  1003  	/*
7388c5c4 Roman Gushchin 2018-06-15  1004  	 * If memory.oom_group is set, kill all tasks belonging to the sub-tree
7388c5c4 Roman Gushchin 2018-06-15  1005  	 * of the chosen memory cgroup, otherwise kill the task with the biggest
7388c5c4 Roman Gushchin 2018-06-15  1006  	 * memory footprint.
7388c5c4 Roman Gushchin 2018-06-15  1007  	 */
7388c5c4 Roman Gushchin 2018-06-15  1008  	if (mem_cgroup_oom_group(oc->chosen_memcg)) {
7388c5c4 Roman Gushchin 2018-06-15  1009  		mem_cgroup_scan_tasks(oc->chosen_memcg, oom_kill_memcg_member,
7388c5c4 Roman Gushchin 2018-06-15  1010  				      NULL);
7388c5c4 Roman Gushchin 2018-06-15  1011  		/* We have one or more terminating processes at this point. */
7388c5c4 Roman Gushchin 2018-06-15  1012  		oc->chosen_task = INFLIGHT_VICTIM;
7388c5c4 Roman Gushchin 2018-06-15  1013  	} else {
4ac2c83a Roman Gushchin 2018-06-15  1014  		oc->chosen_points = 0;
4ac2c83a Roman Gushchin 2018-06-15  1015  		oc->chosen_task = NULL;
4ac2c83a Roman Gushchin 2018-06-15  1016  		mem_cgroup_scan_tasks(oc->chosen_memcg, oom_evaluate_task, oc);
4ac2c83a Roman Gushchin 2018-06-15  1017  
7388c5c4 Roman Gushchin 2018-06-15  1018  		if (oc->chosen_task == NULL ||
7388c5c4 Roman Gushchin 2018-06-15  1019  		    oc->chosen_task == INFLIGHT_VICTIM)
4ac2c83a Roman Gushchin 2018-06-15  1020  			goto out;
4ac2c83a Roman Gushchin 2018-06-15  1021  
4ac2c83a Roman Gushchin 2018-06-15  1022  		__oom_kill_process(oc->chosen_task);
7388c5c4 Roman Gushchin 2018-06-15  1023  	}
4ac2c83a Roman Gushchin 2018-06-15  1024  
4ac2c83a Roman Gushchin 2018-06-15  1025  out:
4ac2c83a Roman Gushchin 2018-06-15 @1026  	mem_cgroup_put(oc->chosen_memcg);
4ac2c83a Roman Gushchin 2018-06-15  1027  	return oc->chosen_task;
4ac2c83a Roman Gushchin 2018-06-15  1028  }

4ac2c83a Roman Gushchin 2018-06-15 1029

:::::: The code at line 1026 was first introduced by commit
:::::: 4ac2c83a8e8a0708278b6f2bb44dc4c880fdcaf6 mm, oom: cgroup-aware OOM killer

:::::: TO: Roman Gushchin <[email protected]> :::::: CC: Stephen Rothwell <[email protected]>

---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation

maintainer
#18 lore raw
In reply to Shakeel Butt

Hi Shakeel,

this looks generally reasonable to me.

However, patch 1 introduces API that isn't used until patch 2 and 3, which makes reviewing harder since you have to jump back and forth between emails. Please fold patch 1 and introduce API along with the users.

Quoted 11 lines · Shakeel Butt

This patchset introduces memcg variant memory allocation functions. The caller can explicitly pass the memcg to charge for kmem allocations. Currently the kernel, for __GFP_ACCOUNT memory allocation requests, extract the memcg of the current task to charge for the kmem allocation. This patch series introduces kmem allocation functions where the caller can pass the pointer to the remote memcg. The remote memcg will be charged for the allocation instead of the memcg of the caller. However the caller must have a reference to the remote memcg. This patch series also introduces scope API for targeted memcg charging. So, all the __GFP_ACCOUNT alloctions within the specified scope will be charged to the given target memcg.

Can you open with the rationale for the series, i.e. the problem statement (fsnotify and bh memory footprint), *then* follow with the proposed solution?

Thanks!

#19 lore raw
Quoted 10 lines · Johannes Weiner

Hi Shakeel,

this looks generally reasonable to me.

However, patch 1 introduces API that isn't used until patch 2 and 3, which makes reviewing harder since you have to jump back and forth between emails. Please fold patch 1 and introduce API along with the users.

Thanks a lot for the review. Ack, I will do as you suggested in next version.

Quoted 13 lines · Shakeel Butt
Quoted 11 lines

This patchset introduces memcg variant memory allocation functions. The caller can explicitly pass the memcg to charge for kmem allocations. Currently the kernel, for __GFP_ACCOUNT memory allocation requests, extract the memcg of the current task to charge for the kmem allocation. This patch series introduces kmem allocation functions where the caller can pass the pointer to the remote memcg. The remote memcg will be charged for the allocation instead of the memcg of the caller. However the caller must have a reference to the remote memcg. This patch series also introduces scope API for targeted memcg charging. So, all the __GFP_ACCOUNT alloctions within the specified scope will be charged to the given target memcg.

Quoted 4 lines

Can you open with the rationale for the series, i.e. the problem statement (fsnotify and bh memory footprint), *then* follow with the proposed solution?

Sure.

thanks,
Shakeel