You are not logged in.

#1 2020-12-28 11:47:43

Skunky
Member
Registered: 2018-01-25
Posts: 231

DKMS - how to build only for certain kernels?

I think Kernel & Hardware is the most appropiate subforum because the subject is Dynamic Kernel Module Support but please feel free to move this post anywhere else.

When i update, the thing that take the longest time to complete is the dkms install part, this is because i have different kernels installed and dkms build modules for every kernel i got installed

e.g.

[ALPM] running '70-dkms-upgrade.hook'...
[ALPM-SCRIPTLET] ==> dkms remove --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.4.85-1-lts
[ALPM-SCRIPTLET] ==> dkms remove --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-zen1-1-zen
[ALPM-SCRIPTLET] ==> dkms remove --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-arch1-1
[ALPM] transaction started
[ALPM] reinstalled virtualbox-host-dkms (6.1.16-4)
[ALPM] transaction completed
[ALPM] running '30-systemd-update.hook'...
[ALPM] running '70-dkms-install.hook'...
[ALPM-SCRIPTLET] ==> dkms install --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.4.85-1-lts
[ALPM-SCRIPTLET] ==> dkms install --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-zen1-1-ze
[ALPM-SCRIPTLET] ==> dkms install --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-arch1-1
[ALPM-SCRIPTLET] ==> depmod 5.8.7-arch1-1
[ALPM-SCRIPTLET] ==> depmod 5.4.85-1-lts
[ALPM-SCRIPTLET] ==> depmod 5.8.7-zen1-1-zen

My question is, how can i tell dkms hook to only build for the LTS kernel for example? I tried changing /usr/share/libalpm/hooks/70-dkms-install.hook by myself but ended up not building anything at all

