Skip to content

nvidia-modeset: free the semaphore surface callback record when the waiter is already signalled - #1368

Open
jdd-canada wants to merge 1 commit into
NVIDIA:mainfrom
jdd-canada:fix-semsurf-callback-leak
Open

jdd-canada wants to merge 1 commit into
NVIDIA:mainfrom
jdd-canada:fix-semsurf-callback-leak

Conversation

@jdd-canada

Copy link
Copy Markdown

Summary

nvKmsKapiRegisterSemaphoreSurfaceCallback() allocates a struct NvKmsKapiSemaphoreSurfaceCallback before asking RM to register a waiter. When RM returns NVOS_STATUS_ERROR_ALREADY_SIGNALLED, the function returns without freeing the record and without handing it back to the caller, so neither of the two documented release paths (the callback firing, or unregisterSemaphoreSurfaceCallback()) can ever reach it. This change frees the record on that return. nvKmsKapiFree(NULL) is already relied on by the function's own fail: path, so the call is safe when no callback was requested.

Impact

nvidia-drm takes this path through __nv_drm_semsurf_ctx_reg_callbacks() for every semaphore surface fence whose GPU work completes before the waiter is registered. On a Wayland compositor that waits its own render fence before each KMS commit, that is most composited frames: the leak rate follows the compositor's frame rate, near zero on a static screen and tens of MiB per hour while anything animates.

Observed on a laptop (RTX, Void Linux, kernel 6.18.50) over 4.5 days of desktop use on 595.71.05: 11.6 million live kmalloc-64 objects, 2.2 GB of unreclaimable slab, 97 percent of the cache, attributed with slub_debug=U,kmalloc-64 to this one call site:

nvkms_alloc  <-  nvKmsKapiRegisterSemaphoreSurfaceCallback  [nvidia_modeset]
             <-  __nv_drm_semsurf_ctx_reg_callbacks         [nvidia_drm]
             <-  nv_drm_semsurf_fence_create_ioctl          (11.26M objects)
             <-  __nv_drm_semsurf_ctx_fence_callback_work   (0.37M objects)

The same lines are present in every tag from 545.29.06 through 610.57.04 and on main at 615.71.09.

Verification

Stock open module 595.91.07 versus the same source with this patch, same kernel and same day, with slab owner tracking enabled and the site's live count read from /sys/kernel/debug/slab/kmalloc-64/alloc_traces. Reproduction that isolates the compositor's own fences (a CPU-rendered client, no client-side GPU fences):

timeout 300 mpv --vo=wlshm --no-audio --really-quiet 'av://lavfi:testsrc2=size=1280x720:rate=60'
Build Site count growth over the 5-minute 60 fps window
stock 595.91.07 +7259 records (125839 live after 38 minutes of uptime)
patched 0

Patched build afterwards: 20 hours of normal use with kmalloc-64 flat at 7.4 MiB in every hourly slab sample, and about 36 hours further with no growth.

…aiter is already signalled

nvKmsKapiRegisterSemaphoreSurfaceCallback() allocates a
struct NvKmsKapiSemaphoreSurfaceCallback before asking RM to register a
waiter. When RM answers NVOS_STATUS_ERROR_ALREADY_SIGNALLED the function
returns without freeing the record and without handing it to the caller,
so neither of the two documented release paths (the callback running, or
unregisterSemaphoreSurfaceCallback()) can ever reach it.

nvidia-drm takes this path for every semaphore surface fence whose GPU
work completes before the waiter is registered, which on a Wayland
compositor is nearly every composited frame. The result is a 40-byte
kmalloc-64 object leaked per frame: 11.6 million objects and 2.2 GB of
unreclaimable slab over 4.5 days of desktop use on 595.71.05, attributed
with slub_debug=U to this call site through
__nv_drm_semsurf_ctx_reg_callbacks().

Applies to every tag from 545.29.06 through 610.57.04 and to main.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant