lkml.org 
[lkml]   [1999]   [Mar]   [12]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
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();
\
 
 \ /
  Last update: 2005-03-22 13:50    [W:0.047 / U:0.064 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site