[Trigger]
Operation = Install
Operation = Upgrade
Type = Path
Target = usr/src/*/dkms.conf ############### i tried usr/src/linux-lts and lib/modules/5.4.85-1-lts/build/ but neither worked, if someone would be so kind to explain why i would appreciate it alot ###############
Target = usr/lib/modules/*/build/include/
Target = usr/lib/modules/*/modules.alias

[Action]
Description = Install DKMS modules
Depends = dkms
When = PostTransaction
Exec = /usr/lib/dkms/alpm-hook install
NeedsTargets

Is it possible without uninstalling other kernels?

Offline

#2 2020-12-28 11:58:58

schard
Forum Moderator
From: Hannover
Registered: 2016-05-06
Posts: 2,653
Website

Re: DKMS - how to build only for certain kernels?

Have a look at the BUILD_EXCLUSIVE_KERNEL directive of the dkms.conf of the respective DKMS module.

Last edited by schard (2020-12-30 11:33:49)


Inofficial first vice president of the Rust Evangelism Strike Force

Offline

#3 2020-12-28 11:59:45

loqs
Member
Registered: 2014-03-06
Posts: 18,920

Re: DKMS - how to build only for certain kernels?

What about:

Type = Package
Target = linux-lts

Also I would suggest overriding the hook using /etc/pacman.d/hooks/70-dkms-install.hook so your changes do not get overwritten.

Offline

#4 2020-12-28 13:01:10

Skunky
Member
Registered: 2018-01-25
Posts: 231

Re: DKMS - how to build only for certain kernels?

@schard according to the man i have to edit /usr/src/vboxhost-6.1.16_OSE/dkms.conf right? My changes disappear (overwritten?) when i reinstall virtualbox-host-dkms, here is how i changed the file

## @file
# Linux DKMS config script for the VirtualBox guest kernel modules
#

#
# Copyright (C) 2006-2015 Oracle Corporation
#
# This file is part of VirtualBox Open Source Edition (OSE), as
# available from http://www.virtualbox.org. This file is free software;
# you can redistribute it and/or modify it under the terms of the GNU
# General Public License (GPL) as published by the Free Software
# Foundation, in version 2 as it comes in the "COPYING" file of the
# VirtualBox OSE distribution. VirtualBox OSE is distributed in the
# hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
#

PACKAGE_NAME="vboxhost"
PACKAGE_VERSION=6.1.16_OSE
AUTOINSTALL=yes

BUILT_MODULE_NAME[0]="vboxdrv"
BUILT_MODULE_LOCATION[0]="vboxdrv"
DEST_MODULE_LOCATION[0]="/kernel/misc"

BUILT_MODULE_NAME[1]="vboxnetflt"
BUILT_MODULE_LOCATION[1]="vboxnetflt"
DEST_MODULE_LOCATION[1]="/kernel/misc"

BUILT_MODULE_NAME[2]="vboxnetadp"
BUILT_MODULE_LOCATION[2]="vboxnetadp"
DEST_MODULE_LOCATION[2]="/kernel/misc"
BUILD_EXCLUSIVE_KERNEL="^5.8.*" #####i added this#####

And when i reinstall nothing is build

sudo pacman -S virtualbox-host-dkms                                                                                                [0]
warning: virtualbox-host-dkms-6.1.16-4 is up to date -- reinstalling
resolving dependencies...
looking for conflicting packages...

Packages (1) virtualbox-host-dkms-6.1.16-4

Total Installed Size:  10.01 MiB
Net Upgrade Size:       0.00 MiB

:: Proceed with installation? [Y/n]
(1/1) checking keys in keyring                                                                  [########################################################] 100%
(1/1) checking package integrity                                                                [########################################################] 100%
(1/1) loading package files                                                                     [########################################################] 100%
(1/1) checking for file conflicts                                                               [########################################################] 100%
(1/1) checking available disk space                                                             [########################################################] 100%
:: Running pre-transaction hooks...
(1/1) Remove upgraded DKMS modules
==> Unable to remove module vboxhost/6.1.16_OSE for kernel 5.8.7-zen1-1-zen: Not found in dkms status output.
==> Unable to remove module vboxhost/6.1.16_OSE for kernel 5.8.7-arch1-1: Not found in dkms status output.
:: Processing package changes...
(1/1) reinstalling virtualbox-host-dkms                                                         [########################################################] 100%
:: Running post-transaction hooks...
(1/1) Arming ConditionNeedsUpdate...

@loqs Weird, still nothing gets build, i'm doing this right?

cat /etc/pacman.d/hooks/70-dkms-install.hook   
[Trigger]
Operation = Install
Operation = Upgrade
Type = Package
Target = linux-lts
Target = usr/lib/modules/*/build/include/
Target = usr/lib/modules/*/modules.alias

[Action]
Description = Install DKMS modules
Depends = dkms
When = PostTransaction
Exec = /usr/lib/dkms/alpm-hook install
NeedsTargets

Thank you both for your precious help

Last edited by Skunky (2020-12-28 13:37:24)

Offline

#5 2020-12-28 16:04:18

Ropid
Member
Registered: 2015-03-09
Posts: 1,069

Re: DKMS - how to build only for certain kernels?

What happens if you remove the "...-headers" package for the kernels you don't want a module for? DKMS can't compile the module if there's no headers, maybe it won't even see the kernels where there's no headers and won't error out.

Last edited by Ropid (2020-12-28 16:05:55)

Offline

#6 2020-12-29 19:10:06

Skunky
Member
Registered: 2018-01-25
Posts: 231

Re: DKMS - how to build only for certain kernels?

Thanks for your answer but i would just remove the kernel packages i dont wan't to build at that point, thank you

Offline

#7 2020-12-29 20:36:41

loqs
Member
Registered: 2014-03-06
Posts: 18,920

Re: DKMS - how to build only for certain kernels?

Nasty hack,  what if after undoing the other changes in /usr/lib/dkms/alpm-hook you change check_buildexclusive() to

check_buildexclusive() {
  local BUILD_EXCLUSIVE_KERNEL=$(source "$source_tree/$1-$2/dkms.conf"; printf '%s\n' "$BUILD_EXCLUSIVE_KERNEL")
  [[ "$3" =~ $BUILD_EXCLUSIVE_KERNEL  || "$3" =~ 5.4 ]]
}

Last edited by loqs (2020-12-29 20:37:32)

Offline

#8 2020-12-30 08:15:01

Skunky
Member
Registered: 2018-01-25
Posts: 231

Re: DKMS - how to build only for certain kernels?

Seems like that change does absolutely nothing, vboxhost module still gets build for all installed kernels

/usr/lib/dkms/alpm-hook

#!/bin/bash

#
# Copyright © 2018-2020, Sébastien Luttringer
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

# display what to run and run it quietly
run() {
  echo "==> $*"
  "$@" > /dev/null
  local ret=$?
  (( $ret )) && echo "==> Warning, \`$*' returned $ret"
  return $ret
}

# check whether the dependencies of a module are installed
# $1: module name
# $2: module version
# $3: kernel version
check_dependency() { (
  source "$source_tree/$1-$2/dkms.conf"
  local mod lines line
  for mod in "${BUILD_DEPENDS[@]}"; do
    mapfile lines < <(dkms status -m "$mod" -k "$3")
    for line in "${lines[@]}"; do
      [[ "$line" =~ "$mod, "[^,]+", $3, "[^:]+': installed' ]] && break 2
    done
    exit 1
  done
  exit 0
) }

# check whether the modules should be built with this kernel version
# $1: module name
# $2: module version
# $3: kernel version
check_buildexclusive() {
  local BUILD_EXCLUSIVE_KERNEL=$(source "$source_tree/$1-$2/dkms.conf"; printf '%s\n' "$BUILD_EXCLUSIVE_KERNEL")
  [[ "$3" =~ $BUILD_EXCLUSIVE_KERNEL  || "$3" =~ 5.4 ]]
}

# handle actions on module addition/upgrade/removal
# $1: module name
# $2: module version
parse_module() {
  pushd "$install_tree" >/dev/null
  local path
  for path in */build/; do
    local kver="${path%%/*}"
    dkms_register "$1" "$2" "$kver"
  done
  popd >/dev/null
}

