aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@kernel.org>2019-09-27 10:24:03 -0700
committerAndy Lutomirski <luto@kernel.org>2019-09-27 10:24:03 -0700
commit87757db3d4177bcbee0d60ab2ebb47f08ce18c66 (patch)
tree1aef7ddc2483087363c6420d19c73333a098bd1b
parentefedddfdaae95579238d303245e3601239d1557c (diff)
parentc6ad9bb7cc29ac75ae8a455e38bd82e81d6d4df2 (diff)
downloadvirtme-87757db3d4177bcbee0d60ab2ebb47f08ce18c66.tar.gz
Merge branch 'kmod'
This is hopefully good enough for master now.
-rwxr-xr-xbin/virtme-prep-kdir-mods38
-rwxr-xr-xsetup.py3
-rw-r--r--virtme/commands/run.py71
-rwxr-xr-xvirtme/guest/virtme-init10
-rw-r--r--virtme/guest_tools.py25
l---------virtme/scripts1
6 files changed, 130 insertions, 18 deletions
diff --git a/bin/virtme-prep-kdir-mods b/bin/virtme-prep-kdir-mods
new file mode 100755
index 0000000..be28fb6
--- /dev/null
+++ b/bin/virtme-prep-kdir-mods
@@ -0,0 +1,38 @@
+#!/bin/sh
+
+# This is still a bit of an experiment.
+
+if ! [ -d .tmp_versions ]; then
+ echo 'virtme-prep-kdir-mods must be run from a kernel build directory' >&2
+ exit 1
+fi
+
+FAKEVER=0.0.0
+MODDIR=".virtme_mods/lib/modules/$FAKEVER"
+
+if ! [ -f "modules.order" ]; then
+ echo "modules.order is missing. Your kernel may be too old or you didn't make modules." >&2
+ exit 1
+fi
+
+# Set up .virtme_mods/lib/modules/0.0.0 as a module directory for this kernel,
+# but fill it with symlinks instead of actual modules.
+
+mkdir -p "$MODDIR/kernel"
+ln -srfT . "$MODDIR/build"
+
+# Remove all preexisting symlinks and add symlinks to all modules that belong
+# to the build kenrnel.
+find "$MODDIR/kernel" -type l -print0 |xargs -0 rm -f --
+while read -r i; do
+ [ ! -e "$i" ] && i=$(echo "$i" | sed s:^kernel/::)
+ mkdir -p "$MODDIR/kernel/$(dirname "$i")"
+ ln -sr "$i" "$MODDIR/kernel/$i"
+done < modules.order
+
+
+# Link in the files that make modules_install would copy
+ln -srf modules.builtin modules.builtin.modinfo modules.order "$MODDIR/"
+
+# Now run depmod to collect dependencies
+depmod -ae -F System.map -b .virtme_mods "$FAKEVER"
diff --git a/setup.py b/setup.py
index 9f7dc63..03c6061 100755
--- a/setup.py
+++ b/setup.py
@@ -29,6 +29,9 @@ setup(
'virtme-configkernel = virtme.commands.configkernel:main',
]
},
+ scripts = [
+ 'bin/virtme-prep-kdir-mods',
+ ],
package_data = {
'virtme.guest': [
'virtme-init',
diff --git a/virtme/commands/run.py b/virtme/commands/run.py
index ae1b4fa..e0a00eb 100644
--- a/virtme/commands/run.py
+++ b/virtme/commands/run.py
@@ -15,6 +15,7 @@ import sys
import shlex
import re
import itertools
+import pkg_resources
from .. import virtmods
from .. import modfinder
from .. import mkinitramfs
@@ -41,6 +42,9 @@ def make_parser():
help='Use a compiled kernel source directory')
g = parser.add_argument_group(title='Kernel options')
+ g.add_argument('--mods', action='store', metavar='none|use|auto', default='use',
+ help='Setup loadable kernel modules inside a compiled kernel source directory (used in conjunction with --kdir); none: ignore kernel modules, use: asks user to refresh virtme\'s kernel modules directory, auto: automatically refreshes virtme\'s kernel modules directory')
+
g.add_argument('-a', '--kopt', action='append', default=[],
help='Add a kernel option. You can specify this more than once.')
@@ -113,12 +117,18 @@ def make_parser():
_ARGPARSER = make_parser()
-def arg_fail(message):
+def arg_fail(message, show_usage=True):
print(message)
- _ARGPARSER.print_usage()
+ if show_usage:
+ _ARGPARSER.print_usage()
sys.exit(1)
+def is_file_more_recent(a, b):
+ return os.stat(a).st_mtime > os.stat(b).st_mtime
+
def find_kernel_and_mods(arch, args):
+ use_root_mods = False
+
if args.installed_kernel is not None:
kver = args.installed_kernel
modfiles = modfinder.find_modules_from_install(
@@ -128,21 +138,47 @@ def find_kernel_and_mods(arch, args):
if not os.path.exists(kimg):
kimg = '/boot/vmlinuz-%s' % kver
dtb = None # For now
+ use_root_mods = True
elif args.kdir is not None:
kimg = os.path.join(args.kdir, arch.kimg_path())
- modfiles = []
- moddir = None
+ virtme_mods = os.path.join(args.kdir, '.virtme_mods')
+ mod_file = os.path.join(args.kdir, 'modules.order')
+ virtme_mod_file = os.path.join(virtme_mods, 'lib/modules/0.0.0/modules.dep')
- # Once kmod gets fixed (if ever), we can do something like:
- # modfiles = modfinder.find_modules_from_install(
- # virtmods.MODALIASES,
- # moddir=os.path.join(args.kernel_build_dir, '.tmp_moddir'))
+ # Kernel modules support
+ kver = None
+ moddir = None
+ modfiles = []
+ if args.mods == 'none':
+ pass
+ elif args.mods == 'use' or args.mods == 'auto':
+ # Check if modules.order exists, otherwise it's not possible to use
+ # this option
+ if not os.path.exists(mod_file):
+ arg_fail('%s not found: kernel modules not enabled or kernel not compiled properly' % mod_file, show_usage=False)
+ # Check if virtme's kernel modules directory needs to be updated
+ if not os.path.exists(virtme_mods) or \
+ is_file_more_recent(mod_file, virtme_mod_file):
+ if args.mods == 'use':
+ # Inform user to manually refresh virtme's kernel modules
+ # directory
+ arg_fail("please run virtme-prep-kdir-mods to update virtme's kernel modules directory or use --mods=auto", show_usage=False)
+ else:
+ # Auto-refresh virtme's kernel modules directory
+ guest_tools.run_script('virtme-prep-kdir-mods')
+ moddir = os.path.join(virtme_mods, 'lib/modules', '0.0.0')
+ modfiles = modfinder.find_modules_from_install(
+ virtmods.MODALIASES, root=virtme_mods, kver='0.0.0')
+ else:
+ arg_fail("invalid argument '%s', please use --mods=none|use|auto" % args.mods)
dtb_path = arch.dtb_path()
if dtb_path is None:
dtb = None
else:
dtb = os.path.join(args.kdir, dtb_path)
+ elif args.mods is not None:
+ arg_fail("--mods must be used together with --kdir")
elif args.kimg is not None:
kimg = args.kimg
modfiles = []
@@ -151,7 +187,7 @@ def find_kernel_and_mods(arch, args):
else:
arg_fail('You must specify a kernel to use.')
- return kimg,dtb,modfiles,moddir
+ return kimg,dtb,modfiles,moddir,use_root_mods
def export_virtfs(qemu, arch, qemuargs, path, mount_tag, security_model='none', readonly=True):
# NB: We can't use -virtfs for this, because it can't handle a mount_tag
@@ -189,7 +225,7 @@ def main():
config = mkinitramfs.Config()
- kimg,dtb,modfiles,moddir = find_kernel_and_mods(arch, args)
+ kimg,dtb,modfiles,moddir,use_root_mods = find_kernel_and_mods(arch, args)
config.modfiles = modfiles
if config.modfiles:
need_initramfs = True
@@ -216,9 +252,20 @@ def main():
'/bin/mount -n -t 9p -o ro,version=9p2000.L,trans=virtio,access=any virtme.guesttools /run/virtme/guesttools',
'exec /run/virtme/guesttools/virtme-init']
- # Map modules
+ # Arrange for modules to end up in the right place
if moddir is not None:
- export_virtfs(qemu, arch, qemuargs, moddir, 'virtme.moddir')
+ if use_root_mods:
+ # Tell virtme-init to use the root /lib/modules
+ kernelargs.append("virtme_root_mods=1")
+ else:
+ # We're grabbing modules from somewhere other than /lib/modules.
+ # Rather than mounting it separately, symlink it in the guest.
+ # This allows symlinks within the module directory to resolve
+ # correctly in the guest.
+ kernelargs.append("virtme_link_mods=/%s" % qemu.quote_optarg(os.path.relpath(moddir, args.root)))
+ else:
+ # No modules are available. virtme-init will hide /lib/modules/KVER
+ pass
# Set up mounts
mount_index = 0
diff --git a/virtme/guest/virtme-init b/virtme/guest/virtme-init
index cd3caa4..f60faa5 100755
--- a/virtme/guest/virtme-init
+++ b/virtme/guest/virtme-init
@@ -27,10 +27,12 @@ done
kver="`uname -r`"
-if [[ -n "${mount_tags[virtme.moddir]}" ]]; then
- mount -t tmpfs none /lib/modules
- mkdir /lib/modules/"$kver"
- mount -n -t 9p -o ro,version=9p2000.L,trans=virtio,access=any virtme.moddir /lib/modules/"$kver"
+if [[ -n "$virtme_root_mods" ]]; then
+ # /lib/modules is already set up
+ true
+elif [[ -n "$virtme_link_mods" ]]; then
+ mount -n -t tmpfs none /lib/modules
+ ln -s "$virtme_link_mods" "/lib/modules/$kver"
elif [[ -d "/lib/modules/$kver" ]]; then
# We may have mismatched modules. Mask them off.
mount -n -t tmpfs -o ro,mode=0000 disallow_modules "/lib/modules/$kver"
diff --git a/virtme/guest_tools.py b/virtme/guest_tools.py
index 96c1cc2..b84f761 100644
--- a/virtme/guest_tools.py
+++ b/virtme/guest_tools.py
@@ -1,14 +1,16 @@
# -*- mode: python -*-
# resources.py: Find virtme's resources
-# Copyright © 2014 Andy Lutomirski
+# Copyright © 2014-2019 Andy Lutomirski
# Licensed under the GPLv2, which is available in the virtme distribution
# as a file called LICENSE with SHA-256 hash:
# 8177f97513213526df2cf6184d8ff986c675afb514d4e68a404010521b880643
-"""Helpers to find virtme's guest tools."""
+"""Helpers to find virtme's guest tools and host scripts."""
import os
+import shutil
import pkg_resources
+import subprocess
def find_guest_tools():
"""Return the path of the guest tools installed with the running virtme.
@@ -19,3 +21,22 @@ def find_guest_tools():
# No luck. This is somewhat surprising.
return None
+
+def find_script(name):
+ # If we're running out of a source checkout, we can find scripts through
+ # the 'virtme/scripts' symlink.
+ fn = pkg_resources.resource_filename(__name__, 'scripts/%s' % name)
+ if os.path.isfile(fn):
+ return fn
+
+ # Otherwise assume we're actually installed and in PATH.
+ fn = shutil.which(name)
+ if fn is not None:
+ return fn
+
+ # No luck. This is somewhat surprising.
+ raise Exception('could not find script %s' % name)
+
+def run_script(name):
+ fn = find_script(name)
+ subprocess.check_call(executable=fn, args=[fn])
diff --git a/virtme/scripts b/virtme/scripts
new file mode 120000
index 0000000..19f285a
--- /dev/null
+++ b/virtme/scripts
@@ -0,0 +1 @@
+../bin \ No newline at end of file