Subject: Re: broken LKM, modload and so on.
To: None <current-users@netbsd.org>
From: MAEKAWA Masahide <bishop@rr.iij4u.or.jp>
List: current-users
Date: 09/09/2002 23:51:05
----Next_Part(Mon_Sep__9_23:51:05_2002_989)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

MAEKAWA Masahide <bishop@rr.iij4u.or.jp> wrote:
>Jaromir Dolecek <jdolecek@netbsd.org> wrote:
>>Please do NOT expose struct lkm_* to userland.
>
>How about attached one?

I have slightly modified.

Here is two types.
base1.diff/sys1.diff and base2.diff/sys2.diff

Type 1: base1 and sys1.diff
     The major number is unsigned 12 bit value.
     We can overload block/character majors into u_long variable and
     can split to two majors.
     These operations are wrapped by macros.

Type 2: base2.diff and sys2.diff
     The ``offset'' field is meaningful for LM_SYSCALL/LM_DEV.
     So remove this field and add union priv data.
     For LM_SYSCALL, define lmc_stat_syscall structure.
     For LM_DEV, define lmc_stat_dev structure.
     modload(8) call post script with
		3rd (syscall number) argument if LM_SYSCALL
		3rd (char major)/4th (block major) arguments if LM_DEV
		no more arguments if others.

Which is better? type 1? type 2? I can't decide...

--- MAEKAWA Masahide
--- Key fingerprint = BC5E D8CB 816C 2CB5 8560  FDE3 6CB8 BF5D 8D50 F2EE

----Next_Part(Mon_Sep__9_23:51:05_2002_989)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="base1.diff"

Index: sbin/modload/modload.c
===================================================================
RCS file: /cvsroot/cvs/NetBSD/basesrc/sbin/modload/modload.c,v
retrieving revision 1.30
diff -u -r1.30 modload.c
--- sbin/modload/modload.c	2001/11/08 15:33:15	1.30
+++ sbin/modload/modload.c	2002/09/09 12:59:24
@@ -454,21 +454,27 @@
 	 */
 	if (post) {
 		struct lmc_stat sbuf;
-		char id[16], type[16], offset[16];
+		char id[16], type[16], offset[2][16];
 
 		sbuf.id = resrv.slot;
 		if (ioctl(devfd, LMSTAT, &sbuf) == -1)
 			err(15, "error fetching module stats for post-install");
 		(void)snprintf(id, sizeof(id), "%d", sbuf.id);
 		(void)snprintf(type, sizeof(type), "0x%x", sbuf.type);
-		(void)snprintf(offset, sizeof(offset), "%ld",
-		    (long)sbuf.offset);
-		/*
-		 * XXX
-		 * The modload docs say that drivers can install bdevsw &
-		 * cdevsw, but the interface only supports one at a time.
-		 */
-		execl(post, post, id, type, offset, 0);
+		if (sbuf.type == LM_DEV) {
+			int bmajor, cmajor;
+			bmajor = block_major(sbuf.offset);
+			cmajor = char_major(sbuf.offset);
+			(void)snprintf(offset[0], sizeof(offset[0]), "%d",
+				cmajor);
+			(void)snprintf(offset[1], sizeof(offset[1]), "%d",
+				bmajor);
+			execl(post, post, id, type, offset[0], offset[1], 0);
+		} else {
+			(void)snprintf(offset[0], sizeof(offset[0]), "%ld",
+			    (long)sbuf.offset);
+			execl(post, post, id, type, offset[0], 0);
+		}
 		err(16, "can't exec `%s'", post);
 	}
 

----Next_Part(Mon_Sep__9_23:51:05_2002_989)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="sys1.diff"

Index: sys/kern/kern_lkm.c
===================================================================
RCS file: /cvsroot/cvs/NetBSD/syssrc/sys/kern/kern_lkm.c,v
retrieving revision 1.58
diff -u -r1.58 kern_lkm.c
--- sys/kern/kern_lkm.c	2002/09/06 13:23:47	1.58
+++ sys/kern/kern_lkm.c	2002/09/09 13:15:23
@@ -733,7 +733,7 @@
 	int cmd;
 {
 	struct lkm_dev *args = lkmtp->private.lkm_dev;
-	int error = 0;
+	int error;
 
 	switch(cmd) {
 	case LKM_E_LOAD:
@@ -744,6 +744,12 @@
 		error = devsw_attach(args->lkm_devname,
 				     args->lkm_bdev, &args->lkm_bdevmaj,
 				     args->lkm_cdev, &args->lkm_cdevmaj);
+		if (error != 0)
+			return (error);
+
+		args->lkm_offset = makemajor(args->lkm_bdevmaj,
+					     args->lkm_cdevmaj);
+
 		break;
 
 	case LKM_E_UNLOAD:
@@ -756,7 +762,7 @@
 		break;
 	}
 
-	return (error);
+	return (0);
 }
 
 #ifdef STREAMS