# handle actions on kernel addition/upgrade/removal
# $1: kernel version
parse_kernel() {
  local path
  for path in "$source_tree"/*-*/dkms.conf; do
    if [[ -f "$path" && "$path" =~ ^$source_tree/([^/]+)-([^/]+)/dkms\.conf$ ]]; then
      dkms_register "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "$1"
    fi
  done
}

# register a dkms module to install/remove
# this function suppress echo call for a module
# $1: module name, $2: module version, $3: kernel version
dkms_register() {
  DKMS_MODULES["$1/$2/$3"]=''
}

# install registered modules
dkms_install() {
  local nvk mod mver kver
  local -i retry=1
  local -A dmods=()

  while (( $retry > 0 )); do
    retry=0
    for nvk in "${!DKMS_MODULES[@]}"; do
      [[ "$nvk" =~ ([^/]+)/([^/]+)/(.+) ]]
      mod="${BASH_REMATCH[1]}"
      mver="${BASH_REMATCH[2]}"
      kver="${BASH_REMATCH[3]}"
      # do not build excluded modules
      if ! check_buildexclusive "$mod" "$mver" "$kver"; then
        unset DKMS_MODULES[$nvk]
        continue
      # skip modules with missing kernel headers
      elif [[ ! -d "$install_tree/$kver/build/include" ]]; then
        DKMS_MODULES[$nvk]='Missing kernel headers'
        continue
      # skip modules with missing kernel package
      elif [[ ! -d "$install_tree/$kver/kernel" ]]; then
        DKMS_MODULES[$nvk]='Missing kernel modules tree'
        continue
      # postpone modules with missing dependencies
      elif ! check_dependency "$mod" "$mver" "$kver"; then
        DKMS_MODULES[$nvk]='Missing dependency'
        continue
      fi
      # give it a try dkms
      run dkms install --no-depmod -m "$mod" -v "$mver" -k "$kver"
      dmods[$kver]=''
      unset DKMS_MODULES[$nvk]
      # maybe this module was a dep of another, so we retry
      retry=1
    done
  done
  # run depmod later for performance improvments
  if (( $DKMS_DEPMOD )); then
    for kver in "${!dmods[@]}"; do
      run depmod "$kver"
    done
  fi
}

