Subject: LKM versioning patch
To: None <tech-kern@netbsd.org>
From: Jaromir Dolecek <jdolecek@netbsd.org>
List: tech-kern
Date: 05/03/2003 10:32:35
Here is the patch I made according to previous discussion. Currently
it refuses to load the LKM if any of DIAGNOSTIC, DEBUG, LOCKDEBUG
and MULTIPROCESSOR options are different, as well as LKM_VERSION
and __NetBSD_Version__. I changed some interface, taking advantage
of the necessary LKM_VERSION bump. The string 'evnronment depends'
are not imlemented yet, so it's not possible for the LKM to say
it depends on some of the options only.

Only two LKM lkminit_foo.c file changes included; others
are changed accordingly.

Opinions welcome.

Jaromir

Index: sys/lkm.h
===================================================================
RCS file: /cvsroot/src/sys/sys/lkm.h,v
retrieving revision 1.27
diff -u -p -r1.27 lkm.h
--- sys/lkm.h	2003/04/10 19:06:04	1.27
+++ sys/lkm.h	2003/05/03 08:26:17
@@ -53,7 +53,7 @@ typedef enum loadmod {
 	LM_MISC,
 } MODTYPE;
 
-#define	LKM_VERSION	1		/* version of module loader */
+#define	LKM_VERSION	2		/* version of module loader */
 #define	MAXLKMNAME	32
 
 /****************************************************************************/
@@ -140,7 +140,7 @@ struct lkm_compat {
 struct lkm_misc {
 	MODTYPE	lkm_type;
 	int	lkm_ver;
-	char	*lkm_name;
+	const char	*lkm_name;
 	u_long	lkm_offset;
 };
 
@@ -150,7 +150,7 @@ struct lkm_misc {
 struct lkm_any {
 	MODTYPE	lkm_type;
 	int	lkm_ver;
-	char	*lkm_name;
+	const char	*lkm_name;
 	u_long	lkm_offset;
 };
 
@@ -180,12 +180,11 @@ struct lkm_table {
 	u_long	area;
 	char	used;
 
-	int	ver;		/* version (INIT) */
 	int	refcnt;		/* reference count (INIT) */
 	int	depcnt;		/* dependency count (INIT) */
 	int	id;		/* identifier (INIT) */
 
-	int	(*entry) __P((struct lkm_table *, int, int));/* entry function */
+	int	(*entry) __P((struct lkm_table *, int));/* entry function */
 	union lkm_generic	private;	/* module private data */
 
 				/* ddb support */
@@ -258,24 +257,65 @@ struct lkm_table {
 		name				\
 	};
 
+/*
+ * Environment encoding, for LKM-kernel compatibility check.
+ */
+#ifdef DIAGNOSTIC
+#define _LKM_E_DIAGNOSTIC	1
+#else
+#define _LKM_E_DIAGNOSTIC	0
+#endif
+
+#ifdef DEBUG
+#define _LKM_E_DEBUG	2
+#else
+#define _LKM_E_DEBUG	0
+#endif
+
+#ifdef LOCKDEBUG
+#define _LKM_E_LOCKDEBUG	4
+#else
+#define _LKM_E_LOCKDEBUG	0
+#endif
+
+#ifdef MULTIPROCESSOR
+#define _LKM_E_MULTIPROCESSOR	8
+#else
+#define _LKM_E_MULTIPROCESSOR	0
+#endif
+
+#define	_LKM_ENV_VERSION	\
+	(_LKM_E_DEBUG | _LKM_E_DIAGNOSTIC | _LKM_E_LOCKDEBUG \
+	| _LKM_E_MULTIPROCESSOR)
+#define _LKM_ENV_FMT		\
+	"\20\01DIAGNOSTIC"	\
+	"\02DEBUG"		\
+	"\03LOCKDEBUG"		\
+	"\04MULTIPROCESSOR"		
+	
 
 extern int	lkm_nofunc __P((struct lkm_table *lkmtp, int cmd));
 extern int	lkmexists __P((struct lkm_table *));
 extern int	lkmdispatch __P((struct lkm_table *, int));
+extern int	lkm_checkver __P((struct lkm_any *, int, int, int, const char *));
 
 /*
- * DISPATCH -- body function for use in module entry point function;
+ * LKM_DISPATCH -- body function for use in module entry point function;
  * generally, the function body will consist entirely of a single
- * DISPATCH line.
+ * LKM_DISPATCH line.
  *
  * If load/unload/stat are called on each corresponding entry instance.
  * If no function is desired for load/stat/unload, lkm_nofunc() should
  * be specified.  "cmd" is passed to each function so that a single
  * function can be used if desired.
  */
-#define	DISPATCH(lkmtp,cmd,ver,load,unload,stat)			\
-	if (ver != LKM_VERSION)						\
-		return EINVAL;	/* version mismatch */		\
+#define LKM_CHECKVER(envdep)	\
+	if (lkm_checkver((void *)&_module, LKM_VERSION,			\
+	    __NetBSD_Version__,	_LKM_ENV_VERSION, envdep))		\
+		return EPROGMISMATCH	/* version mismatch */
+	
+#define	LKM_DISPATCH(lkmtp, envdep, cmd, load, unload, stat)		\
+	LKM_CHECKVER(envdep);						\
 	switch (cmd) {							\
 	int	error;							\
 	case LKM_E_LOAD:						\
Index: kern/kern_lkm.c
===================================================================
RCS file: /cvsroot/src/sys/kern/kern_lkm.c,v
retrieving revision 1.64
diff -u -p -r1.64 kern_lkm.c
--- kern/kern_lkm.c	2003/04/10 19:06:05	1.64
+++ kern/kern_lkm.c	2003/05/03 08:26:17
@@ -270,7 +270,6 @@ lkmioctl(dev, cmd, data, flag, p)
 		}
 		curp = &lkmods[i];
 		curp->id = i;		/* self reference slot offset */
-		curp->ver = LKM_VERSION;
 
 		resrvp->slot = i;		/* return slot */
 
@@ -411,11 +410,11 @@ lkmioctl(dev, cmd, data, flag, p)
 			memset((caddr_t)curp->area + curp->offset, 0,
 			       curp->size - curp->offset);
 
-		curp->entry = (int (*) __P((struct lkm_table *, int, int)))
+		curp->entry = (int (*) __P((struct lkm_table *, int)))
 				(*((long *) (data)));
 
 		/* call entry(load)... (assigns "private" portion) */
-		error = (*(curp->entry))(curp, LKM_E_LOAD, curp->ver);
+		error = (*(curp->entry))(curp, LKM_E_LOAD);
 		if (error) {
 			/*
 			 * Module may refuse loading or may have a
@@ -502,7 +501,7 @@ lkmioctl(dev, cmd, data, flag, p)
 		}
 
 		/* call entry(unload) */
-		if ((*(curp->entry))(curp, LKM_E_UNLOAD, curp->ver)) {
+		if ((*(curp->entry))(curp, LKM_E_UNLOAD)) {
 			error = EBUSY;
 			break;
 		}
@@ -555,7 +554,7 @@ lkmioctl(dev, cmd, data, flag, p)
 			break;
 		}
 
-		if ((error = (*curp->entry)(curp, LKM_E_STAT, curp->ver)))
+		if ((error = (*curp->entry)(curp, LKM_E_STAT)))
 			break;
 
 		/*
@@ -567,7 +566,7 @@ lkmioctl(dev, cmd, data, flag, p)
 		statp->area	= curp->area;
 		statp->size	= curp->size / PAGESIZE;
 		statp->private	= (unsigned long)curp->private.lkm_any;
-		statp->ver	= curp->private.lkm_any->lkm_ver;
+		statp->ver	= LKM_VERSION;
 		copystr(curp->private.lkm_any->lkm_name, 
 			  statp->name,
 			  MAXLKMNAME - 2,
@@ -934,4 +933,45 @@ lkmdispatch(lkmtp, cmd)
 	}
 
 	return (error);
+}
+
+/*
+ * Check LKM version against current kernel.
+ */
+int
+lkm_checkver(struct lkm_any *mod, int lkmver, int kernver, int envver,
+	const char *envdep)
+{
+	if (lkmver != LKM_VERSION) {
+		printf("LKM '%s': LKM version mismatch - LKM %d, kernel %d\n",
+		    mod->lkm_name, lkmver, LKM_VERSION);
+		return (1);
+	}
+
+	if (kernver != __NetBSD_Version__) {
+		printf("LKM '%s': kernel version mismatch - LKM %d, kernel %d\n",
+		    mod->lkm_name, kernver, __NetBSD_Version__);
+		return (2);
+	}
+
+	/*
+	 * Following might eventually be changed to take into account envdep,
+	 * if it's non-NULL.
+	 */
+	if (envver != _LKM_ENV_VERSION) {
+		char lbuf[32], kbuf[32];
+
+		bitmask_snprintf(envver, _LKM_ENV_FMT, lbuf, sizeof(lbuf));
+		bitmask_snprintf(_LKM_ENV_VERSION, _LKM_ENV_FMT,
+		    kbuf, sizeof(kbuf));
+
+		printf("LKM '%s': environment options mismatch - LKM '%s', kernel '%s'\n",
+		    mod->lkm_name, lbuf, kbuf);
+		return (3);
+	}
+
+	/*
+	 * Basic parameters match, LKM is likely to be compatible.
+	 */
+	return (0);
 }
Index: lkm/vfs/smbfs/lkminit_vfs.c
===================================================================
RCS file: /cvsroot/src/sys/lkm/vfs/smbfs/lkminit_vfs.c,v
retrieving revision 1.1
diff -u -p -r1.1 lkminit_vfs.c
--- lkm/vfs/smbfs/lkminit_vfs.c	2003/04/02 09:45:44	1.1
+++ lkm/vfs/smbfs/lkminit_vfs.c	2003/05/03 08:26:17
@@ -49,7 +49,7 @@ __KERNEL_RCSID(0, "$NetBSD: lkminit_vfs.
 #include <sys/file.h>
 #include <sys/errno.h>
 
-int smbfs_lkmentry __P((struct lkm_table *, int, int));
+int smbfs_lkmentry __P((struct lkm_table *, int));
 
 /*
  * This is the vfsops table for the file system in question
@@ -65,11 +65,10 @@ MOD_VFS("smbfs", -1, &smbfs_vfsops);
  * entry point
  */
 int
-smbfs_lkmentry(lkmtp, cmd, ver)
+smbfs_lkmentry(lkmtp, cmd)
 	struct lkm_table *lkmtp;	
 	int cmd;
-	int ver;
 {
 
-	DISPATCH(lkmtp, cmd, ver, lkm_nofunc, lkm_nofunc, lkm_nofunc)
+	LKM_DISPATCH(lkmtp, NULL, cmd, lkm_nofunc, lkm_nofunc, lkm_nofunc)
 }
Index: lkm/vfs/ufs/lfs/lkminit_vfs.c
===================================================================
RCS file: /cvsroot/src/sys/lkm/vfs/ufs/lfs/lkminit_vfs.c,v
retrieving revision 1.6
diff -u -p -r1.6 lkminit_vfs.c
--- lkm/vfs/ufs/lfs/lkminit_vfs.c	2003/03/15 07:20:23	1.6
+++ lkm/vfs/ufs/lfs/lkminit_vfs.c	2003/05/03 08:31:02
@@ -60,7 +60,7 @@ struct lfs_sysent {
 	struct sysent sysent;
 };
 
-int lfs_lkmentry __P((struct lkm_table *, int, int));
+int lfs_lkmentry __P((struct lkm_table *, int));
 static int lfs_load __P((struct lkm_table *, int));
 static int lfs_unload __P((struct lkm_table *, int));
 
@@ -94,20 +94,18 @@ MOD_VFS("lfs", -1, &lfs_vfsops);
  * entry point
  */
 int
-lfs_lkmentry(lkmtp, cmd, ver)
+lfs_lkmentry(lkmtp, cmd)
 	struct lkm_table *lkmtp;	
 	int cmd;
-	int ver;
 {
 	int error;
 
 	/*
 	 * Since we need to call lkmdispatch() first, we can't use
-	 * DISPATCH().
+	 * LKM_DISPATCH().
 	 */
 
-	if (ver != LKM_VERSION)
-		return EINVAL;	/* version mismatch */
+	LKM_CHECKVER(NULL);
 
 	/* do this first, lkmdispatch() expects this to be already filled in */
 	if (cmd == LKM_E_LOAD)
-- 
Jaromir Dolecek <jdolecek@NetBSD.org>            http://www.NetBSD.org/
-=- We should be mindful of the potential goal, but as the tantric    -=-
-=- Buddhist masters say, ``You may notice during meditation that you -=-
-=- sometimes levitate or glow.   Do not let this distract you.''     -=-