otherwise, a value change in this file generates a file
        modified event.
 
+       Note that all fields in this file are hierarchical and the
+       file modified event can be generated due to an event down the
+       hierarchy. For for the local events at the cgroup level see
+       memory.events.local.
+
          low
                The number of times the cgroup is reclaimed due to
                high memory pressure even though its usage is under
                The number of processes belonging to this cgroup
                killed by any kind of OOM killer.
 
+  memory.events.local
+       Similar to memory.events but the fields in the file are local
+       to the cgroup i.e. not hierarchical. The file modified event
+       generated on this file reflects only the local events.
+
   memory.stat
        A read-only flat-keyed file which exists on non-root cgroups.
 
 
        /* OOM-Killer disable */
        int             oom_kill_disable;
 
-       /* memory.events */
+       /* memory.events and memory.events.local */
        struct cgroup_file events_file;
+       struct cgroup_file events_local_file;
 
        /* handle for "memory.swap.events" */
        struct cgroup_file swap_events_file;
 
        /* memory.events */
        atomic_long_t           memory_events[MEMCG_NR_MEMORY_EVENTS];
+       atomic_long_t           memory_events_local[MEMCG_NR_MEMORY_EVENTS];
 
        unsigned long           socket_pressure;
 
 static inline void memcg_memory_event(struct mem_cgroup *memcg,
                                      enum memcg_memory_event event)
 {
+       atomic_long_inc(&memcg->memory_events_local[event]);
+       cgroup_file_notify(&memcg->events_local_file);
+
        do {
                atomic_long_inc(&memcg->memory_events[event]);
                cgroup_file_notify(&memcg->events_file);
 
        return nbytes;
 }
 
+static void __memory_events_show(struct seq_file *m, atomic_long_t *events)
+{
+       seq_printf(m, "low %lu\n", atomic_long_read(&events[MEMCG_LOW]));
+       seq_printf(m, "high %lu\n", atomic_long_read(&events[MEMCG_HIGH]));
+       seq_printf(m, "max %lu\n", atomic_long_read(&events[MEMCG_MAX]));
+       seq_printf(m, "oom %lu\n", atomic_long_read(&events[MEMCG_OOM]));
+       seq_printf(m, "oom_kill %lu\n",
+                  atomic_long_read(&events[MEMCG_OOM_KILL]));
+}
+
 static int memory_events_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
 
-       seq_printf(m, "low %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_LOW]));
-       seq_printf(m, "high %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_HIGH]));
-       seq_printf(m, "max %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_MAX]));
-       seq_printf(m, "oom %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_OOM]));
-       seq_printf(m, "oom_kill %lu\n",
-                  atomic_long_read(&memcg->memory_events[MEMCG_OOM_KILL]));
+       __memory_events_show(m, memcg->memory_events);
+       return 0;
+}
+
+static int memory_events_local_show(struct seq_file *m, void *v)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_seq(m);
 
+       __memory_events_show(m, memcg->memory_events_local);
        return 0;
 }
 
                .file_offset = offsetof(struct mem_cgroup, events_file),
                .seq_show = memory_events_show,
        },
+       {
+               .name = "events.local",
+               .flags = CFTYPE_NOT_ON_ROOT,
+               .file_offset = offsetof(struct mem_cgroup, events_local_file),
+               .seq_show = memory_events_local_show,
+       },
        {
                .name = "stat",
                .flags = CFTYPE_NOT_ON_ROOT,