Subject: kern/2950: Union file system cannot be built as LKM
To: None <gnats-bugs@gnats.netbsd.org>
From: None <paul.goyette@pgoyette.bdt.com>
List: netbsd-bugs
Date: 11/17/1996 17:55:16
>Number:         2950
>Category:       kern
>Synopsis:       Union file system cannot be built as LKM
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sun Nov 17 18:05:01 1996
>Last-Modified:
>Originator:     Paul Goyette
>Organization:
self
>Release:        Nov 15, 1996
>Environment:
System: NetBSD pgoyette.bdt.com 1.2B NetBSD 1.2B (PGOYETTE) 
	#145: Sat Nov 16 10:42:15 PST 1996 
	root@:/home/paul/src/sys/arch/mac68k/compile/PGOYETTE 
	(current as of Fri Nov 15 04:29:13 1996) mac68k
>Description:
	Attempting to build kernel without Options UNION removes all
	support for the Union file system.  Building with the Option
	defined includes the file system code in the kernel proper.

	There is no standard way to build a kernel with the necessary
	support in kern/vfs_syscalls.c and compat/common/vfs_syscalls_43.c
	without including the entire file system code in the kernel.
>How-To-Repeat:
	See above.
>Fix:
	The attached patch implements a new kernel option, UNIONLKM, which
	builds in the required support in the above-mentioned modules
	without having to include the whole file system in the kernel.

	The patch works by building in a new data structure that contains
	the pointers used by the vfs_syscalls routines.  This data structure
	is initialized to NULLs, and is filled in by the lkm initialization
	code in sys/lkm/vfs/miscfs/union/vfs_lkminit.c.  That routine also
	resets the data structure to NULLs if the lkm is unloaded.

	For systems without UNIONLKM defined, there is absolutely no change 
	from current behaviour.  In fact, the identical code is generated,
	since all the changes are contingent upon UNIONLKM.


--- /usr/src/sys/kern/vfs_syscalls.c	Thu Oct 24 04:19:12 1996
+++ /home/paul/src/sys/kern/vfs_syscalls.c	Sun Nov 17 17:20:55 1996
@@ -63,7 +63,21 @@
 
 void checkdirs __P((struct vnode *));
 int dounmount __P((struct mount *, int, struct proc *));
-
+/*
+ * Redirection info so we don't have to include the union fs routines in 
+ * the kernel directly.  This way, we can build unionfs as an LKM.  The
+ * fields get filled in later, when we modload the LKM.
+ */
+#ifdef UNIONLKM
+	struct union_info_desc {
+		int (**l_union_vnodeop_p) __P((void *));
+		struct vnode * (*l_union_dircache) __P((struct vnode *));
+	};
+	struct union_info_desc union_info = {
+		0,
+		NULL
+	};
+#endif
 /*
  * Virtual File System System Calls
  */
@@ -1974,16 +1988,25 @@
 	if (error)
 		return (error);
 
-#ifdef UNION
+#if	defined(UNION) || defined(UNIONLKM)
 {
+#ifdef UNION
 	extern int (**union_vnodeop_p) __P((void *));
 	extern struct vnode *union_dircache __P((struct vnode *));
-
+#endif
 	if ((SCARG(uap, count) == auio.uio_resid) &&
+#ifdef UNION
 	    (vp->v_op == union_vnodeop_p)) {
+#else
+	    (vp->v_op == union_info.l_union_vnodeop_p)) {
+#endif
 		struct vnode *lvp;
 
+#ifdef UNION
 		lvp = union_dircache(vp);
+#else
+		lvp = union_info.l_union_dircache(vp);
+#endif
 		if (lvp != NULLVP) {
 			struct vattr va;
 
@@ -2016,7 +2039,7 @@
 		}
 	}
 }