Index: sys/kern/subr_devsw.c
===================================================================
RCS file: /cvsroot/cvs/NetBSD/syssrc/sys/kern/subr_devsw.c,v
retrieving revision 1.2
diff -u -r1.2 subr_devsw.c
--- sys/kern/subr_devsw.c	2002/09/06 13:23:49	1.2
+++ sys/kern/subr_devsw.c	2002/09/09 01:32:43
@@ -172,9 +172,9 @@
 			}
 			if (i != max_devsw_convs)
 				continue;
-			*devmajor = bmajor;
 			break;
 		}
+		*devmajor = bmajor;
 	}
 	if (*devmajor >= MAXDEVSW) {
 #ifdef DEVSW_DEBUG
@@ -226,9 +226,9 @@
 			}
 			if (i != max_devsw_convs)
 				continue;
-			*devmajor = cmajor;
 			break;
 		}
+		*devmajor = cmajor;
 	}
 	if (*devmajor >= MAXDEVSW) {
 #ifdef DEVSW_DEBUG
Index: sys/sys/lkm.h
===================================================================
RCS file: /cvsroot/cvs/NetBSD/syssrc/sys/sys/lkm.h,v
retrieving revision 1.21
diff -u -r1.21 lkm.h
--- sys/sys/lkm.h	2002/09/06 13:24:09	1.21
+++ sys/sys/lkm.h	2002/09/09 12:55:14
@@ -392,4 +392,8 @@
 	int	ver;			/* OUT: lkm compile version */
 };
 
+#define	makemajor(b, c)		((((b) & 0xffff) << 16) | ((c) & 0xffff))
+#define	block_major(v)		(int)((int16_t)(((v) >> 16) & 0xffff))
+#define	char_major(v)		(int)((int16_t)((v) & 0xffff))
+
 #endif	/* !_SYS_LKM_H_ */

----Next_Part(Mon_Sep__9_23:51:05_2002_989)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="base2.diff"

Index: sbin/modload/modload.c
===================================================================
RCS file: /cvsroot/cvs/NetBSD/basesrc/sbin/modload/modload.c,v
retrieving revision 1.30
diff -u -r1.30 modload.c
--- sbin/modload/modload.c	2001/11/08 15:33:15	1.30
+++ sbin/modload/modload.c	2002/09/09 14:34:24
@@ -454,21 +454,38 @@
 	 */
 	if (post) {
 		struct lmc_stat sbuf;
-		char id[16], type[16], offset[16];
+		char id[16], type[16];
 
 		sbuf.id = resrv.slot;
 		if (ioctl(devfd, LMSTAT, &sbuf) == -1)
 			err(15, "error fetching module stats for post-install");
 		(void)snprintf(id, sizeof(id), "%d", sbuf.id);
 		(void)snprintf(type, sizeof(type), "0x%x", sbuf.type);
-		(void)snprintf(offset, sizeof(offset), "%ld",
-		    (long)sbuf.offset);
-		/*
-		 * XXX
-		 * The modload docs say that drivers can install bdevsw &
-		 * cdevsw, but the interface only supports one at a time.
-		 */
-		execl(post, post, id, type, offset, 0);
+		switch (sbuf.type) {
+		case LM_SYSCALL:
+		    {
+			struct lmc_stat_syscall *sys = &sbuf.priv.u_syscall;
+			char arg[16];
+
+			(void)snprintf(arg, sizeof(arg), "%ld",
+				       (long)sys->number);
+			execl(post, post, id, type, arg);
+		    }
+		case LM_DEV:
+		    {
+			struct lmc_stat_dev *dev = &sbuf.priv.u_dev;
+			char args[2][16];
+
+			(void)snprintf(args[0], sizeof(args[0]), "%d",
+				       dev->cmajor);
+			(void)snprintf(args[1], sizeof(args[1]), "%d",
+				       dev->bmajor);
+			execl(post, post, id, type, args[0], args[1], 0);
+		    }
+		default:
+			execl(post, post, id, type, 0);
+			break;
+		}
 		err(16, "can't exec `%s'", post);
 	}
 

