Messages in this thread Patch in this message | | | Date | Fri, 12 Mar 1999 09:12:08 +0100 (MET) | From | Bernhard Kaindl <> | Subject | [fix] for NOT loading modules if driver is compiled-in and active. |
| |
Hi,
many drivers can't refuse to load as module just in case they are already compiled-in and running in the kernel. So the loading and unloading causes trouble, in this case. End result can be a hard kernel oops.
For example, serial.o has this problem, so if you boot a 2.2.3 with compiled-in serial.o, load the module (accidentally), and unload it. Then do a setserial on the devices and you get a pretty hard oops.
The attached patch for 2.2.3 can be used as an example how this could be prevented.
Interested developers should take a look at it and continue development. It also creates an nice /proc/feature if a driver is registered:
Name: serial, Version:4.27, Type:tty, Info:Serial driver
A broad use of this in a better format could be useful for supporters.
Bernhard
diff -rNu vanillas/223ac1/drivers/char/Makefile feat223ac1/drivers/char/Makefile --- vanillas/223ac1/drivers/char/Makefile Fri Mar 12 01:54:14 1999 +++ feat223ac1/drivers/char/Makefile Fri Mar 12 07:57:46 1999 @@ -21,7 +21,7 @@ L_TARGET := char.a M_OBJS := L_OBJS := tty_io.o n_tty.o tty_ioctl.o mem.o random.o -LX_OBJS := pty.o misc.o +LX_OBJS := pty.o misc.o feature.o ifdef CONFIG_VT L_OBJS += vt.o vc_screen.o consolemap.o consolemap_deftbl.o diff -rNu vanillas/223ac1/drivers/char/feature.c feat223ac1/drivers/char/feature.c --- vanillas/223ac1/drivers/char/feature.c Thu Jan 1 01:00:00 1970 +++ feat223ac1/drivers/char/feature.c Fri Mar 12 07:57:46 1999 @@ -0,0 +1,151 @@ +/* + * linux/drivers/char/feature.c + * + * Generic feature register routine by Bernhard Kaindl + * + * Based on code from Linus and Johan Myreen (misc.c) + * + */ + +#include <linux/module.h> +#include <linux/config.h> + +#include <linux/fs.h> +#include <linux/errno.h> +#include <linux/feature.h> +#include <linux/kernel.h> +#include <linux/major.h> +#include <linux/malloc.h> +#include <linux/proc_fs.h> +#include <linux/stat.h> +#include <linux/init.h> + +#include <linux/tty.h> +#include <linux/selection.h> +#include <linux/kmod.h> + +/* + * Head entry for the doubly linked featuredevice list + */ +static struct feature feature_list = { "head1", "head", NULL, NULL, &feature_list, &feature_list }; + +static int feature_read_proc(char *buf, char **start, off_t offset, + int len, int *eof, void *private) +{ + struct feature *p; + + len=0; + for (p = feature_list.next; p != &feature_list && len < 4000; p = p->next) + len += sprintf(buf+len, "Name: %s, Version:%s, Type:%s, Info:%s\n", + p->name ?: "", + p->version ?: "", + p->type ?: "", + p->info ?: "" + ); + *start = buf + offset; + return len > offset ? len - offset : 0; +} + +static int find_feature(const char * name) +{ + struct feature *p; + int len; + + len=0; + for (p = feature_list.next; p != &feature_list && len < 4000; p = p->next) { +/* + printk(KERN_INFO "Name: %s, Version:%s, Type:%s, Info:%s\n", + p->name ?: "", + p->version ?: "", + p->type ?: "", + p->info ?: "" + ); +*/ + if (strcmp(name, p->name) == 0) { + return 1; + } + } + return 0; +} + + +/* Interressant: (kmod-Support) +static int feature_open(struct inode * inode, struct file * file) +{ + int minor = MINOR(inode->i_rdev); + struct feature *c = feature_list.next; + file->f_op = NULL; + + while ((c != &feature_list) && (c->minor != minor)) + c = c->next; + if (c == &feature_list) { + char modname[20]; + sprintf(modname, "char-major-%d-%d", MISC_MAJOR, minor); + request_module(modname); + c = feature_list.next; + while ((c != &feature_list) && (c->minor != minor)) + c = c->next; + if (c == &feature_list) + return -ENODEV; + } + + if ((file->f_op = c->fops) && file->f_op->open) + return file->f_op->open(inode,file); + else + return -ENODEV; +} +*/ + +int register_feature(struct feature * feature) +{ + if (feature->next || feature->prev) + return -EBUSY; + + if (find_feature(feature->name)) { + printk(KERN_INFO "feature \"%s\" is already present!\n", feature->name); + return -EINVAL; + } + /* + * Add it to the front, so that later features can "override" + * earlier defaults + */ + feature->prev = &feature_list; + feature->next = feature_list.next; + feature->prev->next = feature; + feature->next->prev = feature; +/* + printk(KERN_INFO "Registered feature:\nName: %s, Version:%s, Type:%s, Info:%s\n", + feature->name ?: "", + feature->version ?: "", + feature->type ?: "", + feature->info ?: "" + ); +*/ + return 0; +} + +int deregister_feature(struct feature * feature) +{ + if (!feature->next || !feature->prev) + return -EINVAL; + feature->prev->next = feature->next; + feature->next->prev = feature->prev; + feature->next = NULL; + feature->prev = NULL; + return 0; +} + +EXPORT_SYMBOL(register_feature); +EXPORT_SYMBOL(deregister_feature); + +static struct proc_dir_entry *proc_feature; + +void __init feature_init(void) +{ +/* + printk("feature registration v0.2 by Bernhard Kaindl\n"); +*/ + proc_feature = create_proc_entry("feature", 0, 0); + if (proc_feature) + proc_feature->read_proc = feature_read_proc; +} diff -rNu vanillas/223ac1/drivers/char/serial.c feat223ac1/drivers/char/serial.c --- vanillas/223ac1/drivers/char/serial.c Thu Jan 14 19:27:53 1999 +++ feat223ac1/drivers/char/serial.c Fri Mar 12 07:59:58 1999 @@ -119,6 +119,7 @@ */ #include <linux/config.h> +#include <linux/feature.h> #include <linux/module.h> #include <linux/errno.h> #include <linux/signal.h> @@ -3067,6 +3068,20 @@ EXPORT_SYMBOL(register_serial); EXPORT_SYMBOL(unregister_serial); +static struct feature feature_definition = +{ + "serial", + "4.27", +/* + serial_version, +*/ + "tty", + "Serial driver" +/* + serial_name +*/ +}; + /* * The serial driver boot-time initialization code! */ @@ -3077,6 +3092,14 @@ extern void atomwide_serial_init (void); extern void dualsp_serial_init (void); +/* + printk(KERN_INFO "serial.o: Calling feature registration"); +*/ + if ((i = register_feature(&feature_definition)) != 0) { + printk(KERN_INFO "serial.o: Problem during feature registration\n"); + return i; + } + #ifdef CONFIG_ATOMWIDE_SERIAL atomwide_serial_init (); #endif @@ -3309,6 +3332,7 @@ free_page((unsigned long) tmp_buf); tmp_buf = NULL; } + deregister_feature(&feature_definition); } #endif /* MODULE */ diff -rNu vanillas/223ac1/include/linux/feature.h feat223ac1/include/linux/feature.h --- vanillas/223ac1/include/linux/feature.h Thu Jan 1 01:00:00 1970 +++ feat223ac1/include/linux/feature.h Fri Mar 12 07:57:46 1999 @@ -0,0 +1,18 @@ +#ifndef _LINUX_FEATURE_H +#define _LINUX_FEATURE_H + +extern void feature_init(void); + +struct feature +{ + const char *name; + const char *version; + const char *type; + const char *info; + struct feature * next, * prev; +}; + +extern int register_feature(struct feature * feature); +extern int deregister_feature(struct feature * feature); + +#endif diff -rNu vanillas/223ac1/init/main.c feat223ac1/init/main.c --- vanillas/223ac1/init/main.c Tue Mar 9 11:34:23 1999 +++ feat223ac1/init/main.c Fri Mar 12 07:57:47 1999 @@ -13,6 +13,7 @@ #include <linux/config.h> #include <linux/proc_fs.h> +#include <linux/feature.h> #include <linux/unistd.h> #include <linux/ctype.h> #include <linux/delay.h> @@ -1158,6 +1159,7 @@ #ifdef CONFIG_PROC_FS proc_root_init(); #endif + feature_init(); uidcache_init(); filescache_init(); dcache_init(); | |