]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
um: Delay flushing syscalls until the thread is restarted
authorBenjamin Berg <benjamin@sipsolutions.net>
Wed, 3 Jul 2024 13:45:32 +0000 (15:45 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 3 Jul 2024 15:09:49 +0000 (17:09 +0200)
As running the syscalls is expensive due to context switches, we should
do so as late as possible in case more syscalls need to be queued later
on. This will also benefit a later move to a SECCOMP enabled userspace
as in that case the need for extra context switches is removed entirely.

Signed-off-by: Benjamin Berg <benjamin@sipsolutions.net>
Link: https://patch.msgid.link/20240703134536.1161108-9-benjamin@sipsolutions.net
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
arch/um/include/shared/os.h
arch/um/include/shared/skas/mm_id.h
arch/um/include/shared/skas/skas.h
arch/um/kernel/skas/process.c
arch/um/kernel/tlb.c
arch/um/os-Linux/skas/mem.c
arch/um/os-Linux/skas/process.c

index d12fec5d0b4dbd1800bc14370fae969fd98e1ad0..345b117aff0b3879054b0d999ef5b002d2b7a370 100644 (file)
@@ -195,6 +195,9 @@ extern void get_host_cpu_features(
 /* mem.c */
 extern int create_mem_file(unsigned long long len);
 
+/* tlb.c */
+extern void report_enomem(void);
+
 /* process.c */
 extern unsigned long os_process_pc(int pid);
 extern int os_process_parent(int pid);
@@ -274,6 +277,7 @@ extern long long os_nsecs(void);
 /* skas/mem.c */
 int syscall_stub_flush(struct mm_id *mm_idp);
 struct stub_syscall *syscall_stub_alloc(struct mm_id *mm_idp);
+void syscall_stub_dump_error(struct mm_id *mm_idp);
 
 void map(struct mm_id *mm_idp, unsigned long virt,
         unsigned long len, int prot, int phys_fd,
index 4c5311abe42cb0a6605476cd58b1d5a3063d7dee..1e76ba40febadf8dd216fb88327deb5c605fb67d 100644 (file)
@@ -12,7 +12,6 @@ struct mm_id {
                int pid;
        } u;
        unsigned long stack;
-       int kill;
        int syscall_data_len;
 };
 
index c93d2cbc8f326c825b6162fc5715c7b48a374f3a..5c78b0cc3dd4e363b0fdaf8fde95ad35cbc0254f 100644 (file)
@@ -15,5 +15,6 @@ extern void new_thread_handler(void);
 extern void handle_syscall(struct uml_pt_regs *regs);
 extern long execute_syscall_skas(void *r);
 extern unsigned long current_stub_stack(void);
+extern struct mm_id *current_mm_id(void);
 
 #endif
index 99a5cbb36083284718d7fd6f9fef2e054cee1bb6..41901a74fcccb0527bd4ee7dde67d9d5ef635b37 100644 (file)
@@ -50,3 +50,11 @@ unsigned long current_stub_stack(void)
 
        return current->mm->context.id.stack;
 }
+
+struct mm_id *current_mm_id(void)
+{
+       if (current->mm == NULL)
+               return NULL;
+
+       return &current->mm->context.id;
+}
index a89e2886485f7c52aaa5cfef37704ad4da5f7fc8..1eee7134cba81f7f33c59e1243d8e68a30ed8679 100644 (file)
@@ -53,7 +53,7 @@ struct host_vm_change {
           .index       = 0, \
           .force       = force })
 
-static void report_enomem(void)
+void report_enomem(void)
 {
        printk(KERN_ERR "UML ran out of memory on the host side! "
                        "This can happen due to a memory limitation or "
@@ -338,15 +338,6 @@ static void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
 
        if (!ret)
                ret = do_ops(&hvc, hvc.index, 1);
-
-       /* This is not an else because ret is modified above */
-       if (ret) {
-               struct mm_id *mm_idp = &current->mm->context.id;
-
-               printk(KERN_ERR "fix_range_common: failed, killing current "
-                      "process: %d\n", task_tgid_vnr(current));
-               mm_idp->kill = 1;
-       }
 }
 
 static int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -461,7 +452,7 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
        pmd_t *pmd;
        pte_t *pte;
        struct mm_struct *mm = vma->vm_mm;
-       int r, w, x, prot, err = 0;
+       int r, w, x, prot;
        struct mm_id *mm_id;
 
        address &= PAGE_MASK;
@@ -509,14 +500,6 @@ void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
        } else if (pte_newprot(*pte))
                protect(mm_id, address, PAGE_SIZE, prot);
 