----Next_Part(Mon_Sep__9_23:51:05_2002_989)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="sys2.diff"

Index: sys/kern/kern_lkm.c
===================================================================
RCS file: /cvsroot/cvs/NetBSD/syssrc/sys/kern/kern_lkm.c,v
retrieving revision 1.58
diff -u -r1.58 kern_lkm.c
--- sys/kern/kern_lkm.c	2002/09/06 13:23:47	1.58
+++ sys/kern/kern_lkm.c	2002/09/09 14:10:32
@@ -546,7 +546,6 @@
 		 * Copy out stat information for this module...
 		 */
 		statp->id	= curp->id;
-		statp->offset	= curp->private.lkm_any->lkm_offset;
 		statp->type	= curp->private.lkm_any->lkm_type;
 		statp->area	= curp->area;
 		statp->size	= curp->size / PAGESIZE;
@@ -556,6 +555,28 @@
 			  statp->name,
 			  MAXLKMNAME - 2,
 			  (size_t *)0);
+
+		switch (statp->type) {
+		case LM_SYSCALL:
+		    {
+			struct lkm_syscall *sys = curp->private.lkm_syscall;
+			struct lmc_stat_syscall *lmc_sys =
+				&statp->priv.u_syscall;
+			lmc_sys->number = sys->lkm_offset;
+			break;
+		    }
+		case LM_DEV:
+		    {
+			struct lkm_dev *dev = curp->private.lkm_dev;
+			struct lmc_stat_dev *lmc_dev = &statp->priv.u_dev;
+			lmc_dev->bmajor = dev->lkm_bdevmaj;
+			lmc_dev->cmajor = dev->lkm_cdevmaj;
+			break;
+		    }
+		default:
+			/* do nothing */
+			break;
+		}
 
 		break;
 
Index: sys/kern/subr_devsw.c
===================================================================
RCS file: /cvsroot/cvs/NetBSD/syssrc/sys/kern/subr_devsw.c,v
retrieving revision 1.2
diff -u -r1.2 subr_devsw.c
--- sys/kern/subr_devsw.c	2002/09/06 13:23:49	1.2
+++ sys/kern/subr_devsw.c	2002/09/09 01:32:43
@@ -172,9 +172,9 @@
 			}
 			if (i != max_devsw_convs)
 				continue;
-			*devmajor = bmajor;
 			break;
 		}
+		*devmajor = bmajor;
 	}
 	if (*devmajor >= MAXDEVSW) {
 #ifdef DEVSW_DEBUG
@@ -226,9 +226,9 @@
 			}
 			if (i != max_devsw_convs)
 				continue;
-			*devmajor = cmajor;
 			break;
 		}
+		*devmajor = cmajor;
 	}
 	if (*devmajor >= MAXDEVSW) {
 #ifdef DEVSW_DEBUG
Index: sys/sys/lkm.h
===================================================================
RCS file: /cvsroot/cvs/NetBSD/syssrc/sys/sys/lkm.h,v
retrieving revision 1.21
diff -u -r1.21 lkm.h
--- sys/sys/lkm.h	2002/09/06 13:24:09	1.21
+++ sys/sys/lkm.h	2002/09/09 13:47:58
@@ -381,15 +381,28 @@
 /*
  * Get module information for a given id (or name if id == -1).
  */
+
+struct lmc_stat_syscall {
+	int	number;			/* system call number */
+};
+
+struct lmc_stat_dev {
+	int	bmajor;			/* block device major number */
+	int	cmajor;			/* character device major number */
+};
+
 struct lmc_stat {
 	int	id;			/* IN: module ID to unload */
 	char	name[MAXLKMNAME];	/* IN/OUT: name of module */
-	u_long	offset;			/* OUT: target table offset */
 	MODTYPE	type;			/* OUT: type of module */
 	u_long	area;			/* OUT: kernel load addr */
 	u_long	size;			/* OUT: module size (pages) */
 	u_long	private;		/* OUT: module private data */
 	int	ver;			/* OUT: lkm compile version */
+	union {
+		struct lmc_stat_syscall	u_syscall;
+		struct lmc_stat_dev	u_dev;
+	} priv;
 };
 
 #endif	/* !_SYS_LKM_H_ */

----Next_Part(Mon_Sep__9_23:51:05_2002_989)----