diff mbox series

[RFC] drm: Add flag to make whole ioctl critical section for unplug

Message ID 20230125171659.1365087-1-stanislaw.gruszka@linux.intel.com (mailing list archive)
State New, archived
Headers show
Series [RFC] drm: Add flag to make whole ioctl critical section for unplug | expand

Commit Message

Stanislaw Gruszka Jan. 25, 2023, 5:16 p.m. UTC
drm_dev_is_unplugged() check is inherently racy as unplug can happen
just after this check. Add DRM_UNPLUG_SAFE ioctl flag to keep
the whole ioctl func call within drm_dev_enter() ... drm_dev_exit().

This could be enabled by drivers for individual ioctl's .

Signed-off-by: Stanislaw Gruszka <stanislaw.gruszka@linux.intel.com>
---
 drivers/gpu/drm/drm_ioctl.c | 22 +++++++++++++++-------
 include/drm/drm_ioctl.h     |  7 +++++++
 2 files changed, 22 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index ca2a6e6101dc..9943f38c6b05 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -773,24 +773,32 @@  long drm_ioctl_kernel(struct file *file, drm_ioctl_t *func, void *kdata,
 {
 	struct drm_file *file_priv = file->private_data;
 	struct drm_device *dev = file_priv->minor->dev;
-	int retcode;
+	const bool global_mutex = drm_core_check_feature(dev, DRIVER_LEGACY) &&
+				  !(flags & DRM_UNLOCKED);
+	const bool unplug_safe = flags & DRM_UNPLUG_SAFE;
+	int retcode, idx;
 
-	if (drm_dev_is_unplugged(dev))
+	if (!drm_dev_enter(dev, &idx))
 		return -ENODEV;
+	if (!unplug_safe)
+		drm_dev_exit(idx);
 
 	retcode = drm_ioctl_permit(flags, file_priv);
 	if (unlikely(retcode))
-		return retcode;
+		goto out;
 
-	/* Enforce sane locking for modern driver ioctls. */
-	if (likely(!drm_core_check_feature(dev, DRIVER_LEGACY)) ||
-	    (flags & DRM_UNLOCKED))
+	if (likely(!global_mutex)) {
 		retcode = func(dev, kdata, file_priv);
-	else {
+	} else {
 		mutex_lock(&drm_global_mutex);
 		retcode = func(dev, kdata, file_priv);
 		mutex_unlock(&drm_global_mutex);
 	}
+
+out:
+	if (unplug_safe)
+		drm_dev_exit(idx);
+
 	return retcode;
 }
 EXPORT_SYMBOL(drm_ioctl_kernel);
diff --git a/include/drm/drm_ioctl.h b/include/drm/drm_ioctl.h
index 6ed61c371f6c..894ce775ff12 100644
--- a/include/drm/drm_ioctl.h
+++ b/include/drm/drm_ioctl.h
@@ -130,6 +130,13 @@  enum drm_ioctl_flags {
 	 * not set DRM_AUTH because they do not require authentication.
 	 */
 	DRM_RENDER_ALLOW	= BIT(5),
+	/**
+	 * @DRM_UNPUG_SAFE:
+	 *
+	 * Whether &drm_ioctl_desc.func should be called as unplug critical
+	 * section protected by drm_dev_enter() / drm_dev_exit()
+	 */
+	DRM_UNPLUG_SAFE		= BIT(6),
 };
 
 /**