]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
kaiser: vmstat show NR_KAISERTABLE as nr_overhead
authorHugh Dickins <hughd@google.com>
Sun, 10 Sep 2017 04:27:32 +0000 (21:27 -0700)
committerKirtikar Kashyap <kirtikar.kashyap@oracle.com>
Fri, 12 Jan 2018 18:20:07 +0000 (10:20 -0800)
The kaiser update made an interesting choice, never to free any shadow
page tables.  Contention on global spinlock was worrying, particularly
with it held across page table scans when freeing.  Something had to be
done: I was going to add refcounting; but simply never to free them is
an appealing choice, minimizing contention without complicating the code
(the more a page table is found already, the less the spinlock is used).

But leaking pages in this way is also a worry: can we get away with it?
At the very least, we need a count to show how bad it actually gets:
in principle, one might end up wasting about 1/256 of memory that way
(1/512 for when direct-mapped pages have to be user-mapped, plus 1/512
for when they are user-mapped from the vmalloc area on another occasion
(but we don't have vmalloc'ed stacks, so only large ldts are vmalloc'ed).

Add per-cpu stat NR_KAISERTABLE: including 256 at startup for the
shared pgd entries, and 1 for each intermediate page table added
thereafter for user-mapping - but leave out the 1 per mm, for its
shadow pgd, because that distracts from the monotonic increase.
Shown in /proc/vmstat as nr_overhead (0 if kaiser not enabled).

In practice, it doesn't look so bad so far: more like 1/12000 after
nine hours of gtests below; and movable pageblock segregation should
tend to cluster the kaiser tables into a subset of the address space
(if not, they will be bad for compaction too).  But production may
tell a different story: keep an eye on this number, and bring back
lighter freeing if it gets out of control (maybe a shrinker).

Signed-off-by: Hugh Dickins <hughd@google.com>
Acked-by: Jiri Kosina <jkosina@suse.cz>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
(cherry picked from commit 3e3d38fd9832e82a8cb1a5b1154acfa43ac08d15)
Orabug: 27333760
CVE: CVE-2017-5754
Signed-off-by: Pavel Tatashin <pasha.tatashin@oracle.com>
Signed-off-by: Kirtikar Kashyap <kirtikar.kashyap@oracle.com>
arch/x86/mm/kaiser.c
include/linux/mmzone.h
mm/vmstat.c

index 8996f32925963645d0091d24a6fb9fa0a02e4228..50d650799f3912ecfaf6013766eec8a1fd18973f 100644 (file)
@@ -122,9 +122,11 @@ static pte_t *kaiser_pagetable_walk(unsigned long address, bool is_atomic)
                if (!new_pmd_page)
                        return NULL;
                spin_lock(&shadow_table_allocation_lock);
-               if (pud_none(*pud))
+               if (pud_none(*pud)) {
                        set_pud(pud, __pud(_KERNPG_TABLE | __pa(new_pmd_page)));
-               else
+                       __inc_zone_page_state(virt_to_page((void *)
+                                               new_pmd_page), NR_KAISERTABLE);
+               } else
                        free_page(new_pmd_page);
                spin_unlock(&shadow_table_allocation_lock);
        }
@@ -140,9 +142,11 @@ static pte_t *kaiser_pagetable_walk(unsigned long address, bool is_atomic)
                if (!new_pte_page)
                        return NULL;
                spin_lock(&shadow_table_allocation_lock);
-               if (pmd_none(*pmd))
+               if (pmd_none(*pmd)) {
                        set_pmd(pmd, __pmd(_KERNPG_TABLE | __pa(new_pte_page)));
-               else
+                       __inc_zone_page_state(virt_to_page((void *)
+                                               new_pte_page), NR_KAISERTABLE);
+               } else
                        free_page(new_pte_page);
                spin_unlock(&shadow_table_allocation_lock);
        }
@@ -206,11 +210,13 @@ static void __init kaiser_init_all_pgds(void)
        pgd = native_get_shadow_pgd(pgd_offset_k((unsigned long )0));
        for (i = PTRS_PER_PGD / 2; i < PTRS_PER_PGD; i++) {
                pgd_t new_pgd;
-               pud_t *pud = pud_alloc_one(&init_mm, PAGE_OFFSET + i * PGDIR_SIZE);
+               pud_t *pud = pud_alloc_one(&init_mm,
+                                          PAGE_OFFSET + i * PGDIR_SIZE);
                if (!pud) {
                        WARN_ON(1);
                        break;
                }
+               inc_zone_page_state(virt_to_page(pud), NR_KAISERTABLE);
                new_pgd = __pgd(_KERNPG_TABLE |__pa(pud));
                /*
                 * Make sure not to stomp on some other pgd entry.
index 4f2f3d134bcf27224d0265b0ce2164428ad09d58..1b01724737682d2d13cb93cc27ff2369e9733e89 100644 (file)
@@ -131,8 +131,9 @@ enum zone_stat_item {
        NR_SLAB_RECLAIMABLE,
        NR_SLAB_UNRECLAIMABLE,
        NR_PAGETABLE,           /* used for pagetables */
-       NR_KERNEL_STACK,
        /* Second 128 byte cacheline */
+       NR_KERNEL_STACK,
+       NR_KAISERTABLE,
        NR_UNSTABLE_NFS,        /* NFS unstable pages */
        NR_BOUNCE,
        NR_VMSCAN_WRITE,
index 4f5cd974e11a0adbb8a601cc92b9866ab6d67d55..8e0cbcd0fccc89db543a871dd67898a9c5902fce 100644 (file)
@@ -714,6 +714,7 @@ const char * const vmstat_text[] = {
        "nr_slab_unreclaimable",
        "nr_page_table_pages",
        "nr_kernel_stack",
+       "nr_overhead",
        "nr_unstable",
        "nr_bounce",
        "nr_vmscan_write",