Skip to content

An out-of-tree GPU or storage kernel module stops building after a kernel upgrade

DKMS rebuilds out-of-tree modules against each new kernel, but it can only recompile the source it was given. When the kernel removes or renames an internal function the module calls, the rebuild fails with an implicit declaration error and the node comes back from its upgrade without GPUDirect, without its parallel filesystem client, or in some cases without a working driver at all.

Quick answer

Read the first error in /var/lib/dkms/<module>/<version>/build/make.log. It names the removed or renamed kernel function. The fix is a module release that supports the running kernel, not a change to your configuration.

Infrastructure#dkms#kernel-module#implicit-declaration#gpudirect#peermem#kernel-upgrade

What this failure is

A post-upgrade build failure in which DKMS recompiles an out-of-tree kernel module against a kernel whose internal API has changed, so the module fails to compile or fails to load and the capability it provided disappears without an explicit alert.

Why it happens (the mechanism)

Linux deliberately keeps no stable in-kernel API, so anything living outside the tree must track it. DKMS exists to rebuild those modules automatically and does exactly that, which means it will rebuild source the kernel has outgrown and surface the disagreement as a compile error. The upgrade succeeds from the package manager's point of view because the package is still installed; only the module is missing.

What you'll observe

  • A node reboots after routine patching and loses a capability nothing in the change record touched
  • The failure is a compiler error in a log nobody reads, not an alert
  • The module built correctly on this machine last month against the previous kernel
  • Rolling the kernel back restores service, which makes the vendor look blameless and the kernel look at fault

Common symptoms and what they mean

SymptomWhy it happens
error: implicit declaration of function, naming a kernel helper the module callsThe kernel offers no stable internal API. Functions are renamed, moved between headers, or deleted between releases, and out-of-tree code that calls them has to be updated in step. DKMS automates recompilation, not adaptation, so it faithfully rebuilds source that no longer matches the target and reports the mismatch as a compiler error.
A compiler suggestion of the form did you mean, naming the renamed replacementA missing declaration is fatal rather than a warning because the build treats implicit function declarations as errors. That is deliberate: a silently assumed signature would produce a module that loads and then corrupts memory, which is far worse on a node holding GPU mappings.
The installed module version is incompatible with the running kernel versionThe blast radius is wider than the module because these components sit under a capability rather than an application. A peer-memory module that fails to build does not announce that GPUDirect is gone; the fabric simply falls back to a slower path, or the mount that needed it is absent, and the first symptom is a performance or availability change nobody connects to a patch.
A kernel and module version mismatch, where the module release predates the kernel it is being built againstThe kernel offers no stable internal API. Functions are renamed, moved between headers, or deleted between releases, and out-of-tree code that calls them has to be updated in step. DKMS automates recompilation, not adaptation, so it faithfully rebuilds source that no longer matches the target and reports the mismatch as a compiler error.
Build output under /var/lib/dkms/<module>/<version>/build/make.log ending at the first such errorA missing declaration is fatal rather than a warning because the build treats implicit function declarations as errors. That is deliberate: a silently assumed signature would produce a module that loads and then corrupts memory, which is far worse on a node holding GPU mappings.
modprobe reporting that it could not insert the module, or dmesg reporting an unknown symbolThe blast radius is wider than the module because these components sit under a capability rather than an application. A peer-memory module that fails to build does not announce that GPUDirect is gone; the fabric simply falls back to a slower path, or the mount that needed it is absent, and the first symptom is a performance or availability change nobody connects to a patch.

Which systems are affected

  • GPUDirect Storage and RDMA stacks, where peer-memory modules bridge the GPU driver and the fabric
  • Parallel filesystem clients built as out-of-tree modules, including BeeGFS with GPU Direct support
  • NVIDIA driver DKMS packages on distributions that ship kernels faster than the driver supports them
  • Any cluster where unattended upgrades can move the kernel without moving the drivers with it

How to confirm this is the problem

Apply the following checklist to a small reproduction: each box below is a positive signal that you are looking at this exact failure rather than a sibling in the same taxonomy.

  • Open /var/lib/dkms/<module>/<version>/build/make.log and take the first error line; it names the symbol and the source file, which is the whole diagnosis.
  • Compare the running kernel against the versions the module's release notes claim support for. A kernel newer than anything the vendor lists is the answer.
  • Check whether the module is loaded at all. A module that failed to rebuild leaves the package installed, so package state is not evidence that the capability exists.

