mm: per-cgroup memory reclaim stats
[linux-2.6-microblaze.git] / mm / memcontrol.c
index d75b38b..3e2f8cf 100644 (file)
@@ -2376,10 +2376,9 @@ void mem_cgroup_split_huge_fixup(struct page *head)
 
 #ifdef CONFIG_MEMCG_SWAP
 static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
-                                        bool charge)
+                                      int nr_entries)
 {
-       int val = (charge) ? 1 : -1;
-       this_cpu_add(memcg->stat->count[MEMCG_SWAP], val);
+       this_cpu_add(memcg->stat->count[MEMCG_SWAP], nr_entries);
 }
 
 /**
@@ -2405,8 +2404,8 @@ static int mem_cgroup_move_swap_account(swp_entry_t entry,
        new_id = mem_cgroup_id(to);
 
        if (swap_cgroup_cmpxchg(entry, old_id, new_id) == old_id) {
-               mem_cgroup_swap_statistics(from, false);
-               mem_cgroup_swap_statistics(to, true);
+               mem_cgroup_swap_statistics(from, -1);
+               mem_cgroup_swap_statistics(to, 1);
                return 0;
        }
        return -EINVAL;
@@ -5231,6 +5230,16 @@ static int memory_stat_show(struct seq_file *m, void *v)
        seq_printf(m, "pgfault %lu\n", events[PGFAULT]);
        seq_printf(m, "pgmajfault %lu\n", events[PGMAJFAULT]);
 
+       seq_printf(m, "pgrefill %lu\n", events[PGREFILL]);
+       seq_printf(m, "pgscan %lu\n", events[PGSCAN_KSWAPD] +
+                  events[PGSCAN_DIRECT]);
+       seq_printf(m, "pgsteal %lu\n", events[PGSTEAL_KSWAPD] +
+                  events[PGSTEAL_DIRECT]);
+       seq_printf(m, "pgactivate %lu\n", events[PGACTIVATE]);
+       seq_printf(m, "pgdeactivate %lu\n", events[PGDEACTIVATE]);
+       seq_printf(m, "pglazyfree %lu\n", events[PGLAZYFREE]);
+       seq_printf(m, "pglazyfreed %lu\n", events[PGLAZYFREED]);
+
        seq_printf(m, "workingset_refault %lu\n",
                   stat[WORKINGSET_REFAULT]);
        seq_printf(m, "workingset_activate %lu\n",
@@ -5445,7 +5454,7 @@ void mem_cgroup_commit_charge(struct page *page, struct mem_cgroup *memcg,
                 * let's not wait for it.  The page already received a
                 * memory+swap charge, drop the swap entry duplicate.
                 */
-               mem_cgroup_uncharge_swap(entry);
+               mem_cgroup_uncharge_swap(entry, nr_pages);
        }
 }
 
@@ -5873,9 +5882,9 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
         * ancestor for the swap instead and transfer the memory+swap charge.
         */
        swap_memcg = mem_cgroup_id_get_online(memcg);
-       oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg));
+       oldid = swap_cgroup_record(entry, mem_cgroup_id(swap_memcg), 1);
        VM_BUG_ON_PAGE(oldid, page);
-       mem_cgroup_swap_statistics(swap_memcg, true);
+       mem_cgroup_swap_statistics(swap_memcg, 1);
 
        page->mem_cgroup = NULL;
 
@@ -5902,19 +5911,20 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
                css_put(&memcg->css);
 }
 
-/*
- * mem_cgroup_try_charge_swap - try charging a swap entry
+/**
+ * mem_cgroup_try_charge_swap - try charging swap space for a page
  * @page: page being added to swap
  * @entry: swap entry to charge
  *
- * Try to charge @entry to the memcg that @page belongs to.
+ * Try to charge @page's memcg for the swap space at @entry.
  *
  * Returns 0 on success, -ENOMEM on failure.
  */
 int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
 {
-       struct mem_cgroup *memcg;
+       unsigned int nr_pages = hpage_nr_pages(page);
        struct page_counter *counter;
+       struct mem_cgroup *memcg;
        unsigned short oldid;
 
        if (!cgroup_subsys_on_dfl(memory_cgrp_subsys) || !do_swap_account)
@@ -5929,25 +5939,27 @@ int mem_cgroup_try_charge_swap(struct page *page, swp_entry_t entry)
        memcg = mem_cgroup_id_get_online(memcg);
 
        if (!mem_cgroup_is_root(memcg) &&
-           !page_counter_try_charge(&memcg->swap, 1, &counter)) {
+           !page_counter_try_charge(&memcg->swap, nr_pages, &counter)) {
                mem_cgroup_id_put(memcg);
                return -ENOMEM;
        }
 
-       oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
+       /* Get references for the tail pages, too */
+       if (nr_pages > 1)
+               mem_cgroup_id_get_many(memcg, nr_pages - 1);
+       oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg), nr_pages);
        VM_BUG_ON_PAGE(oldid, page);
-       mem_cgroup_swap_statistics(memcg, true);
+       mem_cgroup_swap_statistics(memcg, nr_pages);
 
        return 0;
 }
 
 /**
- * mem_cgroup_uncharge_swap - uncharge a swap entry
+ * mem_cgroup_uncharge_swap - uncharge swap space
  * @entry: swap entry to uncharge
- *
- * Drop the swap charge associated with @entry.
+ * @nr_pages: the amount of swap space to uncharge
  */
-void mem_cgroup_uncharge_swap(swp_entry_t entry)
+void mem_cgroup_uncharge_swap(swp_entry_t entry, unsigned int nr_pages)
 {
        struct mem_cgroup *memcg;
        unsigned short id;
@@ -5955,18 +5967,18 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry)
        if (!do_swap_account)
                return;
 
-       id = swap_cgroup_record(entry, 0);
+       id = swap_cgroup_record(entry, 0, nr_pages);
        rcu_read_lock();
        memcg = mem_cgroup_from_id(id);
        if (memcg) {
                if (!mem_cgroup_is_root(memcg)) {
                        if (cgroup_subsys_on_dfl(memory_cgrp_subsys))
-                               page_counter_uncharge(&memcg->swap, 1);
+                               page_counter_uncharge(&memcg->swap, nr_pages);
                        else
-                               page_counter_uncharge(&memcg->memsw, 1);
+                               page_counter_uncharge(&memcg->memsw, nr_pages);
                }
-               mem_cgroup_swap_statistics(memcg, false);
-               mem_cgroup_id_put(memcg);
+               mem_cgroup_swap_statistics(memcg, -nr_pages);
+               mem_cgroup_id_put_many(memcg, nr_pages);
        }
        rcu_read_unlock();
 }