-#endif /* UNION */
+#endif /* UNION || UNIONLKM */
 
 	if ((SCARG(uap, count) == auio.uio_resid) &&
 	    (vp->v_flag & VROOT) &&
--- /usr/src/sys/compat/common/vfs_syscalls_43.c	Fri Mar 15 04:41:06 1996
+++ /home/paul/src/sys/compat/common/vfs_syscalls_43.c	Sun Nov 17 17:24:24 1996
@@ -64,6 +64,13 @@
 
 static void cvtstat __P((struct stat *, struct ostat *));
 
+#ifdef UNIONLKM
+	struct union_info_desc {
+		int (**l_union_vnodeop_p) __P((void *));
+		struct vnode * (*l_union_dircache) __P((struct vnode *));
+	};
+	extern struct union_info_desc union_info;
+#endif
 /*
  * Convert from an old to a new stat structure.
  */
@@ -451,19 +458,28 @@
 	if (error)
 		return (error);
 
-#ifdef UNION
+#if	defined(UNION) || defined(UNIONLKM)
 {
+#ifdef UNION
 	extern int (**union_vnodeop_p) __P((void *));
 	extern struct vnode *union_dircache __P((struct vnode *));
-
-	if ((SCARG(uap, count) == auio.uio_resid) &&
+#endif
+ 	if ((SCARG(uap, count) == auio.uio_resid) &&
+#ifdef UNION
 	    (vp->v_op == union_vnodeop_p)) {
-		struct vnode *lvp;
-
+#else
+	    (vp->v_op == union_info.l_union_vnodeop_p)) {
+#endif
+ 		struct vnode *lvp;
+ 
+#ifdef UNION
 		lvp = union_dircache(vp);
-		if (lvp != NULLVP) {
-			struct vattr va;
-
+#else
+		lvp = union_info.l_union_dircache(vp);
+#endif
+ 		if (lvp != NULLVP) {
+ 			struct vattr va;
+ 
 			/*
 			 * If the directory is opaque,
 			 * then don't show lower entries
@@ -493,7 +509,7 @@
 		}
 	}
 }
-#endif /* UNION */
+#endif /* UNION || UNIONLKM */
 
 	if ((SCARG(uap, count) == auio.uio_resid) &&
 	    (vp->v_flag & VROOT) &&
--- /usr/src/sys/lkm/vfs/miscfs/union/lkminit_vfs.c	Mon Oct 14 09:40:58 1996
+++ /home/paul/src/sys/lkm/vfs/miscfs/union/lkminit_vfs.c	Sun Nov 17 13:34:51 1996
@@ -45,7 +45,17 @@
  */
 extern struct vfsops union_vfsops;
 extern struct vnodeopv_desc union_vnodeop_opv_desc;
-
+/*
+ * This structure contains a couple of pointers that vfs_syscalls (and
+ * vfs_syscalls_43) need to reference.  This indirect structure allows
+ * us to build the kernel without the union code, but still support
+ * union fs's via the lkm method.
+ */
+struct union_info_desc {
+	int (**l_union_vnodeop_p) __P((void *));
+	struct vnode * (*l_union_dircache) __P((struct vnode *));
+};
+extern struct union_info_desc union_info;
 /*
  * declare the filesystem
  */
@@ -68,5 +78,30 @@
 	vfs_opv_init_explicit(&union_vnodeop_opv_desc);
 	vfs_opv_init_default(&union_vnodeop_opv_desc);
 
-	DISPATCH(lkmtp, cmd, ver, lkm_nofunc, lkm_nofunc, lkm_nofunc)
+	DISPATCH(lkmtp, cmd, ver, union_load, union_load, lkm_nofunc)
+}
+/*
+ * Routine to execute when module is loaded or unloaded.  We need to set
+ * a couple of critical pointers for the vfs_syscalls routines.
+ */
+int
+union_load(lkmtp, cmd)
+	struct lkm_table *lkmtp;
+	int cmd;
+	{
+	extern int (**union_vnodeop_p) __P((void *));
+	extern struct vnode *union_dircache __P((struct vnode *));
+
+	switch (cmd) {
+	case LKM_E_LOAD:
+		union_info.l_union_vnodeop_p = union_vnodeop_p;
+		union_info.l_union_dircache  = union_dircache;
+		break;
+
+	case LKM_E_UNLOAD:
+		union_info.l_union_vnodeop_p = NULL;
+		union_info.l_union_dircache  = NULL;
+		break;
+	};
+	return (0);
 }
>Audit-Trail:
>Unformatted: