diff options
author | Andy Lutomirski <luto@kernel.org> | 2019-09-27 10:24:03 -0700 |
---|---|---|
committer | Andy Lutomirski <luto@kernel.org> | 2019-09-27 10:24:03 -0700 |
commit | 87757db3d4177bcbee0d60ab2ebb47f08ce18c66 (patch) | |
tree | 1aef7ddc2483087363c6420d19c73333a098bd1b | |
parent | efedddfdaae95579238d303245e3601239d1557c (diff) | |
parent | c6ad9bb7cc29ac75ae8a455e38bd82e81d6d4df2 (diff) | |
download | virtme-87757db3d4177bcbee0d60ab2ebb47f08ce18c66.tar.gz |
Merge branch 'kmod'
This is hopefully good enough for master now.
-rwxr-xr-x | bin/virtme-prep-kdir-mods | 38 | ||||
-rwxr-xr-x | setup.py | 3 | ||||
-rw-r--r-- | virtme/commands/run.py | 71 | ||||
-rwxr-xr-x | virtme/guest/virtme-init | 10 | ||||
-rw-r--r-- | virtme/guest_tools.py | 25 | ||||
l--------- | virtme/scripts | 1 |
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" @@ -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 |