]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/xe: Fix fault on fd close after unbind
authorLucas De Marchi <lucas.demarchi@intel.com>
Wed, 18 Dec 2024 05:31:21 +0000 (21:31 -0800)
committerThomas Hellström <thomas.hellstrom@linux.intel.com>
Mon, 23 Dec 2024 15:19:52 +0000 (16:19 +0100)
If userspace holds an fd open, unbinds the device and then closes it,
the driver shouldn't try to access the hardware. Protect it by using
drm_dev_enter()/drm_dev_exit(). This fixes the following page fault:

<6> [IGT] xe_wedged: exiting, ret=98
<1> BUG: unable to handle page fault for address: ffffc901bc5e508c
<1> #PF: supervisor read access in kernel mode
<1> #PF: error_code(0x0000) - not-present page
...
<4>   xe_lrc_update_timestamp+0x1c/0xd0 [xe]
<4>   xe_exec_queue_update_run_ticks+0x50/0xb0 [xe]
<4>   xe_exec_queue_fini+0x16/0xb0 [xe]
<4>   __guc_exec_queue_fini_async+0xc4/0x190 [xe]
<4>   guc_exec_queue_fini_async+0xa0/0xe0 [xe]
<4>   guc_exec_queue_fini+0x23/0x40 [xe]
<4>   xe_exec_queue_destroy+0xb3/0xf0 [xe]
<4>   xe_file_close+0xd4/0x1a0 [xe]
<4>   drm_file_free+0x210/0x280 [drm]
<4>   drm_close_helper.isra.0+0x6d/0x80 [drm]
<4>   drm_release_noglobal+0x20/0x90 [drm]

Fixes: 514447a12190 ("drm/xe: Stop accumulating LRC timestamp on job_free")
Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/3421
Reviewed-by: Umesh Nerlige Ramappa <umesh.nerlige.ramappa@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20241218053122.2730195-1-lucas.demarchi@intel.com
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
(cherry picked from commit 4ca1fd418338d4d135428a0eb1e16e3b3ce17ee8)
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
drivers/gpu/drm/xe/xe_exec_queue.c

index fd0f3b3c9101d45e83b8a06d9167c5e6337e40f0..268cd3123be9d9d4b0a67cfedb93af0ba6394409 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/nospec.h>
 
 #include <drm/drm_device.h>
+#include <drm/drm_drv.h>
 #include <drm/drm_file.h>
 #include <uapi/drm/xe_drm.h>
 
@@ -762,9 +763,11 @@ bool xe_exec_queue_is_idle(struct xe_exec_queue *q)
  */
 void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q)
 {
+       struct xe_device *xe = gt_to_xe(q->gt);
        struct xe_file *xef;
        struct xe_lrc *lrc;
        u32 old_ts, new_ts;
+       int idx;
 
        /*
         * Jobs that are run during driver load may use an exec_queue, but are
@@ -774,6 +777,10 @@ void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q)
        if (!q->vm || !q->vm->xef)
                return;
 
+       /* Synchronize with unbind while holding the xe file open */
+       if (!drm_dev_enter(&xe->drm, &idx))
+               return;
+
        xef = q->vm->xef;
 
        /*
@@ -787,6 +794,8 @@ void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q)
        lrc = q->lrc[0];
        new_ts = xe_lrc_update_timestamp(lrc, &old_ts);
        xef->run_ticks[q->class] += (new_ts - old_ts) * q->width;
+
+       drm_dev_exit(idx);
 }
 
 /**