slab,slub: remove rcu_head size checks
[linux-2.6-microblaze.git] / mm / memcontrol.c
index 1695f38..e3d5692 100644 (file)
@@ -1034,13 +1034,13 @@ static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg)
        unsigned long limit;
 
        count = page_counter_read(&memcg->memory);
-       limit = READ_ONCE(memcg->memory.limit);
+       limit = READ_ONCE(memcg->memory.max);
        if (count < limit)
                margin = limit - count;
 
        if (do_memsw_account()) {
                count = page_counter_read(&memcg->memsw);
-               limit = READ_ONCE(memcg->memsw.limit);
+               limit = READ_ONCE(memcg->memsw.max);
                if (count <= limit)
                        margin = min(margin, limit - count);
                else
@@ -1148,13 +1148,13 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
 
        pr_info("memory: usage %llukB, limit %llukB, failcnt %lu\n",
                K((u64)page_counter_read(&memcg->memory)),
-               K((u64)memcg->memory.limit), memcg->memory.failcnt);
+               K((u64)memcg->memory.max), memcg->memory.failcnt);
        pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %lu\n",
                K((u64)page_counter_read(&memcg->memsw)),
-               K((u64)memcg->memsw.limit), memcg->memsw.failcnt);
+               K((u64)memcg->memsw.max), memcg->memsw.failcnt);
        pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n",
                K((u64)page_counter_read(&memcg->kmem)),
-               K((u64)memcg->kmem.limit), memcg->kmem.failcnt);
+               K((u64)memcg->kmem.max), memcg->kmem.failcnt);
 
        for_each_mem_cgroup_tree(iter, memcg) {
                pr_info("Memory cgroup stats for ");
@@ -1179,21 +1179,21 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
 /*
  * Return the memory (and swap, if configured) limit for a memcg.
  */
-unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg)
+unsigned long mem_cgroup_get_max(struct mem_cgroup *memcg)
 {
-       unsigned long limit;
+       unsigned long max;
 
-       limit = memcg->memory.limit;
+       max = memcg->memory.max;
        if (mem_cgroup_swappiness(memcg)) {
-               unsigned long memsw_limit;
-               unsigned long swap_limit;
+               unsigned long memsw_max;
+               unsigned long swap_max;
 
-               memsw_limit = memcg->memsw.limit;
-               swap_limit = memcg->swap.limit;
-               swap_limit = min(swap_limit, (unsigned long)total_swap_pages);
-               limit = min(limit + swap_limit, memsw_limit);
+               memsw_max = memcg->memsw.max;
+               swap_max = memcg->swap.max;
+               swap_max = min(swap_max, (unsigned long)total_swap_pages);
+               max = min(max + swap_max, memsw_max);
        }
-       return limit;
+       return max;
 }
 
 static bool mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
@@ -2444,12 +2444,13 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
 }
 #endif
 
-static DEFINE_MUTEX(memcg_limit_mutex);
+static DEFINE_MUTEX(memcg_max_mutex);
 
-static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
-                                  unsigned long limit, bool memsw)
+static int mem_cgroup_resize_max(struct mem_cgroup *memcg,
+                                unsigned long max, bool memsw)
 {
        bool enlarge = false;
+       bool drained = false;
        int ret;
        bool limits_invariant;
        struct page_counter *counter = memsw ? &memcg->memsw : &memcg->memory;
@@ -2460,26 +2461,32 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
                        break;
                }
 
-               mutex_lock(&memcg_limit_mutex);
+               mutex_lock(&memcg_max_mutex);
                /*
                 * Make sure that the new limit (memsw or memory limit) doesn't
-                * break our basic invariant rule memory.limit <= memsw.limit.
+                * break our basic invariant rule memory.max <= memsw.max.
                 */
-               limits_invariant = memsw ? limit >= memcg->memory.limit :
-                                          limit <= memcg->memsw.limit;
+               limits_invariant = memsw ? max >= memcg->memory.max :
+                                          max <= memcg->memsw.max;
                if (!limits_invariant) {
-                       mutex_unlock(&memcg_limit_mutex);
+                       mutex_unlock(&memcg_max_mutex);
                        ret = -EINVAL;
                        break;
                }
-               if (limit > counter->limit)
+               if (max > counter->max)
                        enlarge = true;
-               ret = page_counter_limit(counter, limit);
-               mutex_unlock(&memcg_limit_mutex);
+               ret = page_counter_set_max(counter, max);
+               mutex_unlock(&memcg_max_mutex);
 
                if (!ret)
                        break;
 
+               if (!drained) {
+                       drain_all_stock(memcg);
+                       drained = true;
+                       continue;
+               }
+
                if (!try_to_free_mem_cgroup_pages(memcg, 1,
                                        GFP_KERNEL, !memsw)) {
                        ret = -EBUSY;
@@ -2603,6 +2610,9 @@ static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
 
        /* we call try-to-free pages for make this cgroup empty */
        lru_add_drain_all();
+
+       drain_all_stock(memcg);
+
        /* try to free all pages in this cgroup */
        while (nr_retries && page_counter_read(&memcg->memory)) {
                int progress;
@@ -2757,7 +2767,7 @@ static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
                        return (u64)mem_cgroup_usage(memcg, true) * PAGE_SIZE;
                return (u64)page_counter_read(counter) * PAGE_SIZE;
        case RES_LIMIT:
-               return (u64)counter->limit * PAGE_SIZE;
+               return (u64)counter->max * PAGE_SIZE;
        case RES_MAX_USAGE:
                return (u64)counter->watermark * PAGE_SIZE;
        case RES_FAILCNT:
@@ -2871,24 +2881,24 @@ static void memcg_free_kmem(struct mem_cgroup *memcg)
 }
 #endif /* !CONFIG_SLOB */
 
-static int memcg_update_kmem_limit(struct mem_cgroup *memcg,
-                                  unsigned long limit)
+static int memcg_update_kmem_max(struct mem_cgroup *memcg,
+                                unsigned long max)
 {
        int ret;
 
-       mutex_lock(&memcg_limit_mutex);
-       ret = page_counter_limit(&memcg->kmem, limit);
-       mutex_unlock(&memcg_limit_mutex);
+       mutex_lock(&memcg_max_mutex);
+       ret = page_counter_set_max(&memcg->kmem, max);
+       mutex_unlock(&memcg_max_mutex);
        return ret;
 }
 
-static int memcg_update_tcp_limit(struct mem_cgroup *memcg, unsigned long limit)
+static int memcg_update_tcp_max(struct mem_cgroup *memcg, unsigned long max)
 {
        int ret;
 
-       mutex_lock(&memcg_limit_mutex);
+       mutex_lock(&memcg_max_mutex);
 
-       ret = page_counter_limit(&memcg->tcpmem, limit);
+       ret = page_counter_set_max(&memcg->tcpmem, max);
        if (ret)
                goto out;
 
@@ -2913,7 +2923,7 @@ static int memcg_update_tcp_limit(struct mem_cgroup *memcg, unsigned long limit)
                memcg->tcpmem_active = true;
        }
 out:
-       mutex_unlock(&memcg_limit_mutex);
+       mutex_unlock(&memcg_max_mutex);
        return ret;
 }
 
@@ -2941,16 +2951,16 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
                }
                switch (MEMFILE_TYPE(of_cft(of)->private)) {
                case _MEM:
-                       ret = mem_cgroup_resize_limit(memcg, nr_pages, false);
+                       ret = mem_cgroup_resize_max(memcg, nr_pages, false);
                        break;
                case _MEMSWAP:
-                       ret = mem_cgroup_resize_limit(memcg, nr_pages, true);
+                       ret = mem_cgroup_resize_max(memcg, nr_pages, true);
                        break;
                case _KMEM:
-                       ret = memcg_update_kmem_limit(memcg, nr_pages);
+                       ret = memcg_update_kmem_max(memcg, nr_pages);
                        break;
                case _TCP:
-                       ret = memcg_update_tcp_limit(memcg, nr_pages);
+                       ret = memcg_update_tcp_max(memcg, nr_pages);
                        break;
                }
                break;
@@ -3083,7 +3093,7 @@ static int memcg_numa_stat_show(struct seq_file *m, void *v)
 #endif /* CONFIG_NUMA */
 
 /* Universal VM events cgroup1 shows, original sort order */
-unsigned int memcg1_events[] = {
+static const unsigned int memcg1_events[] = {
        PGPGIN,
        PGPGOUT,
        PGFAULT,
@@ -3126,8 +3136,8 @@ static int memcg_stat_show(struct seq_file *m, void *v)
        /* Hierarchical information */
        memory = memsw = PAGE_COUNTER_MAX;
        for (mi = memcg; mi; mi = parent_mem_cgroup(mi)) {
-               memory = min(memory, mi->memory.limit);
-               memsw = min(memsw, mi->memsw.limit);
+               memory = min(memory, mi->memory.max);
+               memsw = min(memsw, mi->memsw.max);
        }
        seq_printf(m, "hierarchical_memory_limit %llu\n",
                   (u64)memory * PAGE_SIZE);
@@ -3562,11 +3572,6 @@ static int mem_cgroup_oom_control_write(struct cgroup_subsys_state *css,
 
 #ifdef CONFIG_CGROUP_WRITEBACK
 
-struct list_head *mem_cgroup_cgwb_list(struct mem_cgroup *memcg)
-{
-       return &memcg->cgwb_list;
-}
-
 static int memcg_wb_domain_init(struct mem_cgroup *memcg, gfp_t gfp)
 {
        return wb_domain_init(&memcg->cgwb_domain, gfp);
@@ -3626,7 +3631,7 @@ void mem_cgroup_wb_stats(struct bdi_writeback *wb, unsigned long *pfilepages,
        *pheadroom = PAGE_COUNTER_MAX;
 
        while ((parent = parent_mem_cgroup(memcg))) {
-               unsigned long ceiling = min(memcg->memory.limit, memcg->high);
+               unsigned long ceiling = min(memcg->memory.max, memcg->high);
                unsigned long used = page_counter_read(&memcg->memory);
 
                *pheadroom = min(*pheadroom, ceiling - min(ceiling, used));
@@ -4270,7 +4275,8 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
        }
        spin_unlock(&memcg->event_list_lock);
 
-       memcg->low = 0;
+       page_counter_set_min(&memcg->memory, 0);
+       page_counter_set_low(&memcg->memory, 0);
 
        memcg_offline_kmem(memcg);
        wb_memcg_offline(memcg);
@@ -4319,12 +4325,13 @@ static void mem_cgroup_css_reset(struct cgroup_subsys_state *css)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(css);
 
-       page_counter_limit(&memcg->memory, PAGE_COUNTER_MAX);
-       page_counter_limit(&memcg->swap, PAGE_COUNTER_MAX);
-       page_counter_limit(&memcg->memsw, PAGE_COUNTER_MAX);
-       page_counter_limit(&memcg->kmem, PAGE_COUNTER_MAX);
-       page_counter_limit(&memcg->tcpmem, PAGE_COUNTER_MAX);
-       memcg->low = 0;
+       page_counter_set_max(&memcg->memory, PAGE_COUNTER_MAX);
+       page_counter_set_max(&memcg->swap, PAGE_COUNTER_MAX);
+       page_counter_set_max(&memcg->memsw, PAGE_COUNTER_MAX);
+       page_counter_set_max(&memcg->kmem, PAGE_COUNTER_MAX);
+       page_counter_set_max(&memcg->tcpmem, PAGE_COUNTER_MAX);
+       page_counter_set_min(&memcg->memory, 0);
+       page_counter_set_low(&memcg->memory, 0);
        memcg->high = PAGE_COUNTER_MAX;
        memcg->soft_limit = PAGE_COUNTER_MAX;
        memcg_wb_domain_size_changed(memcg);
@@ -5061,10 +5068,40 @@ static u64 memory_current_read(struct cgroup_subsys_state *css,
        return (u64)page_counter_read(&memcg->memory) * PAGE_SIZE;
 }
 
+static int memory_min_show(struct seq_file *m, void *v)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
+       unsigned long min = READ_ONCE(memcg->memory.min);
+
+       if (min == PAGE_COUNTER_MAX)
+               seq_puts(m, "max\n");
+       else
+               seq_printf(m, "%llu\n", (u64)min * PAGE_SIZE);
+
+       return 0;
+}
+
+static ssize_t memory_min_write(struct kernfs_open_file *of,
+                               char *buf, size_t nbytes, loff_t off)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
+       unsigned long min;
+       int err;
+
+       buf = strstrip(buf);
+       err = page_counter_memparse(buf, "max", &min);
+       if (err)
+               return err;
+
+       page_counter_set_min(&memcg->memory, min);
+
+       return nbytes;
+}
+
 static int memory_low_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-       unsigned long low = READ_ONCE(memcg->low);
+       unsigned long low = READ_ONCE(memcg->memory.low);
 
        if (low == PAGE_COUNTER_MAX)
                seq_puts(m, "max\n");
@@ -5086,7 +5123,7 @@ static ssize_t memory_low_write(struct kernfs_open_file *of,
        if (err)
                return err;
 
-       memcg->low = low;
+       page_counter_set_low(&memcg->memory, low);
 
        return nbytes;
 }
@@ -5131,7 +5168,7 @@ static ssize_t memory_high_write(struct kernfs_open_file *of,
 static int memory_max_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-       unsigned long max = READ_ONCE(memcg->memory.limit);
+       unsigned long max = READ_ONCE(memcg->memory.max);
 
        if (max == PAGE_COUNTER_MAX)
                seq_puts(m, "max\n");
@@ -5155,7 +5192,7 @@ static ssize_t memory_max_write(struct kernfs_open_file *of,
        if (err)
                return err;
 
-       xchg(&memcg->memory.limit, max);
+       xchg(&memcg->memory.max, max);
 
        for (;;) {
                unsigned long nr_pages = page_counter_read(&memcg->memory);
@@ -5295,6 +5332,12 @@ static struct cftype memory_files[] = {
                .flags = CFTYPE_NOT_ON_ROOT,
                .read_u64 = memory_current_read,
        },
+       {
+               .name = "min",
+               .flags = CFTYPE_NOT_ON_ROOT,
+               .seq_show = memory_min_show,
+               .write = memory_min_write,
+       },
        {
                .name = "low",
                .flags = CFTYPE_NOT_ON_ROOT,
@@ -5344,54 +5387,140 @@ struct cgroup_subsys memory_cgrp_subsys = {
 };
 
 /**
- * mem_cgroup_low - check if memory consumption is below the normal range
+ * mem_cgroup_protected - check if memory consumption is in the normal range
  * @root: the top ancestor of the sub-tree being checked
  * @memcg: the memory cgroup to check
  *
- * Returns %true if memory consumption of @memcg, and that of all
- * ancestors up to (but not including) @root, is below the normal range.
+ * WARNING: This function is not stateless! It can only be used as part
+ *          of a top-down tree iteration, not for isolated queries.
  *
- * @root is exclusive; it is never low when looked at directly and isn't
- * checked when traversing the hierarchy.
+ * Returns one of the following:
+ *   MEMCG_PROT_NONE: cgroup memory is not protected
+ *   MEMCG_PROT_LOW: cgroup memory is protected as long there is
+ *     an unprotected supply of reclaimable memory from other cgroups.
+ *   MEMCG_PROT_MIN: cgroup memory is protected
  *
- * Excluding @root enables using memory.low to prioritize memory usage
- * between cgroups within a subtree of the hierarchy that is limited by
- * memory.high or memory.max.
+ * @root is exclusive; it is never protected when looked at directly
  *
- * For example, given cgroup A with children B and C:
+ * To provide a proper hierarchical behavior, effective memory.min/low values
+ * are used. Below is the description of how effective memory.low is calculated.
+ * Effective memory.min values is calculated in the same way.
  *
- *    A
- *   / \
- *  B   C
+ * Effective memory.low is always equal or less than the original memory.low.
+ * If there is no memory.low overcommittment (which is always true for
+ * top-level memory cgroups), these two values are equal.
+ * Otherwise, it's a part of parent's effective memory.low,
+ * calculated as a cgroup's memory.low usage divided by sum of sibling's
+ * memory.low usages, where memory.low usage is the size of actually
+ * protected memory.
  *
- * and
+ *                                             low_usage
+ * elow = min( memory.low, parent->elow * ------------------ ),
+ *                                        siblings_low_usage
  *
- *  1. A/memory.current > A/memory.high
- *  2. A/B/memory.current < A/B/memory.low
- *  3. A/C/memory.current >= A/C/memory.low
+ *             | memory.current, if memory.current < memory.low
+ * low_usage = |
+              | 0, otherwise.
  *
- * As 'A' is high, i.e. triggers reclaim from 'A', and 'B' is low, we
- * should reclaim from 'C' until 'A' is no longer high or until we can
- * no longer reclaim from 'C'.  If 'A', i.e. @root, isn't excluded by
- * mem_cgroup_low when reclaming from 'A', then 'B' won't be considered
- * low and we will reclaim indiscriminately from both 'B' and 'C'.
+ *
+ * Such definition of the effective memory.low provides the expected
+ * hierarchical behavior: parent's memory.low value is limiting
+ * children, unprotected memory is reclaimed first and cgroups,
+ * which are not using their guarantee do not affect actual memory
+ * distribution.
+ *
+ * For example, if there are memcgs A, A/B, A/C, A/D and A/E:
+ *
+ *     A      A/memory.low = 2G, A/memory.current = 6G
+ *    //\\
+ *   BC  DE   B/memory.low = 3G  B/memory.current = 2G
+ *            C/memory.low = 1G  C/memory.current = 2G
+ *            D/memory.low = 0   D/memory.current = 2G
+ *            E/memory.low = 10G E/memory.current = 0
+ *
+ * and the memory pressure is applied, the following memory distribution
+ * is expected (approximately):
+ *
+ *     A/memory.current = 2G
+ *
+ *     B/memory.current = 1.3G
+ *     C/memory.current = 0.6G
+ *     D/memory.current = 0
+ *     E/memory.current = 0
+ *
+ * These calculations require constant tracking of the actual low usages
+ * (see propagate_protected_usage()), as well as recursive calculation of
+ * effective memory.low values. But as we do call mem_cgroup_protected()
+ * path for each memory cgroup top-down from the reclaim,
+ * it's possible to optimize this part, and save calculated elow
+ * for next usage. This part is intentionally racy, but it's ok,
+ * as memory.low is a best-effort mechanism.
  */
-bool mem_cgroup_low(struct mem_cgroup *root, struct mem_cgroup *memcg)
+enum mem_cgroup_protection mem_cgroup_protected(struct mem_cgroup *root,
+                                               struct mem_cgroup *memcg)
 {
+       struct mem_cgroup *parent;
+       unsigned long emin, parent_emin;
+       unsigned long elow, parent_elow;
+       unsigned long usage;
+
        if (mem_cgroup_disabled())
-               return false;
+               return MEMCG_PROT_NONE;
 
        if (!root)
                root = root_mem_cgroup;
        if (memcg == root)
-               return false;
+               return MEMCG_PROT_NONE;
+
+       usage = page_counter_read(&memcg->memory);
+       if (!usage)
+               return MEMCG_PROT_NONE;
+
+       emin = memcg->memory.min;
+       elow = memcg->memory.low;
+
+       parent = parent_mem_cgroup(memcg);
+       if (parent == root)
+               goto exit;
+
+       parent_emin = READ_ONCE(parent->memory.emin);
+       emin = min(emin, parent_emin);
+       if (emin && parent_emin) {
+               unsigned long min_usage, siblings_min_usage;
+
+               min_usage = min(usage, memcg->memory.min);
+               siblings_min_usage = atomic_long_read(
+                       &parent->memory.children_min_usage);
 
-       for (; memcg != root; memcg = parent_mem_cgroup(memcg)) {
-               if (page_counter_read(&memcg->memory) >= memcg->low)
-                       return false;
+               if (min_usage && siblings_min_usage)
+                       emin = min(emin, parent_emin * min_usage /
+                                  siblings_min_usage);
        }
 
-       return true;
+       parent_elow = READ_ONCE(parent->memory.elow);
+       elow = min(elow, parent_elow);
+       if (elow && parent_elow) {
+               unsigned long low_usage, siblings_low_usage;
+
+               low_usage = min(usage, memcg->memory.low);
+               siblings_low_usage = atomic_long_read(
+                       &parent->memory.children_low_usage);
+
+               if (low_usage && siblings_low_usage)
+                       elow = min(elow, parent_elow * low_usage /
+                                  siblings_low_usage);
+       }
+
+exit:
+       memcg->memory.emin = emin;
+       memcg->memory.elow = elow;
+
+       if (usage <= emin)
+               return MEMCG_PROT_MIN;
+       else if (usage <= elow)
+               return MEMCG_PROT_LOW;
+       else
+               return MEMCG_PROT_NONE;
 }
 
 /**
@@ -6012,10 +6141,17 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
        if (!memcg)
                return 0;
 
+       if (!entry.val) {
+               memcg_memory_event(memcg, MEMCG_SWAP_FAIL);
+               return 0;
+       }
+
        memcg = mem_cgroup_id_get_online(memcg);
 
        if (!mem_cgroup_is_root(memcg) &&
            !page_counter_try_charge(&memcg->swap, nr_pages, &counter)) {
+               memcg_memory_event(memcg, MEMCG_SWAP_MAX);
+               memcg_memory_event(memcg, MEMCG_SWAP_FAIL);
                mem_cgroup_id_put(memcg);
                return -ENOMEM;
        }
@@ -6067,7 +6203,7 @@ long mem_cgroup_get_nr_swap_pages(struct mem_cgroup *memcg)
                return nr_swap_pages;
        for (; memcg != root_mem_cgroup; memcg = parent_mem_cgroup(memcg))
                nr_swap_pages = min_t(long, nr_swap_pages,
-                                     READ_ONCE(memcg->swap.limit) -
+                                     READ_ONCE(memcg->swap.max) -
                                      page_counter_read(&memcg->swap));
        return nr_swap_pages;
 }
@@ -6088,7 +6224,7 @@ bool mem_cgroup_swap_full(struct page *page)
                return false;
 
        for (; memcg != root_mem_cgroup; memcg = parent_mem_cgroup(memcg))
-               if (page_counter_read(&memcg->swap) * 2 >= memcg->swap.limit)
+               if (page_counter_read(&memcg->swap) * 2 >= memcg->swap.max)
                        return true;
 
        return false;
@@ -6122,7 +6258,7 @@ static u64 swap_current_read(struct cgroup_subsys_state *css,
 static int swap_max_show(struct seq_file *m, void *v)
 {
        struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
-       unsigned long max = READ_ONCE(memcg->swap.limit);
+       unsigned long max = READ_ONCE(memcg->swap.max);
 
        if (max == PAGE_COUNTER_MAX)
                seq_puts(m, "max\n");
@@ -6144,15 +6280,27 @@ static ssize_t swap_max_write(struct kernfs_open_file *of,
        if (err)
                return err;
 
-       mutex_lock(&memcg_limit_mutex);
-       err = page_counter_limit(&memcg->swap, max);
-       mutex_unlock(&memcg_limit_mutex);
+       mutex_lock(&memcg_max_mutex);
+       err = page_counter_set_max(&memcg->swap, max);
+       mutex_unlock(&memcg_max_mutex);
        if (err)
                return err;
 
        return nbytes;
 }
 
+static int swap_events_show(struct seq_file *m, void *v)
+{
+       struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
+
+       seq_printf(m, "max %lu\n",
+                  atomic_long_read(&memcg->memory_events[MEMCG_SWAP_MAX]));
+       seq_printf(m, "fail %lu\n",
+                  atomic_long_read(&memcg->memory_events[MEMCG_SWAP_FAIL]));
+
+       return 0;
+}
+
 static struct cftype swap_files[] = {
        {
                .name = "swap.current",
@@ -6165,6 +6313,12 @@ static struct cftype swap_files[] = {
                .seq_show = swap_max_show,
                .write = swap_max_write,
        },
+       {
+               .name = "swap.events",
+               .flags = CFTYPE_NOT_ON_ROOT,
+               .file_offset = offsetof(struct mem_cgroup, swap_events_file),
+               .seq_show = swap_events_show,
+       },
        { }     /* terminate */
 };