From: Steven Rostedt <rostedt@goodmis.org>
To: Adrian Bunk <bunk@stusta.de>
Cc: Jan Engelhardt <jengelh@linux01.gwdg.de>,
LKML <linux-kernel@vger.kernel.org>
Subject: Re: [RFC] dynamic syscalls revisited
Date: Mon, 06 Dec 2004 11:07:35 -0500 [thread overview]
Message-ID: <1102349255.25841.189.camel@localhost.localdomain> (raw)
In-Reply-To: <20041205234605.GF2953@stusta.de>
On Mon, 2004-12-06 at 00:46 +0100, Adrian Bunk wrote:
>
> Why don't you EXPORT_SYMBOL_GPL dsyscall_{,un}register?
>
> This should at least fix the binary only module concerns.
Done!
Updated on http://home.stny.rr.com/rostedt/dynamic as well as included
in this email for ease.
Now, I guess you can still get around this if the "Bad Vendor" were to
write a GPL module with their added system calls, and have that module
include hooks to their binary module. So, until we can fix that, I
guess Linus won't allow for this module to be included in the main line.
-- Steve
Index: kernel/Makefile
===================================================================
--- kernel/Makefile (revision 15)
+++ kernel/Makefile (working copy)
@@ -29,6 +29,7 @@
obj-$(CONFIG_SYSFS) += ksysfs.o
obj-$(CONFIG_GENERIC_HARDIRQS) += irq/
obj-$(CONFIG_CRASH_DUMP) += crash.o
+obj-$(CONFIG_DSYSCALL) += dsyscall.o
ifneq ($(CONFIG_IA64),y)
# According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
Index: kernel/dsyscall.c
===================================================================
--- kernel/dsyscall.c (revision 0)
+++ kernel/dsyscall.c (revision 0)
@@ -0,0 +1,286 @@
+/*
+ * dsyscall.c
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/config.h>
+#include <linux/slab.h>
+#include <linux/user.h>
+#include <linux/dsyscall.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+
+#include <asm/uaccess.h>
+
+#undef DEBUG
+#ifdef DEBUG
+#define dprintk(x...) printk(x)
+#else
+#define dprintk(x...) do { } while(0)
+#endif
+
+#define DSYSCALL_HASH_SIZE 32
+
+DECLARE_RWSEM(dsyscall_sem);
+
+static long dsyscall_next_id = 0;
+static long dsyscall_iterations = 0;
+static kmem_cache_t *dsyscall_cache;
+static struct list_head dsyscall_hash[DSYSCALL_HASH_SIZE];
+static LIST_HEAD(dsyscall_syscalls);
+
+static int dsyscall_hash_add(struct dsyscall_struct *ds)
+{
+ list_add(&ds->link,&dsyscall_hash[ds->id & (DSYSCALL_HASH_SIZE - 1)]);
+ return 0;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_name(char *name)
+{
+ struct list_head *li;
+ struct dsyscall_struct *ds, *ret = NULL;
+
+ /* slow, but this should not be called often. */
+ list_for_each(li,&dsyscall_syscalls) {
+ ds = list_entry(li, struct dsyscall_struct, next);
+ if (strcmp(ds->name,name) == 0) {
+ ret = ds;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static struct dsyscall_struct * find_dsyscall_by_id(struct dsyscall *d)
+{
+ struct list_head *li;
+ struct dsyscall_struct *ds, *ret = NULL;
+
+ /* For now it's a little faster. We can optimize this if we need to */
+ list_for_each(li,&dsyscall_hash[d->id & (DSYSCALL_HASH_SIZE - 1)]) {
+ ds = list_entry(li, struct dsyscall_struct, link);
+ if (ds->id == d->id) {
+ if (likely(ds->iteration == d->iteration))
+ ret = ds;
+ break;
+ }
+ }
+ return ret;
+}
+
+
+int sys_dsyscall(int type, char *user_name, struct dsyscall *dcall)
+{
+ int ret;
+ struct dsyscall_struct *ds;
+ struct dsyscall d;
+ long argv[DSYSCALL_MAX_ARGS];
+
+ /*
+ * OK, this is pretty long to hold a semaphore, even if
+ * if is just for reading. But if you want speed, don't use
+ * dynamic system calls!
+ */
+ down_read(&dsyscall_sem);
+ switch (type) {
+ case DSYSCALL_GET:
+ dprintk("sys_dsyscall: DSYSCALL_GET, ");
+ memset (&d,0,sizeof(d));
+ ret = -EFAULT;
+ if (strncpy_from_user(d.name,user_name,DSYSCALL_NAME_SZ-1) < 0) {
+ dprintk(">>>BAD NAME<<<\n");
+ goto out;
+ }
+ dprintk("%s: ", d.name);
+
+ /* just in case */
+ d.name[DSYSCALL_NAME_SZ-1] = 0;
+
+ ds = find_dsyscall_by_name(d.name);
+
+ if (!ds) {
+ dprintk("not found\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ dprintk("found\n");
+ d.id = ds->id;
+ d.iteration = ds->iteration;
+ d.argc = ds->args;
+
+ ret = 0;
+ if (copy_to_user(dcall,&d,sizeof(d)) != 0) {
+ ret = -EFAULT;
+ }
+ break;
+
+ case DSYSCALL_CALL:
+ ret = -EFAULT;
+ if (copy_from_user(&d,dcall,sizeof(d)) != 0) {
+ goto out;
+ }
+
+ ds = find_dsyscall_by_id(&d);
+ if (!ds) {
+ ret = -ENODEV;
+ goto out;
+ }
+ /* Comparing to ds->args which can not be bigger than DSYSCALL_MAX_ARGS */
+ if (d.argc != ds->args) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (d.argc > 0) {
+ if (copy_from_user(argv,d.argv,sizeof(char*)*d.argc) != 0) {
+ ret = -EFAULT;
+ goto out;
+ }
+ }
+
+ switch (d.argc) {
+ case 0:
+ ret = ds->func(0); /* The argument should be ignored */
+ break;
+ case 1:
+ ret = ds->func(argv[0]);
+ break;
+ case 2:
+ ret = ds->func(argv[0],argv[1]);
+ break;
+ case 3:
+ ret = ds->func(argv[0],argv[1],argv[2]);
+ break;
+ case 4:
+ ret = ds->func(argv[0],argv[1],argv[2],argv[3]);
+ break;
+ case 5:
+ ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4]);
+ break;
+ case 6:
+ ret = ds->func(argv[0],argv[1],argv[2],argv[3],argv[4],argv[5]);
+ break;
+ }
+ goto out;
+ break;
+
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ out:
+ up_read(&dsyscall_sem);
+
+ return ret;
+}
+
+int dsyscall_register(char *name, int args, int (*func)(long,...))
+{
+ int ret = -1;
+ struct dsyscall_struct *ds;
+
+ dprintk("dsyscall_register: %s args: %d func=%p\n",name,args,func);
+
+ if (strlen(name) >= DSYSCALL_NAME_SZ) {
+ printk(KERN_INFO "dsyscall: name %s is too large.", name);
+ return -1;
+ }
+ if (args > DSYSCALL_MAX_ARGS) {
+ printk(KERN_INFO "dsyscall: args is too big.");
+ return -1;
+ }
+
+ down_write(&dsyscall_sem);
+ if ((ds = find_dsyscall_by_name(name)) != NULL) {
+ printk(KERN_INFO "dsyscall: name %s is already in use.",name);
+ goto out;
+ }
+
+ ds = kmem_cache_alloc(dsyscall_cache,GFP_KERNEL);
+ if (!ds) {
+ printk(KERN_INFO "dsyscall: could not allocate dsyscall_struct");
+ goto out;
+ }
+
+ ds->args = args;
+ ds->func = func;
+ ds->id = dsyscall_next_id++;
+ ds->iteration = dsyscall_iterations;
+ if (!dsyscall_next_id) {
+ if (!++dsyscall_iterations) {
+ printk(KERN_WARNING "dsyscall: iterations has overflowed???");
+ }
+ }
+ strcpy(ds->name,name);
+
+ list_add(&ds->next,&dsyscall_syscalls);
+ dsyscall_hash_add(ds);
+
+ ret = 0;
+ out:
+ up_write(&dsyscall_sem);
+ return ret;
+}
+
+int dsyscall_unregister(char *name)
+{
+ struct dsyscall_struct *ds;
+
+ down_write(&dsyscall_sem);
+ if ((ds = find_dsyscall_by_name(name)) == NULL) {
+ printk("dsyscall: name %s is not registered\n",name);
+ up_write(&dsyscall_sem);
+ return -1;
+ }
+
+ list_del(&ds->next);
+ list_del(&ds->link);
+
+ up_write(&dsyscall_sem);
+
+ kmem_cache_free(dsyscall_cache,ds);
+
+ return 0;
+}
+
+EXPORT_SYMBOL_GPL(dsyscall_register);
+EXPORT_SYMBOL_GPL(dsyscall_unregister);
+
+int __init dsyscall_init(void)
+{
+ int i;
+
+ dsyscall_cache = kmem_cache_create("dsyscalls", sizeof(struct dsyscall_struct),
+ 0, 0, NULL, NULL);
+ if (!dsyscall_cache)
+ panic ("Can't allocate dsyscall cache!"); /* Too much? something else is wrong if
+ we fail here. */
+
+ for (i=0; i < DSYSCALL_HASH_SIZE; i++) {
+ INIT_LIST_HEAD(&dsyscall_hash[i]);
+ }
+
+ return 0;
+}
+__initcall(dsyscall_init);
Index: include/asm-i386/unistd.h
===================================================================
--- include/asm-i386/unistd.h (revision 15)
+++ include/asm-i386/unistd.h (working copy)
@@ -300,8 +300,9 @@
#define __NR_vperfctr_unlink (__NR_perfctr_info+3)
#define __NR_vperfctr_iresume (__NR_perfctr_info+4)
#define __NR_vperfctr_read (__NR_perfctr_info+5)
+#define __NR_dsyscall 295
-#define NR_syscalls 295
+#define NR_syscalls 296
/*
* user-visible error numbers are in the range -1 - -128: see
Index: include/linux/dsyscall.h
===================================================================
--- include/linux/dsyscall.h (revision 0)
+++ include/linux/dsyscall.h (revision 0)
@@ -0,0 +1,174 @@
+/*
+ * dsyscall.h
+ *
+ * Copyright (C) 2004 Steven Rostedt <steven.rostedt@kihontech.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#ifndef _LINUX_DSYSCALL_H
+#define _LINUX_DSYSCALL_H
+
+#define DSYSCALL_NAME_SZ 128
+#define DSYSCALL_MAX_ARGS 6
+
+enum dsyscall_cmd {
+ DSYSCALL_GET = 1,
+ DSYSCALL_CALL,
+};
+
+struct dsyscall {
+ char name[DSYSCALL_NAME_SZ]; /* Name of system call */
+ long id; /* unique id of available dynamic syscalls */
+ long iteration; /* incase this box runs longer than we have been on earth
+ count the iterations of id's. If interation overflows,
+ then we are simply out of luck! */
+ int argc; /* Number of arguments that this system call takes. */
+ long *argv; /* pointer to the argument list */
+};
+
+#define DSYSCALL_FUNC(func) ((int(*)(long,...))func)
+
+#ifdef __KERNEL__
+
+#include <linux/list.h>
+
+struct dsyscall_struct {
+ struct list_head next; /* list of all dynamic syscalls */
+ struct list_head link; /* used in the hash */
+ char name[DSYSCALL_NAME_SZ]; /* name of the dynamic syscall */
+ int args; /* number of arguments for this syscall */
+ int (*func)(long,...); /* The actual dynamic system call */
+ long id;
+ long iteration;
+
+};
+
+int dsyscall_register(char *name, int args, int (*func)(long,...));
+int dsyscall_unregister(char *name);
+
+#else /* !__KERNEL__ */
+
+/* OK, this should probably be in another file for users */
+#include <asm/unistd.h>
+
+#define _dsyscall_call(name,args,arg) \
+{ \
+ long __res; \
+ static int has_init = 0; \
+ static struct dsyscall ds; \
+ if (!has_init) { \
+ __res = dsyscall(DSYSCALL_GET,#name,&ds); \
+ if (!__res) \
+ has_init = 1; \
+ else \
+ return __res; \
+ } \
+ ds.argc = args; \
+ ds.argv = arg; \
+ __res = dsyscall(DSYSCALL_CALL,#name,&ds); \
+ if (__res < 0 && errno == ENODEV) { \
+ has_init = 0; \
+ } \
+ return __res; \
+}
+
+#define _dsyscall0(type,name) \
+type name(void) \
+{ \
+ long argv[0]; \
+ _dsyscall_call(name,0,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall1(type,name,type1,arg1) \
+type name(type1 arg1) \
+{ \
+ long argv[1]; \
+ argv[0] = (long)arg1; \
+ _dsyscall_call(name,1,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall2(type,name,type1,arg1,type2,arg2) \
+type name(type1 arg1, type2 arg2) \
+{ \
+ long argv[2]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ _dsyscall_call(name,2,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall3(type,name,type1,arg1,type2,arg2,type3,arg3) \
+type name(type1 arg1, type2 arg2, type3 arg3) \
+{ \
+ long argv[3]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ _dsyscall_call(name,3,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall4(type,name,type1,arg1,type2,arg2,type3,arg3, \
+ type4,arg4) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4) \
+{ \
+ long argv[4]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ _dsyscall_call(name,4,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall5(type,name,type1,arg1,type2,arg2,type3,arg3, \
+ type4,arg4,type5,arg5) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5) \
+{ \
+ long argv[5]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ _dsyscall_call(name,5,argv); \
+ return 0; /* not reached */ \
+}
+
+#define _dsyscall6(type,name,type1,arg1,type2,arg2,type3,arg3, \
+ type4,arg4,type5,arg5,type6,arg6) \
+type name(type1 arg1, type2 arg2, type3 arg3, type4 arg4, \
+ type5 arg5, type6 arg6) \
+{ \
+ long argv[6]; \
+ argv[0] = (long)arg1; \
+ argv[1] = (long)arg2; \
+ argv[2] = (long)arg3; \
+ argv[3] = (long)arg4; \
+ argv[4] = (long)arg5; \
+ argv[5] = (long)arg6; \
+ _dsyscall_call(name,6,argv); \
+ return 0; /* not reached */ \
+}
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_DSYSCALL_H */
Index: init/Kconfig
===================================================================
--- init/Kconfig (revision 15)
+++ init/Kconfig (working copy)
@@ -249,6 +249,14 @@
through /proc/config.gz.
+config DSYSCALL
+ bool "Enable dynamic system calls"
+ default y
+ help
+ This option enables usage of dynamic system calls by drivers.
+ This allows drivers to register system calls that are not
+ already defined by the compiled kernel.
+
menuconfig EMBEDDED
bool "Configure standard kernel features (for small systems)"
help
Index: arch/i386/kernel/entry.S
===================================================================
--- arch/i386/kernel/entry.S (revision 15)
+++ arch/i386/kernel/entry.S (working copy)
@@ -906,5 +906,10 @@
.long sys_vperfctr_unlink
.long sys_vperfctr_iresume
.long sys_vperfctr_read
+#ifdef CONFIG_DSYSCALL
+ .long sys_dsyscall /* 295 */
+#else
+ .long sys_ni_syscall /* 295 */
+#endif
syscall_table_size=(.-sys_call_table)
next prev parent reply other threads:[~2004-12-06 16:14 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-11-29 15:11 [PATCH][RFC] dynamic syscalls revisited Steven Rostedt
2004-11-29 15:17 ` Christoph Hellwig
2004-11-29 15:36 ` Steven Rostedt
2004-11-30 19:30 ` Kristian Sørensen
2004-11-29 16:41 ` [RFC] " Jan Engelhardt
2004-11-29 17:10 ` Steven Rostedt
2004-12-05 23:46 ` Adrian Bunk
2004-12-06 16:07 ` Steven Rostedt [this message]
2004-12-06 17:16 ` Steven Rostedt
2004-12-06 17:32 ` Zwane Mwaikambo
2004-12-06 17:57 ` linux-os
2004-12-06 18:03 ` Steven Rostedt
2004-12-06 18:18 ` Arjan van de Ven
2004-12-07 0:20 ` Michael Buesch
2004-12-07 0:57 ` Steven Rostedt
2004-12-06 21:14 ` H. Peter Anvin
2004-12-06 22:01 ` Steven Rostedt
2004-12-06 22:20 ` H. Peter Anvin
2004-12-06 22:38 ` Steven Rostedt
2004-12-14 23:14 ` Werner Almesberger
2004-12-15 2:14 ` Steven Rostedt
2004-12-15 3:35 ` Steven Rostedt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1102349255.25841.189.camel@localhost.localdomain \
--to=rostedt@goodmis.org \
--cc=bunk@stusta.de \
--cc=jengelh@linux01.gwdg.de \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.