<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
  <meta charset="utf-8" />
  <meta name="generator" content="pandoc" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
  <title>Fix nv_drm_revoke_modeset_permission</title>
  <style>
    code{white-space: pre-wrap;}
    span.smallcaps{font-variant: small-caps;}
    div.columns{display: flex; gap: min(4vw, 1.5em);}
    div.column{flex: auto; overflow-x: auto;}
    div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
    /* The extra [class] is a hack that increases specificity enough to
       override a similar rule in reveal.js */
    ul.task-list[class]{list-style: none;}
    ul.task-list li input[type="checkbox"] {
      font-size: inherit;
      width: 0.8em;
      margin: 0 0.8em 0.2em -1.6em;
      vertical-align: middle;
    }
    .display.math{display: block; text-align: center; margin: 0.5rem auto;}
    /* CSS for syntax highlighting */
    html { -webkit-text-size-adjust: 100%; }
    pre > code.sourceCode { white-space: pre; position: relative; }
    pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
    pre > code.sourceCode > span:empty { height: 1.2em; }
    .sourceCode { overflow: visible; }
    code.sourceCode > span { color: inherit; text-decoration: inherit; }
    div.sourceCode { margin: 1em 0; }
    pre.sourceCode { margin: 0; }
    @media screen {
    div.sourceCode { overflow: auto; }
    }
    @media print {
    pre > code.sourceCode { white-space: pre-wrap; }
    pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
    }
    pre.numberSource code
      { counter-reset: source-line 0; }
    pre.numberSource code > span
      { position: relative; left: -4em; counter-increment: source-line; }
    pre.numberSource code > span > a:first-child::before
      { content: counter(source-line);
        position: relative; left: -1em; text-align: right; vertical-align: baseline;
        border: none; display: inline-block;
        -webkit-touch-callout: none; -webkit-user-select: none;
        -khtml-user-select: none; -moz-user-select: none;
        -ms-user-select: none; user-select: none;
        padding: 0 4px; width: 4em;
        color: #aaaaaa;
      }
    pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa;  padding-left: 4px; }
    div.sourceCode
      {  background-color: #f8f8f8; }
    @media screen {
    pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
    }
    code span.al { color: #ef2929; } /* Alert */
    code span.an { color: #8f5902; font-weight: bold; font-style: italic; } /* Annotation */
    code span.at { color: #204a87; } /* Attribute */
    code span.bn { color: #0000cf; } /* BaseN */
    code span.cf { color: #204a87; font-weight: bold; } /* ControlFlow */
    code span.ch { color: #4e9a06; } /* Char */
    code span.cn { color: #8f5902; } /* Constant */
    code span.co { color: #8f5902; font-style: italic; } /* Comment */
    code span.cv { color: #8f5902; font-weight: bold; font-style: italic; } /* CommentVar */
    code span.do { color: #8f5902; font-weight: bold; font-style: italic; } /* Documentation */
    code span.dt { color: #204a87; } /* DataType */
    code span.dv { color: #0000cf; } /* DecVal */
    code span.er { color: #a40000; font-weight: bold; } /* Error */
    code span.ex { } /* Extension */
    code span.fl { color: #0000cf; } /* Float */
    code span.fu { color: #204a87; font-weight: bold; } /* Function */
    code span.im { } /* Import */
    code span.in { color: #8f5902; font-weight: bold; font-style: italic; } /* Information */
    code span.kw { color: #204a87; font-weight: bold; } /* Keyword */
    code span.op { color: #ce5c00; font-weight: bold; } /* Operator */
    code span.ot { color: #8f5902; } /* Other */
    code span.pp { color: #8f5902; font-style: italic; } /* Preprocessor */
    code span.sc { color: #ce5c00; font-weight: bold; } /* SpecialChar */
    code span.ss { color: #4e9a06; } /* SpecialString */
    code span.st { color: #4e9a06; } /* String */
    code span.va { color: #000000; } /* Variable */
    code span.vs { color: #4e9a06; } /* VerbatimString */
    code span.wa { color: #8f5902; font-weight: bold; font-style: italic; } /* Warning */
  </style>
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/github-markdown-css/github-markdown.min.css" />
</head>
<body>
<header id="title-block-header">
<h1 class="title">Fix nv_drm_revoke_modeset_permission</h1>
</header>
<h1 id="fix-nv_drm_revoke_modeset_permission-kernel-warning">Fix
nv_drm_revoke_modeset_permission kernel WARNING</h1>
<p>Fix kernel WARN_ON in <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-drv.c#L1182"><code>nv_drm_revoke_modeset_permission</code></a>
on nvidia-drm 550 branch / Debian kernel 6.12. Two patches needed - one
fixing the conftest detection (primary cause of the visible symptom) and
one fixing error handling bugs in the driver (secondary/latent
bugs).</p>
<h2 id="error-symptom">Error Symptom</h2>
<pre><code>WARNING at nvidia-drm/nvidia-drm-drv.c:1221 nv_drm_revoke_modeset_permission+0x327/0x340</code></pre>
<p>Triggered from <a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_file.c#L223"><code>drm_file_free</code></a>
<code>-></code> <a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_file.c#L410"><code>drm_release</code></a>
<code>-> __fput -> close()</code> – i.e., whenever a DRM file
descriptor is closed (by processes like <code>glxtest</code>,
<code>kioworker</code>, <code>kscreenlocker_g</code>).</p>
<p>The WARN instruction (<code>ud2</code>) is at offset 0x327 in a
0x340-byte function, placing it in the <a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_modeset_lock.c#L143"><code>DRM_MODESET_LOCK_ALL_END</code></a>
macro expansion at the end of the function. Line 1221 falls within the
connector iteration block.</p>
<h2
id="root-cause-conftest-failure-primary-causes-the-visible-warn">Root
Cause: Conftest Failure (Primary – causes the visible WARN)</h2>
<p>The WARNING is primarily caused by a <strong>conftest
failure</strong> that activates a buggy fallback code path:</p>
<h3 id="conftest-for-drm_connector_list_iter-fails">1. Conftest for
<code>drm_connector_list_iter</code> fails</h3>
<p>The compile test for <a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_connector.h#L2336"><code>struct drm_connector_list_iter</code></a>
in <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/conftest.sh#L4272"><code>conftest.sh</code></a>
fails on Debian kernel 6.12.90. The test includes <a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_connector.h"><code><drm/drm_connector.h></code></a>
directly, but that header depends on types from <a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_device.h"><code><drm/drm_device.h></code></a>
and <a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_mode_config.h"><code><drm/drm_mode_config.h></code></a>
that are not transitively available.</p>
<p>This is a <strong>latent upstream bug</strong> (the conftest was
always fragile) <strong>triggered by the Debian
<code>use-kbuild-flags.patch</code></strong>, which prepends
<code>KBUILD_CFLAGS</code> to the conftest compile flags. Under the
stricter flags (or changed include order),
<code>drm/drm_connector.h</code> cannot compile standalone.</p>
<p>Evidence in the build output:</p>
<pre><code># conftest/compile-tests/drm_connector_list_iter.h (BEFORE fix)
#undef NV_DRM_CONNECTOR_LIST_ITER_PRESENT       ← types conftest correctly fails
#define NV_DRM_CONNECTOR_LIST_ITER_BEGIN_PRESENT  ← functions conftest false positive (inverted logic)</code></pre>
<h3 id="fallback-macro-fires-bogus-warn_on">2. Fallback macro fires
bogus WARN_ON</h3>
<p>Without <code>NV_DRM_CONNECTOR_LIST_ITER_PRESENT</code>, the code
uses the fallback <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-helper.h#L157"><code>nv_drm_for_each_connector</code></a>
macro in <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-helper.h"><code>nvidia-drm-helper.h</code></a>:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#define nv_drm_for_each_connector</span><span class="op">(</span><span class="pp">connector</span><span class="op">,</span><span class="pp"> conn_iter</span><span class="op">,</span><span class="pp"> dev</span><span class="op">)</span><span class="pp"> </span><span class="op">\</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="pp">    WARN_ON</span><span class="op">(!</span><span class="pp">mutex_is_locked</span><span class="op">(&</span><span class="pp">dev</span><span class="op">-></span><span class="pp">mode_config</span><span class="op">.</span><span class="pp">mutex</span><span class="op">));</span><span class="pp">      </span><span class="op">\</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="pp">    list_for_each_entry</span><span class="op">(</span><span class="pp">connector</span><span class="op">,</span><span class="pp"> </span><span class="op">&(</span><span class="pp">dev</span><span class="op">)-></span><span class="pp">mode_config</span><span class="op">.</span><span class="pp">connector_list</span><span class="op">,</span><span class="pp"> head</span><span class="op">)</span><span class="pp">  </span><span class="co">/* kernel list.h */</span></span></code></pre></div>
<h3 id="warn_on-fires-because-mode_config.mutex-is-not-held">3. WARN_ON
fires because mode_config.mutex is not held</h3>
<p>The call chain in <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-drv.c#L1182"><code>nv_drm_revoke_modeset_permission</code></a>
is:</p>
<pre><code>DRM_MODESET_LOCK_ALL_BEGIN(dev, ctx, flags, ret)
    nv_drm_for_each_connector(connector, conn_iter, dev)   ← WARN_ON here
        ...
DRM_MODESET_LOCK_ALL_END(dev, ctx, ret)</code></pre>
<p><a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_modeset_lock.c#L143"><code>DRM_MODESET_LOCK_ALL_BEGIN</code></a>
(the 3-arg version used here) expands roughly to:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>drm_modeset_acquire_init<span class="op">(&</span>ctx<span class="op">,</span> flags<span class="op">);</span>               <span class="co">/* kernel: drm_modeset_lock.c */</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>retry<span class="op">:</span></span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>ret <span class="op">=</span> drm_modeset_lock_all_ctx<span class="op">(</span>dev<span class="op">,</span> <span class="op">&</span>ctx<span class="op">);</span>            <span class="co">/* kernel: drm_modeset_lock.c */</span></span>
<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> <span class="op">(</span>ret <span class="op">==</span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>    <span class="co">/* user code -- the connector iteration goes here */</span></span>
<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span></code></pre></div>
<p><a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_modeset_lock.c#L449"><code>drm_modeset_lock_all_ctx</code></a>
acquires locks in this order: 1.
<code>dev->mode_config.connection_mutex</code> – protects the
connector list and connector properties 2. Each CRTC’s
<code>crtc->mutex</code> 3. Each plane’s
<code>plane->mutex</code></p>
<p>Crucially, it does <strong>not</strong> acquire
<code>dev->mode_config.mutex</code>. That mutex is only taken by the
legacy <a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_modeset_lock.c#L143"><code>drm_modeset_lock_all()</code></a>
path (non-<code>_ctx</code> variant), which is used by non-atomic
(legacy) drivers. The nvidia-drm driver is an atomic driver (<a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_drv.h#L533"><code>drm_drv_uses_atomic_modeset(dev)</code></a>
returns true), so it correctly uses the <code>_ctx</code> path which
relies on <code>connection_mutex</code> to serialize connector list
access.</p>
<p>The fallback <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-helper.h#L157"><code>nv_drm_for_each_connector</code></a>
macro checks
<code>WARN_ON(!mutex_is_locked(&dev->mode_config.mutex))</code>,
but this is the <strong>wrong mutex</strong> to assert on for atomic
drivers. The connector list is properly protected by
<code>connection_mutex</code> (which <em>is</em> held), making this
WARN_ON a false alarm. The proper <a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_connector.h#L2336"><code>drm_connector_list_iter</code></a>-based
code path (used when the conftest succeeds) doesn’t have this incorrect
assertion at all – it uses <a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_connector.c#L878">refcounted
iteration</a> that is safe under <code>connection_mutex</code>.</p>
<h2 id="secondary-bugs-in-nvidia-drm-drv.cnv_drm_drv_c-latent">Secondary
Bugs in <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-drv.c"><code>nvidia-drm-drv.c</code></a>
(Latent)</h2>
<p>Two additional bugs exist in <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-drv.c#L1182"><code>nv_drm_revoke_modeset_permission</code></a>
which patch 0084 fixes:</p>
<h3 id="bug-1-connector-list-iterator-leak-via-goto-done">Bug 1:
Connector list iterator leak via <code>goto done</code></h3>
<p>When <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-drv.c#L1152"><code>nv_drm_atomic_disable_connector</code></a>
returns an error, <code>goto done</code> skips <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-helper.h#L531"><code>nv_drm_connector_list_iter_end</code></a>,
leaking the iterator’s internal reference.</p>
<h3 id="bug-2-null-state-dereference-on-alloc-failure">Bug 2: NULL state
dereference on alloc failure</h3>
<p>If <a
href="https://elixir.bootlin.com/linux/v6.12/source/drivers/gpu/drm/drm_atomic.c#L166"><code>drm_atomic_state_alloc</code></a>
fails, <code>goto done</code> leads to <a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_atomic.h#L536"><code>drm_atomic_state_put(NULL)</code></a>
/ <code>drm_atomic_state_free(NULL)</code>, which dereferences a NULL
pointer.</p>
<p>These bugs exist in all versions from 550 through 580+. In 580+, the
wrapper macro removal hides the WARN symptom, but the iterator leak
persists. In 610+, the code was fully refactored to use <a
href="https://elixir.bootlin.com/linux/v6.12/source/include/drm/drm_connector.h#L2336"><code>drm_connector_list_iter</code></a>
APIs directly without conftests or wrappers.</p>
<h2 id="fix-two-debian-patches">Fix: Two Debian Patches</h2>
<h3 id="patch-0085-fix-conftest-primary-fix">Patch 0085: Fix conftest
(primary fix)</h3>
<p>File:
<code>debian/patches/module/0085-fix-drm_connector_list_iter-conftest.patch</code></p>
<p>Adds prerequisite DRM headers (guarded by their own conftest defines)
before <code>#include <drm/drm_connector.h></code> in the
<code>drm_connector_list_iter</code> conftest, and adds a missing
<code>return 0;</code> to avoid <code>-Werror=return-type</code>:</p>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>CODE<span class="op">=</span><span class="st">"</span></span>
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a><span class="pp">#if defined(NV_DRM_DRM_DEVICE_H_PRESENT)</span></span>
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im"><drm/drm_device.h></span></span>
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="pp">#if defined(NV_DRM_DRM_MODE_CONFIG_H_PRESENT)</span></span>
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im"><drm/drm_mode_config.h></span></span>
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a><span class="pp">#endif</span></span>
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im"><drm/drm_connector.h></span></span>
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a><span class="dt">int</span> conftest_drm_connector_list_iter<span class="op">(</span><span class="dt">void</span><span class="op">)</span> <span class="op">{</span></span>
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a>    <span class="kw">struct</span> drm_connector_list_iter conn_iter<span class="op">;</span></span>
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="dv">0</span><span class="op">;</span></span>
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="op">}</span><span class="st">"</span></span></code></pre></div>
<p>With this fix, the conftest correctly detects
<code>struct drm_connector_list_iter</code> as present, the proper <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-helper.h#L520"><code>nv_drm_connector_list_iter_begin</code></a>/<a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-helper.h#L531"><code>end</code></a>
API path is used, and the fallback macro with the bogus
<code>WARN_ON</code> is never reached.</p>
<h3 id="patch-0084-fix-error-handling-secondary-fix">Patch 0084: Fix
error handling (secondary fix)</h3>
<p>File:
<code>debian/patches/module/0084-fix-nv_drm_revoke_modeset_permission-error-handling.patch</code></p>
<p>Fixes two bugs in <a
href="https://github.com/NVIDIA/open-gpu-kernel-modules/blob/550.163.01/kernel-open/nvidia-drm/nvidia-drm-drv.c#L1182"><code>nv_drm_revoke_modeset_permission</code></a>:</p>
<ul>
<li>Replace <code>goto done</code> with <code>break</code> inside the
connector loop (ensures iterator cleanup)</li>
<li>Add <code>if (ret < 0) goto done;</code> after the iterator end
call</li>
<li>Guard
<code>drm_atomic_state_put</code>/<code>drm_atomic_state_free</code>
with <code>if (state != NULL)</code></li>
</ul>
<h2 id="files-modified">Files Modified</h2>
<p>In the <a
href="https://salsa.debian.org/nvidia-team/nvidia-graphics-drivers">nvidia-graphics-drivers</a>
repo:</p>
<ul>
<li><code>debian/patches/module/0084-fix-nv_drm_revoke_modeset_permission-error-handling.patch</code>
(created)</li>
<li><code>debian/patches/module/0085-fix-drm_connector_list_iter-conftest.patch</code>
(created)</li>
<li><code>debian/patches/module/series</code> (updated to include both
patches)</li>
</ul>
<h2 id="verification">Verification</h2>
<p>After rebuilding the DKMS module with both patches:</p>
<div class="sourceCode" id="cb7"><pre
class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Verify conftest now succeeds:</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="fu">grep</span> NV_DRM_CONNECTOR_LIST_ITER /var/lib/dkms/nvidia-current/550.163.01/build/conftest/types.h</span>
<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="co"># Expected: #define NV_DRM_CONNECTOR_LIST_ITER_PRESENT</span></span>
<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a><span class="co"># Verify module loaded (if version was bumped):</span></span>
<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a><span class="ex">modinfo</span> nvidia-drm <span class="kw">|</span> <span class="fu">grep</span> version</span>
<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a><span class="co"># Verify </span><span class="al">WARNING</span><span class="co"> no longer appears in dmesg:</span></span>
<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a><span class="fu">dmesg</span> <span class="kw">|</span> <span class="fu">grep</span> nv_drm_revoke_modeset_permission</span>
<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a><span class="co"># Expected: no output</span></span></code></pre></div>
<h2 id="important-dkms-rebuild-gotcha">Important: DKMS Rebuild
Gotcha</h2>
<p>Simply copying patched files into the DKMS build directory is not
enough. A full <code>dkms remove</code> + <code>dkms install</code>
cycle is required, followed by rebuilding the initramfs
(<code>update-initramfs -u</code> or equivalent), to ensure the old
module is fully replaced. Without this, the old (unpatched) module may
persist in the initramfs and continue to be loaded at boot.</p>
<h2 id="source-references">Source References</h2>
<h3 id="nvidia-driver-open-gpu-kernel-modules-tag-550.163.01">NVIDIA
driver (open-gpu-kernel-modules, tag 550.163.01)</h3>
<h3 id="linux-kernel-v6.12-on-elixirbootlin">Linux kernel (v6.12 on
Elixir/Bootlin)</h3>
<hr />
<p><em>Document written with assistance from Claude Opus 4.6 (Anthropic)
via Cursor IDE.</em></p>
</body>
</html>