s390/kvm: avoid global config of vm.alloc_pgste=1
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Wed, 7 Jun 2017 12:10:24 +0000 (14:10 +0200)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Tue, 13 Jun 2017 11:03:41 +0000 (13:03 +0200)
The system control vm.alloc_pgste is used to control the size of the
page tables, either 2K or 4K. The idea is that a KVM host sets the
vm.alloc_pgste control to 1 which causes *all* new processes to run
with 4K page tables. For a non-kvm system the control should stay off
to save on memory used for page tables.

Trouble is that distributions choose to set the control globally to
be able to run KVM guests. This wastes memory on non-KVM systems.

Introduce the PT_S390_PGSTE ELF segment type to "mark" the qemu
executable with it. All executables with this (empty) segment in
its ELF phdr array will be started with 4K page tables. Any executable
without PT_S390_PGSTE will run with the default 2K page tables.

This removes the need to set vm.alloc_pgste=1 for a KVM host and
minimizes the waste of memory for page tables.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
arch/s390/Kconfig
arch/s390/include/asm/elf.h
arch/s390/include/asm/mmu_context.h
arch/s390/include/asm/ptrace.h
arch/s390/include/asm/thread_info.h
arch/s390/kernel/entry.S

index e7ff58150e8ff927d9741764e8dfcf98a1f715e8..bb11f9f30c8d42533e73142213d068cf8813c46a 100644 (file)
@@ -64,6 +64,7 @@ config ARCH_SUPPORTS_UPROBES
 
 config S390
        def_bool y
+       select ARCH_BINFMT_ELF_STATE
        select ARCH_HAS_DEVMEM_IS_ALLOWED
        select ARCH_HAS_ELF_RANDOMIZE
        select ARCH_HAS_GCOV_PROFILE_ALL
index e8f62304176957ac217a5524c49e5b779c352b45..ec024c08dabe662feb4cd3c016f05b781a54b0b0 100644 (file)
 #define ELF_DATA       ELFDATA2MSB
 #define ELF_ARCH       EM_S390
 
+/* s390 specific phdr types */
+#define PT_S390_PGSTE  0x70000000
+
 /*
  * ELF register definitions..
  */
@@ -151,6 +154,35 @@ extern unsigned int vdso_enabled;
         && (x)->e_ident[EI_CLASS] == ELF_CLASS)
 #define compat_start_thread    start_thread31
 
+struct arch_elf_state {
+       int rc;
+};
+
+#define INIT_ARCH_ELF_STATE { .rc = 0 }
+
+#define arch_check_elf(ehdr, interp, interp_ehdr, state) (0)
+#ifdef CONFIG_PGSTE
+#define arch_elf_pt_proc(ehdr, phdr, elf, interp, state)       \
+({                                                             \
+       struct arch_elf_state *_state = state;                  \
+       if ((phdr)->p_type == PT_S390_PGSTE &&                  \
+           !page_table_allocate_pgste &&                       \
+           !test_thread_flag(TIF_PGSTE) &&                     \
+           !current->mm->context.alloc_pgste) {                \
+               set_thread_flag(TIF_PGSTE);                     \
+               set_pt_regs_flag(task_pt_regs(current),         \
+                                PIF_SYSCALL_RESTART);          \
+               _state->rc = -EAGAIN;                           \
+       }                                                       \
+       _state->rc;                                             \
+})
+#else
+#define arch_elf_pt_proc(ehdr, phdr, elf, interp, state)       \
+({                                                             \
+       (state)->rc;                                            \
+})
+#endif
+
 /* For SVR4/S390 the function pointer to be registered with `atexit` is
    passed in R14. */
 #define ELF_PLAT_INIT(_r, load_addr) \
