मैंने यह x86_64 पर आजमाया
94836ecf1e7378b64d37624fb81fe48fbd4c772 के विरुद्ध पैच: (यहां भी https://github.com/pskocik/linux/tree/supersyscall )
diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl
index 5aef183e2f85..8df2e98eb403 100644
--- a/arch/x86/entry/syscalls/syscall_64.tbl
+++ b/arch/x86/entry/syscalls/syscall_64.tbl
@@ -339,6 +339,7 @@
330 common pkey_alloc sys_pkey_alloc
331 common pkey_free sys_pkey_free
332 common statx sys_statx
+333 common supersyscall sys_supersyscall
#
# x32-specific system call numbers start at 512 to avoid cache impact
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 980c3c9b06f8..c61c14e3ff4e 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -905,5 +905,20 @@ asmlinkage long sys_pkey_alloc(unsigned long flags, unsigned long init_val);
asmlinkage long sys_pkey_free(int pkey);
asmlinkage long sys_statx(int dfd, const char __user *path, unsigned flags,
unsigned mask, struct statx __user *buffer);
-
#endif
+
+struct supersyscall_args {
+ unsigned call_nr;
+ long args[6];
+};
+#define SUPERSYSCALL__abort_on_failure 0
+#define SUPERSYSCALL__continue_on_failure 1
+/*#define SUPERSYSCALL__lock_something 2?*/
+
+
+asmlinkage
+long
+sys_supersyscall(long* Rets,
+ struct supersyscall_args *Args,
+ int Nargs,
+ int Flags);
diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h
index a076cf1a3a23..56184b84530f 100644
--- a/include/uapi/asm-generic/unistd.h
+++ b/include/uapi/asm-generic/unistd.h
@@ -732,9 +732,11 @@ __SYSCALL(__NR_pkey_alloc, sys_pkey_alloc)
__SYSCALL(__NR_pkey_free, sys_pkey_free)
#define __NR_statx 291
__SYSCALL(__NR_statx, sys_statx)
+#define __NR_supersyscall 292
+__SYSCALL(__NR_supersyscall, sys_supersyscall)
#undef __NR_syscalls
-#define __NR_syscalls 292
+#define __NR_syscalls (__NR_supersyscall+1)
/*
* All syscalls below here should go away really,
diff --git a/init/Kconfig b/init/Kconfig
index a92f27da4a27..25f30bf0ebbb 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -2184,4 +2184,9 @@ config ASN1
inform it as to what tags are to be expected in a stream and what
functions to call on what tags.
+config SUPERSYSCALL
+ bool
+ help
+ System call for batching other system calls
+
source "kernel/Kconfig.locks"
diff --git a/kernel/Makefile b/kernel/Makefile
index b302b4731d16..4d86bcf90f90 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -9,7 +9,7 @@ obj-y = fork.o exec_domain.o panic.o \
extable.o params.o \
kthread.o sys_ni.o nsproxy.o \
notifier.o ksysfs.o cred.o reboot.o \
- async.o range.o smpboot.o ucount.o
+ async.o range.o smpboot.o ucount.o supersyscall.o
obj-$(CONFIG_MULTIUSER) += groups.o
diff --git a/kernel/supersyscall.c b/kernel/supersyscall.c
new file mode 100644
index 000000000000..d7fac5d3f970
--- /dev/null
+++ b/kernel/supersyscall.c
@@ -0,0 +1,83 @@
+#include <linux/syscalls.h>
+#include <linux/uaccess.h>
+#include <linux/compiler.h>
+#include <linux/sched/signal.h>
+
+/*TODO: do this properly*/
+/*#include <uapi/asm-generic/unistd.h>*/
+#ifndef __NR_syscalls
+# define __NR_syscalls (__NR_supersyscall+1)
+#endif
+
+#define uif(Cond) if(unlikely(Cond))
+#define lif(Cond) if(likely(Cond))
+
+
+typedef asmlinkage long (*sys_call_ptr_t)(unsigned long, unsigned long,
+ unsigned long, unsigned long,
+ unsigned long, unsigned long);
+extern const sys_call_ptr_t sys_call_table[];
+
+static bool
+syscall__failed(unsigned long Ret)
+{
+ return (Ret > -4096UL);
+}
+
+
+static bool
+syscall(unsigned Nr, long A[6])
+{
+ uif (Nr >= __NR_syscalls )
+ return -ENOSYS;
+ return sys_call_table[Nr](A[0], A[1], A[2], A[3], A[4], A[5]);
+}
+
+
+static int
+segfault(void const *Addr)
+{
+ struct siginfo info[1];
+ info->si_signo = SIGSEGV;
+ info->si_errno = 0;
+ info->si_code = 0;
+ info->si_addr = (void*)Addr;
+ return send_sig_info(SIGSEGV, info, current);
+ //return force_sigsegv(SIGSEGV, current);
+}
+
+asmlinkage long /*Ntried*/
+sys_supersyscall(long* Rets,
+ struct supersyscall_args *Args,
+ int Nargs,
+ int Flags)
+{
+ int i = 0, nfinished = 0;
+ struct supersyscall_args args; /*7 * sizeof(long) */
+
+ for (i = 0; i<Nargs; i++){
+ long ret;
+
+ uif (0!=copy_from_user(&args, Args+i, sizeof(args))){
+ segfault(&Args+i);
+ return nfinished;
+ }
+
+ ret = syscall(args.call_nr, args.args);
+ nfinished++;
+
+ if ((Flags & 1) == SUPERSYSCALL__abort_on_failure
+ && syscall__failed(ret))
+ return nfinished;
+
+
+ uif (0!=put_user(ret, Rets+1)){
+ segfault(Rets+i);
+ return nfinished;
+ }
+ }
+ return nfinished;
+
+}
+
+
diff --git a/kernel/sys_ni.c b/kernel/sys_ni.c
index 8acef8576ce9..c544883d7a13 100644
--- a/kernel/sys_ni.c
+++ b/kernel/sys_ni.c
@@ -258,3 +258,5 @@ cond_syscall(sys_membarrier);
cond_syscall(sys_pkey_mprotect);
cond_syscall(sys_pkey_alloc);
cond_syscall(sys_pkey_free);
+
+cond_syscall(sys_supersyscall);
और यह काम करने के लिए प्रतीत होता है - मैं हैलो को लिख सकता हूँ 1 fd और दुनिया को fd 2 को सिर्फ एक syscall के साथ:
#define _GNU_SOURCE
#include <unistd.h>
#include <sys/syscall.h>
#include <stdio.h>
struct supersyscall_args {
unsigned call_nr;
long args[6];
};
#define SUPERSYSCALL__abort_on_failure 0
#define SUPERSYSCALL__continue_on_failure 1
long
supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags);
int main(int c, char**v)
{
puts("HELLO WORLD:");
long r=0;
struct supersyscall_args args[] = {
{SYS_write, {1, (long)"hello\n", 6 }},
{SYS_write, {2, (long)"world\n", 6 }},
};
long rets[sizeof args / sizeof args[0]];
r = supersyscall(rets,
args,
sizeof(rets)/sizeof(rets[0]),
0);
printf("r=%ld\n", r);
printf( 0>r ? "%m\n" : "\n");
puts("");
#if 1
#if SEGFAULT
r = supersyscall(0,
args,
sizeof(rets)/sizeof(rets[0]),
0);
printf("r=%ld\n", r);
printf( 0>r ? "%m\n" : "\n");
#endif
#endif
return 0;
}
long
supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags)
{
return syscall(333, Rets, Args, Nargs, Flags);
}
मूल रूप से मैं उपयोग कर रहा हूँ:
long a_syscall(long, long, long, long, long, long);
एक सार्वभौमिक syscall प्रोटोटाइप के रूप में, जो प्रतीत होता है कि चीजें x86_64 पर कैसे काम करती हैं, इसलिए मेरा "सुपर" syscall है:
struct supersyscall_args {
unsigned call_nr;
long args[6];
};
#define SUPERSYSCALL__abort_on_failure 0
#define SUPERSYSCALL__continue_on_failure 1
/*#define SUPERSYSCALL__lock_something 2?*/
asmlinkage
long
sys_supersyscall(long* Rets,
struct supersyscall_args *Args,
int Nargs,
int Flags);
यह syscalls की संख्या की कोशिश करता है ( ==Nargs
यदि SUPERSYSCALL__continue_on_failure
ध्वज पारित किया गया है, अन्यथा >0 && <=Nargs
) और विफलताओं के बीच की गुठली अंतरिक्ष और उपयोगकर्ता के स्थान के बीच सामान्य रूप से segfaults द्वारा संकेतित हैं -EFAULT
।
मुझे नहीं पता कि यह अन्य आर्किटेक्चर के लिए कैसे पोर्ट होगा, लेकिन यह निश्चित रूप से अच्छा होगा कि कर्नेल में ऐसा कुछ हो।
यदि यह सभी अभिलेखों के लिए संभव था, तो मुझे लगता है कि एक उपयोगकर्ता रैपर हो सकता है जो कुछ यूनियनों और मैक्रोज़ के माध्यम से टाइप सुरक्षा प्रदान करेगा (यह syscall नाम के आधार पर एक यूनियन सदस्य का चयन कर सकता है और सभी यूनियन फिर 6 लॉन्ग में परिवर्तित हो जाएंगे। या जो भी आर्किटेक्चर डे पत्रिकाओं के 6 लोंगो के बराबर होगा)।
batch
में syscallsbatch
syscalls, आप मनमाने ढंग से syscalls के मनमाने ढंग से गहरी कॉल पेड़ बना सकते हैं। मूल रूप से, आप अपने पूरे आवेदन को एक एकल syscall में डाल सकते हैं।