Example training logs (fingerprint)

training.log (synthetic fingerprint)
/var/lib/dkms/beegfs/8.1.0/build/build/../source/common/storage/RdmaInfo.c:58:13: error: implicit declaration of function 'ib_peer_memory_client_register'
modprobe: ERROR: could not insert 'nvidia_peermem': Invalid argument
dmesg: nvidia_peermem: Unknown symbol ib_register_peer_memory_client

Timestamps and exact values vary across runs, but the pattern. An info-level start, an early WARN, an ERROR carrying the symptom. Is the actual fingerprint you should alert on. The Denpex platform flags this combination automatically.

Root cause, fix & prevention, signed in

Sign up free to see why this failure really happens, the exact remediation steps, and the production-grade prevention pattern. You also get 3 free full diagnoses for your own training logs.

Sign up free. Unlock the full analysis

No credit card · 3 free diagnoses · Instant access

Why the recommended fix works

Moving to a module release built for the running kernel supplies source that calls functions which exist, so the rebuild completes and the capability returns. Correcting the install order for peer-memory components works on the same principle from the linking side: the driver can only bind to fabric symbols that were present when it built.

Code examples

typical reference pattern
// Typical pattern:
import torch.optim as optim
optimizer = optim.AdamW(model.parameters(), lr=3e-4)
scheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=num_training_steps)
for step in range(num_training_steps):
    optimizer.zero_grad()
    loss = model(batch)
    loss.backward()
    optimizer.step()
    scheduler.step()

Adapt the snippet to your framework. The same pattern holds for PyTorch Lightning, Hugging Face Trainer, DeepSpeed, Megatron-LM, and vLLM training wrappers. Where the wrapper exposes a config flag (for examplelr_scheduler_type in Trainer), prefer the flag over the imperative API to keep the schedule declarative and reproducible.

Best practices by model family

Model / StackRecommendationNotes
Kernel newer than the module supportsUpgrade the module, do not patch the sourceA local patch has to be re-made at every subsequent upgrade.
Peer-memory unknown symbol on loadReinstall the GPU driver after the fabric stackThe driver binds fabric symbols at build time; order is significant.
Suspected toolchain problemCheck gcc matches the kernel's build compilerRules out a similar-looking failure with a different cause.
GPU node fleetsPin the kernel and move it with the driversUnattended kernel updates decouple components that are one unit.

With the fix vs without the fix

DimensionWith the fixWithout the fix
What DKMS guaranteesRecompilation against the new kernelAssumed to include adapting to API changes
Evidence the capability existsThe module is loaded and the feature worksThe package is installed
How it presentsA slower fallback path or a missing mountExpected to be an explicit failure at boot

Real engineering notes

The dangerous property of this failure is that it is silent at the layer people watch. The node boots, the GPU works, jobs schedule, and only the fast path is gone — so it shows up as a throughput regression or an unexplained fallback to sockets days later. Check the capability after every kernel change, not the package list; a failed DKMS rebuild leaves the package looking perfectly installed.

Visual fingerprint

What the upgrade actually changed
  before   kernel 5.14.0-427   module source calls helper_v1()   -> builds, loads
  upgrade  kernel 5.14.0-503   helper_v1() removed upstream
  after    DKMS rebuilds same source          -> implicit declaration -> no module

  package manager view: package still installed, upgrade succeeded
  operational view:     GPUDirect gone, nothing alerted
DKMS recompiles the unchanged module source against the new kernel. Because the helper it calls no longer exists, the build stops and no module is produced, while the package remains installed and the upgrade is reported as successful.

Root cause, fix & prevention

Frequently asked questions

Twelve targeted questions that engineers and on-call staff most commonly ask about this failure.

Why did a routine kernel patch break this?
The kernel has no stable internal API. A function the module calls was renamed or removed, and DKMS rebuilds the source without adapting it.
The package is still installed, so is the module fine?
No. A failed rebuild leaves the package in place with no module produced. Check that the module is loaded and the capability works.
Should I patch the source myself?
Only as a last resort. A local patch has to be re-made at every subsequent kernel upgrade; a module release that supports the kernel does not.
Why does it load on one node and not another?
Usually build order. Where a peer-memory module is involved, the GPU driver must be installed after the fabric stack so it can bind the fabric's symbols.

Don't just read the fix, diagnose your run

The encyclopedia tells you what went wrong. Denpex tells you what went wrong in YOUR training run. With your logs, your config, and your stack.