-       err = syscall_stub_flush(mm_id);
-       if (err) {
-               if (err == -ENOMEM)
-                       report_enomem();
-
-               goto kill;
-       }
-
        *pte = pte_mkuptodate(*pte);
 
        return;
index 32c61189110c8d0353cee370a7318bffe67bf65e..46fa10ab9892c778e322207d565b4f0fda2b420d 100644 (file)
 
 extern char __syscall_stub_start[];
 
+void syscall_stub_dump_error(struct mm_id *mm_idp)
+{
+       struct stub_data *proc_data = (void *)mm_idp->stack;
+       struct stub_syscall *sc;
+
+       if (proc_data->syscall_data_len < 0 ||
+           proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data))
+               panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!",
+                       proc_data->syscall_data_len,
+                       mm_idp->syscall_data_len);
+
+       sc = &proc_data->syscall_data[proc_data->syscall_data_len];
+
+       printk(UM_KERN_ERR "%s : length = %d, last offset = %d",
+               __func__, mm_idp->syscall_data_len,
+               proc_data->syscall_data_len);
+       printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n",
+               __func__, sc->syscall, proc_data->err);
+
+       print_hex_dump(UM_KERN_ERR, "    syscall data: ", 0,
+                      16, 4, sc, sizeof(*sc), 0);
+}
+
 static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
                                              unsigned long *stack)
 {
@@ -82,26 +105,9 @@ static inline long do_syscall_stub(struct mm_id *mm_idp)
         * otherwise it will be zero (but we do not need to rely on that).
         */
        if (proc_data->err < 0) {
-               struct stub_syscall *sc;
-
-               if (proc_data->syscall_data_len < 0 ||
-                   proc_data->syscall_data_len >= ARRAY_SIZE(proc_data->syscall_data))
-                       panic("Syscall data was corrupted by stub (len is: %d, expected maximum: %d)!",
-                             proc_data->syscall_data_len,
-                             mm_idp->syscall_data_len);
-
-               sc = &proc_data->syscall_data[proc_data->syscall_data_len];
-
-               printk(UM_KERN_ERR "%s : length = %d, last offset = %d",
-                      __func__, mm_idp->syscall_data_len,
-                      proc_data->syscall_data_len);
-               printk(UM_KERN_ERR "%s : stub syscall type %d failed, return value = 0x%lx\n",
-                      __func__, sc->syscall, proc_data->err);
-
-               print_hex_dump(UM_KERN_ERR,
-                              "    syscall data: ", 0,
-                              16, 4, sc, sizeof(*sc), 0);
+               syscall_stub_dump_error(mm_idp);
 
+               /* Store error code in case someone tries to add more syscalls */
                mm_idp->syscall_data_len = proc_data->err;
        } else {
                mm_idp->syscall_data_len = 0;
index 566b8ecccc3f19dd03d7f99bfe37096bbfdac16a..9cb61610147a3131731878477cb6511fab834892 100644 (file)
@@ -254,7 +254,6 @@ static int userspace_tramp(void *stack)
 }
 
 int userspace_pid[NR_CPUS];
-int kill_userspace_mm[NR_CPUS];
 
 /**
  * start_userspace() - prepare a new userspace process
@@ -348,8 +347,16 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
        while (1) {
                time_travel_print_bc_msg();
 
-               if (kill_userspace_mm[0])
+               /* Flush out any pending syscalls */
+               err = syscall_stub_flush(current_mm_id());
+               if (err) {
+                       if (err == -ENOMEM)
+                               report_enomem();
+
+                       printk(UM_KERN_ERR "%s - Error flushing stub syscalls: %d",
+                               __func__, -err);
                        fatal_sigsegv();
+               }
 
                /*
                 * This can legitimately fail if the process loads a
@@ -580,5 +587,4 @@ void reboot_skas(void)
 void __switch_mm(struct mm_id *mm_idp)
 {
        userspace_pid[0] = mm_idp->u.pid;
-       kill_userspace_mm[0] = mm_idp->kill;
 }