# remove registered modules when built/installed
# run depmod later for performance improvments
dkms_remove() {
  local nvk mod mver kver state
  local -A dmods=()
  for nvk in "${!DKMS_MODULES[@]}"; do
    [[ "$nvk" =~ ([^/]+)/([^/]+)/(.+) ]]
    mod="${BASH_REMATCH[1]}"
    mver="${BASH_REMATCH[2]}"
    kver="${BASH_REMATCH[3]}"
    # do not remove excluded modules (n.b. display not found errors)
    if ! check_buildexclusive "$mod" "$mver" "$kver"; then
      unset DKMS_MODULES[$nvk]
      continue
    fi
    state=$(dkms status -m "$mod" -v "$mver" -k "$kver")
    if [[ "$state" =~ "$mod, $mver, $kver, "[^:]+": "(added|built|installed) ]]; then
      dmods[$kver]=''
      run dkms remove --no-depmod -m "$mod" -v "$mver" -k "$kver"
      if (( $? == 0 )); then
        unset DKMS_MODULES[$nvk]
      else
        DKMS_MODULES[$nvk]='dkms remove failed'
      fi
    else
      DKMS_MODULES[$nvk]='Not found in dkms status output'
    fi
  done
  # run depmod later for performance improvments
  if (( $DKMS_DEPMOD )); then
    for kver in "${!dmods[@]}"; do
      run depmod "$kver"
    done
  fi
}

# show information about failed modules
show_errors() {
  local nvk mod kver
  for nvk in "${!DKMS_MODULES[@]}"; do
    mod=${nvk%/*}
    kver=${nvk##*/}
    echo "==> Unable to $DKMS_ACTION module $mod for kernel $kver: ${DKMS_MODULES[$nvk]}."
  done
}

# display hook usage and exit $1 (default 1)
usage() {
  cat << EOF >&2
usage: ${0##*/} <options> install|remove
options: -D  Do not run depmod
EOF
  exit ${1:-1}
}

# emulated program entry point
main() {
  [[ "$DKMS_ALPM_HOOK_DEBUG" ]] && set -x

  # prevent each dkms call from failing with authorization errors
  if (( EUID )); then
    echo 'You must be root to use this hook' >&2
    exit 1
  fi

  # parse command line options
  declare -i DKMS_DEPMOD=1
  local opt
  while getopts 'hD' opt; do
    case $opt in
      D) DKMS_DEPMOD=0;;
      *) usage;;
    esac
  done
  shift $((OPTIND - 1))
  (( $# != 1 )) && usage

  # register DKMS action
  case "$1" in
    install|remove)
      declare -r DKMS_ACTION="$1";;
    *) usage;;
  esac

  # dkms path from framework config
  # note: the alpm hooks which trigger this script use static path
  source_tree='/usr/src'
  install_tree='/usr/lib/modules'
  source /etc/dkms/framework.conf

  # check source_tree and install_tree exists
  local path
  for path in "$source_tree" "$install_tree"; do
    if [[ ! -d "$path" ]]; then
      echo "==> Missing mandatory directory: $path. Exiting!"
      return 1
    fi
  done

  # storage for DKMS modules to install/remove
  # we use associate arrays to prevent duplicate
  declare -A DKMS_MODULES

  # parse stdin paths to guess what do do
  while read -r path; do
    if [[ "/$path" =~ ^$source_tree/([^/]+)-([^/]+)/dkms\.conf$ ]]; then
      parse_module "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
    elif [[ "/$path" =~ ^$install_tree/([^/]+)/ ]]; then
      parse_kernel "${BASH_REMATCH[1]}"
    fi
  done

  dkms_$DKMS_ACTION

  show_errors

  return 0
}

main "$@"

Pacman output

[PACMAN] Running 'pacman -S virtualbox-host-dkms'
[ALPM] running '70-dkms-upgrade.hook'...
[ALPM-SCRIPTLET] ==> dkms remove --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.4.85-1-lts
[ALPM-SCRIPTLET] ==> dkms remove --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-zen1-1-zen
[ALPM-SCRIPTLET] ==> dkms remove --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-arch1-1
[ALPM] transaction started
[ALPM] reinstalled virtualbox-host-dkms (6.1.16-4)
[ALPM] transaction completed
[ALPM] running '30-systemd-update.hook'...
[ALPM] running '70-dkms-install.hook'...
[ALPM-SCRIPTLET] ==> dkms install --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.4.85-1-lts
[ALPM-SCRIPTLET] ==> dkms install --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-zen1-1-zen
[ALPM-SCRIPTLET] ==> dkms install --no-depmod -m vboxhost -v 6.1.16_OSE -k 5.8.7-arch1-1
[ALPM-SCRIPTLET] ==> depmod 5.8.7-arch1-1
[ALPM-SCRIPTLET] ==> depmod 5.4.85-1-lts
[ALPM-SCRIPTLET] ==> depmod 5.8.7-zen1-1-zen

I also tried || "$3" =~ 5.8.7 ]]   same results, i'm worried there is something really wrong with my system now

Last edited by Skunky (2020-12-30 08:17:18)

Offline

#9 2020-12-30 10:40:19

loqs
Member
Registered: 2014-03-06
Posts: 18,920

Re: DKMS - how to build only for certain kernels?

$ [[ "5.8.7" =~ 5.4 ]] && echo match
$ [[ "5.8.7" =~ 5.8 ]] && echo match
match

Most likely I am not understanding what the function is intended to do.

Offline

#10 2020-12-30 11:03:25

progandy
Member
Registered: 2012-05-17
Posts: 5,317

Re: DKMS - how to build only for certain kernels?

check_buildexclusive checks if dkmsis allowed to build the module for the current kernel version. The value can be empty. In that case, the build is allowed as well. The hack should require both conditions (&& instead of ||):

test:

$ BUILD_EXCLUSIVE_KERNEL= ; [[ "5.8" =~ $BUILD_EXCLUSIVE_KERNEL  || "5.8" =~ 5.4 ]] && echo match
match
$ BUILD_EXCLUSIVE_KERNEL= ; [[ "5.8" =~ $BUILD_EXCLUSIVE_KERNEL  && "5.8" =~ 5.4 ]] && echo match
$ BUILD_EXCLUSIVE_KERNEL= ; [[ "5.4" =~ $BUILD_EXCLUSIVE_KERNEL  && "5.4" =~ 5.4 ]] && echo match
match
check_buildexclusive() {
  local BUILD_EXCLUSIVE_KERNEL=$(source "$source_tree/$1-$2/dkms.conf"; printf '%s\n' "$BUILD_EXCLUSIVE_KERNEL")
  [[ "$3" =~ $BUILD_EXCLUSIVE_KERNEL  && "$3" =~ 5.4 ]]
}

Last edited by progandy (2020-12-30 11:04:45)


| alias CUTF='LANG=en_XX.UTF-8@POSIX ' | alias ENGLISH='LANG=C.UTF-8 ' |

Offline

#11 2020-12-30 22:38:28

Skunky
Member
Registered: 2018-01-25
Posts: 231

Re: DKMS - how to build only for certain kernels?

It does work, awesome! Now, is it safe to modify /usr/lib/dkms/alpm-hook? Is there a better way? Also with this metod, i guess i will have to change the kernel version when needed
Thanks everyone for your help, appreciate it so much

Last edited by Skunky (2020-12-30 22:39:10)

Offline

Board footer

Powered by FluxBB