]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
mei: gsc: fix remove operations order
authorAlexander Usyskin <alexander.usyskin@intel.com>
Mon, 15 Sep 2025 12:45:54 +0000 (15:45 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 18 Sep 2025 16:27:40 +0000 (18:27 +0200)
The mei disconnect should be the last operation in remove flow.
Otherwise the device is used after destruction.
Fix minor free flow that happens after device destruction too.

The fault leads to the following oops in Intel Gfx CI:

<4>[  267.871331] Oops: general protection fault, probably for non-canonical address 0x6b6b6b6b6b6b6bcb: 0000 [#1] SMP NOPTI
...
<4>[  267.871410] RIP: 0010:mei_gsc_remove+0x44/0x90 [mei_gsc]
...
<4>[  267.871555] Call Trace:
<4>[  267.871562]  <TASK>
<4>[  267.871570]  auxiliary_bus_remove+0x1b/0x30
<4>[  267.871589]  device_remove+0x43/0x80
<4>[  267.871604]  device_release_driver_internal+0x215/0x280
<4>[  267.871619]  device_release_driver+0x12/0x20
<4>[  267.871630]  bus_remove_device+0xdc/0x150
<4>[  267.871645]  device_del+0x15f/0x3b0
<4>[  267.871656]  ? bus_unregister_notifier+0x37/0x50
<4>[  267.871672]  gsc_destroy_one.isra.0+0x44/0x210 [i915]
<4>[  267.872295]  intel_gsc_fini+0x28/0x50 [i915]
<4>[  267.872860]  intel_gt_driver_unregister+0x2c/0x80 [i915]
<4>[  267.873300]  i915_driver_remove+0x6e/0x150 [i915]
<4>[  267.873694]  i915_pci_remove+0x1e/0x40 [i915]
<4>[  267.874095]  pci_device_remove+0x3e/0xb0
<4>[  267.874111]  device_remove+0x43/0x80
<4>[  267.874126]  device_release_driver_internal+0x215/0x280
<4>[  267.874137]  ? bus_find_device+0xa5/0xe0
<4>[  267.874153]  device_driver_detach+0x14/0x20
<4>[  267.874164]  unbind_store+0xac/0xc0
<4>[  267.874178]  drv_attr_store+0x21/0x50
<4>[  267.874190]  sysfs_kf_write+0x4a/0x80
<4>[  267.874204]  kernfs_fop_write_iter+0x188/0x240
<4>[  267.874222]  vfs_write+0x283/0x540
<4>[  267.874241]  ksys_write+0x6f/0xf0
<4>[  267.874253]  __x64_sys_write+0x19/0x30
<4>[  267.874264]  x64_sys_call+0x79/0x26a0
<4>[  267.874277]  do_syscall_64+0x93/0xd50
<4>[  267.874291]  ? do_syscall_64+0x1a2/0xd50
<4>[  267.874301]  ? do_syscall_64+0x1a2/0xd50
<4>[  267.874313]  ? do_syscall_64+0x1a2/0xd50
<4>[  267.874324]  ? clear_bhb_loop+0x30/0x80
<4>[  267.874336]  ? clear_bhb_loop+0x30/0x80
<4>[  267.874349]  entry_SYSCALL_64_after_hwframe+0x76/0x7e

Fixes: 7704e6be4ed2 ("mei: hook mei_device on class device")
Signed-off-by: Alexander Usyskin <alexander.usyskin@intel.com>
Link: https://lore.kernel.org/r/20250915124554.2263330-1-alexander.usyskin@intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/misc/mei/gsc-me.c
drivers/misc/mei/main.c

index f147258e7c28e581367bccceab15445aafd50bb2..93cba090ea0880ff8bda46ba28191c4bd091c299 100644 (file)
@@ -150,13 +150,13 @@ static void mei_gsc_remove(struct auxiliary_device *aux_dev)
        if (mei_me_hw_use_polling(hw))
                kthread_stop(hw->polling_thread);
 
-       mei_deregister(dev);
-
        pm_runtime_disable(&aux_dev->dev);
 
        mei_disable_interrupts(dev);
        if (!mei_me_hw_use_polling(hw))
                devm_free_irq(&aux_dev->dev, hw->irq, dev);
+
+       mei_deregister(dev);
 }
 
 static int __maybe_unused mei_gsc_pm_suspend(struct device *device)
index f37f9b8b1f518708b9fc2b2e70263376a4ac4932..93c518bb5e141f8bb21addc3e80df5c54b6f67a6 100644 (file)
@@ -1208,12 +1208,12 @@ static int mei_minor_get(struct mei_device *dev)
 /**
  * mei_minor_free - mark device minor number as free
  *
- * @dev:  device pointer
+ * @minor: minor number to free
  */
-static void mei_minor_free(struct mei_device *dev)
+static void mei_minor_free(int minor)
 {
        mutex_lock(&mei_minor_lock);
-       idr_remove(&mei_idr, dev->minor);
+       idr_remove(&mei_idr, minor);
        mutex_unlock(&mei_minor_lock);
 }
 
@@ -1225,11 +1225,14 @@ static void mei_device_release(struct device *dev)
 int mei_register(struct mei_device *dev, struct device *parent)
 {
        int ret, devno;
+       int minor;
 
        ret = mei_minor_get(dev);
        if (ret < 0)
                return ret;
 
+       minor = dev->minor;
+
        /* Fill in the data structures */
        devno = MKDEV(MAJOR(mei_devt), dev->minor);
 
@@ -1279,7 +1282,7 @@ int mei_register(struct mei_device *dev, struct device *parent)
 err_del_cdev:
        cdev_del(dev->cdev);
 err:
-       mei_minor_free(dev);
+       mei_minor_free(minor);
        return ret;
 }
 EXPORT_SYMBOL_GPL(mei_register);
@@ -1287,6 +1290,7 @@ EXPORT_SYMBOL_GPL(mei_register);
 void mei_deregister(struct mei_device *dev)
 {
        int devno;
+       int minor = dev->minor;
 
        devno = dev->cdev->dev;
        cdev_del(dev->cdev);
@@ -1295,7 +1299,7 @@ void mei_deregister(struct mei_device *dev)
 
        device_destroy(&mei_class, devno);
 
-       mei_minor_free(dev);
+       mei_minor_free(minor);
 }
 EXPORT_SYMBOL_GPL(mei_deregister);