index 8712e11bead40327f6ad5bb22a659d37ddbbf644..4541ac44b35f0e39b831b3eba2e5669d29dd9f89 100644 (file)
@@ -25,7 +25,9 @@ static inline int init_new_context(struct task_struct *tsk,
        mm->context.gmap_asce = 0;
        mm->context.flush_mm = 0;
 #ifdef CONFIG_PGSTE
-       mm->context.alloc_pgste = page_table_allocate_pgste;
+       mm->context.alloc_pgste = page_table_allocate_pgste ||
+               test_thread_flag(TIF_PGSTE) ||
+               current->mm->context.alloc_pgste;
        mm->context.has_pgste = 0;
        mm->context.use_skey = 0;
        mm->context.use_cmma = 0;
index 004f549092351d000a54671df81252f31e312c19..853b01245c209bb821e9907c8fa5617f8143dc16 100644 (file)
 
 #define PIF_SYSCALL            0       /* inside a system call */
 #define PIF_PER_TRAP           1       /* deliver sigtrap on return to user */
+#define PIF_SYSCALL_RESTART    2       /* restart the current system call */
 
 #define _PIF_SYSCALL           _BITUL(PIF_SYSCALL)
 #define _PIF_PER_TRAP          _BITUL(PIF_PER_TRAP)
+#define _PIF_SYSCALL_RESTART   _BITUL(PIF_SYSCALL_RESTART)
 
 #ifndef __ASSEMBLY__
 
index 0b3ee083a6658104b94ef5383d543d705d991c98..1aecf432c48d413f9a8be0f279526ab5991f9d4b 100644 (file)
@@ -58,6 +58,7 @@ int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 #define TIF_UPROBE             3       /* breakpointed or single-stepping */
 #define TIF_GUARDED_STORAGE    4       /* load guarded storage control block */
 #define TIF_PATCH_PENDING      5       /* pending live patching update */
+#define TIF_PGSTE              6       /* New mm's will use 4K page tables */
 
 #define TIF_31BIT              16      /* 32bit process */
 #define TIF_MEMDIE             17      /* is terminating due to OOM killer */
index 6315037335ba9365a198859de579c6fdcfb683cf..0c0138c7dfc760aa15bc2103d152dbd0127b8931 100644 (file)
@@ -52,7 +52,7 @@ _TIF_TRACE    = (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | _TIF_SECCOMP | \
                   _TIF_SYSCALL_TRACEPOINT)
 _CIF_WORK      = (_CIF_MCCK_PENDING | _CIF_ASCE_PRIMARY | \
                   _CIF_ASCE_SECONDARY | _CIF_FPU)
-_PIF_WORK      = (_PIF_PER_TRAP)
+_PIF_WORK      = (_PIF_PER_TRAP | _PIF_SYSCALL_RESTART)
 
 #define BASED(name) name-cleanup_critical(%r13)
 
@@ -334,6 +334,8 @@ ENTRY(system_call)
        jo      .Lsysc_mcck_pending
        TSTMSK  __TI_flags(%r12),_TIF_NEED_RESCHED
        jo      .Lsysc_reschedule
+       TSTMSK  __PT_FLAGS(%r11),_PIF_SYSCALL_RESTART
+       jo      .Lsysc_syscall_restart
 #ifdef CONFIG_UPROBES
        TSTMSK  __TI_flags(%r12),_TIF_UPROBE
        jo      .Lsysc_uprobe_notify
@@ -347,6 +349,8 @@ ENTRY(system_call)
        jo      .Lsysc_patch_pending    # handle live patching just before
                                        # signals and possible syscall restart
 #endif
+       TSTMSK  __PT_FLAGS(%r11),_PIF_SYSCALL_RESTART
+       jo      .Lsysc_syscall_restart
        TSTMSK  __TI_flags(%r12),_TIF_SIGPENDING
        jo      .Lsysc_sigpending
        TSTMSK  __TI_flags(%r12),_TIF_NOTIFY_RESUME
@@ -447,6 +451,15 @@ ENTRY(system_call)
        larl    %r14,.Lsysc_return
        jg      do_per_trap
 
+#
+# _PIF_SYSCALL_RESTART is set, repeat the current system call
+#
+.Lsysc_syscall_restart:
+       ni      __PT_FLAGS+7(%r11),255-_PIF_SYSCALL_RESTART
+       lmg     %r1,%r7,__PT_R1(%r11)   # load svc arguments
+       lg      %r2,__PT_ORIG_GPR2(%r11)
+       j       .Lsysc_do_svc
+
 #
 # call tracehook_report_syscall_entry/tracehook_report_syscall_exit before
 # and after the system call