@@ -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);
@@ -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),
};
/**
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(-)