Subject: Re: LKM support for many filesystems as well as compat_freebsd
To: Jason Thorpe <thorpej@nas.nasa.gov>
From: Michael Graff <explorer@flame.org>
List: tech-kern
Date: 08/12/1996 18:25:28
Jason Thorpe <thorpej@nas.nasa.gov> writes:

> Could you post an overview of your current approach?

Well, since you asked.  I was going to do this anyway, to avoid repeated
and useless work, but I think having made both freebsd and linux emulation
into lkm's at least shows that this is a possible approach.

EMULATION
---------

First, there are many changes to portions of the kernel which are not
contained in compat/foo.  For example, kern_prot contains this:

int
sys_getpid(p, v, retval)
        struct proc *p;
        void *v;
        register_t *retval;
{

        *retval = p->p_pid;
#if defined(COMPAT_43) || defined(COMPAT_SUNOS) || defined(COMPAT_IBCS2) || \
    defined(COMPAT_FREEBSD)
        retval[1] = p->p_pptr->p_pid;
#endif
        return (0);
}

Since this code is enabled anytime COMPAT_FREEBSD is compiled in, I assume
it doesn't hurt to have it "always" work.  I changed the
	defined(COMPAT_FREEBSD)
part to read
	defined(COMPAT_FREEBSD) || defined(COMPAT_FREEBSD_LKM)
in this case, and I use
	options COMPAT_FREEBSD_LKM
in my config file.  It could be argued that this is a hack and should be
based on which emulation is currently active rather than a compile-time
hook, but this was easier as an experiment.

Also, there are some portions of code which actually check to see which
emulation mode a program is running in, using
	#ifdef COMPAT_LINUX
	               /* Linux has a special system setup call as number 0 */
	              if (p->p_emul == &emul_linux_aout ||
	                  p->p_emul == &emul_linux_elf) { ... }

I replaced the COMPAT_LINUX portion as above, and replaced the check with
		      if (p->p_emul == emul_linux_aout || ...

I then added, to a new file I called compat_lkm.c for lack of a better
name for this experiment:
	#if defined(COMPAT_LINUX)
	struct emul *emul_linux_aout = &_emul_linux_aout;
	struct emul *emul_linux_elf = &_emul_linux_elf;
	#else
	#if defined(COMPAT_LINUX_LKM)
	struct emul *emul_linux_aout = NULL;
	struct emul *emul_linux_elf = NULL;
	#endif
	#endif

I taught the lkm load routine to DTRT with these, setting it to the correct
value on load and back to NULL on unload.

One thing I don't know for certain is what happens if you try to unload
freebsd when something is being run in freebsd emulation mode.  I suspect
Bad Things.


FILESYSTEMS
-----------

For filesystems which don't require syscalls, they Just Work.  I just
take the files the filesystem would normally compile into the kernel,
compile them, and link them in.

Type    Id  Off Loadaddr Size Info     Rev Module Name
VFS       0  21 f881e000 0020 f8825000   1 msdosfs
VFS       1  20 f8828000 000c f882a000   1 procfs
VFS       2  19 f882e000 0008 f882f000   1 kernfs
VFS       3  18 f8830000 0014 f8834000   1 cd9660
VFS       4  17 f8836000 0008 f8837000   1 mfs

All of those work just fine.

For filesystems which require syscalls or other kernel modifications, I am
somewhat stuck.  I don't know how exactly to do that yet, so currently
I just don't load those.  This includes NFS, lfs, and perhaps ffs.

GENERAL
-------
I think it would be a really nice to have a way to query "support levels"
for this stuff.  I have started on this somewhat.  More or less, I have
a structure like
	struct kern_conf {
		char	*kc_name;
		int	 kc_support;
		int	 kc_status;
	};

The name are things like "compat_freebsd" or "insecure".  The kc_support
values are one of COMPILED_IN, LOADABLE, or NONE.  The kc_status values
are LOADED or UNLOADED, depending on if the support is active or not.

This allows the LKM loader portion to look at the kernel's suport level for
various things and make certain what it needs is indeed there.

Comments welcome, and expected.

--Michael