If there's a DRM master, return -EBUSY. Block userspace from becoming master by taking the master lock while the client is setting the mode. Suggested-by: Daniel Vetter <daniel.vetter@xxxxxxxx> Signed-off-by: Noralf Trønnes <noralf@xxxxxxxxxxx> --- drivers/gpu/drm/drm_auth.c | 33 +++++++++++++++++++++++++++++++++ drivers/gpu/drm/drm_client.c | 34 +++++++++++++++++++++++++++++----- drivers/gpu/drm/drm_fb_helper.c | 8 ++++---- drivers/gpu/drm/drm_internal.h | 2 ++ include/drm/drm_client.h | 4 ++-- 5 files changed, 70 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/drm_auth.c b/drivers/gpu/drm/drm_auth.c index d9c0f7573905..d656d0d93da3 100644 --- a/drivers/gpu/drm/drm_auth.c +++ b/drivers/gpu/drm/drm_auth.c @@ -366,3 +366,36 @@ void drm_master_put(struct drm_master **master) *master = NULL; } EXPORT_SYMBOL(drm_master_put); + +/** + * drm_master_block - Block DRM master operations + * @dev: DRM device + * + * This function checks if there is a master on @dev. If there is no master it + * blocks anyone from becoming master. In-kernel clients can use this to know + * when they can act as master. Use drm_master_unblock() to unblock. + * + * Returns: + * True if there is no master, false otherwise. + */ +bool drm_master_block(struct drm_device *dev) +{ + mutex_lock(&dev->master_mutex); + if (dev->master) { + mutex_unlock(&dev->master_mutex); + return false; + } + + return true; +} + +/** + * drm_master_unblock - Unblock DRM master operations + * @dev: DRM device + * + * Unblock and allow userspace to become master. + */ +void drm_master_unblock(struct drm_device *dev) +{ + mutex_unlock(&dev->master_mutex); +} diff --git a/drivers/gpu/drm/drm_client.c b/drivers/gpu/drm/drm_client.c index 27818a467b09..764c556630b8 100644 --- a/drivers/gpu/drm/drm_client.c +++ b/drivers/gpu/drm/drm_client.c @@ -18,6 +18,8 @@ #include <drm/drm_device.h> #include <drm/drm_modes.h> +#include "drm_internal.h" + struct drm_client_display_offset { int x, y; }; @@ -313,18 +315,30 @@ static int drm_client_display_restore_legacy(struct drm_client_display *display) /** * drm_client_display_restore() - Restore client display * @display: Client display + * @force: If true, restore even if there's a DRM master * * Restore client display using the current modeset configuration. * * Return: * Zero on succes or negative error code on failure. */ -int drm_client_display_restore(struct drm_client_display *display) +int drm_client_display_restore(struct drm_client_display *display, bool force) { - if (drm_drv_uses_atomic_modeset(display->dev)) - return drm_client_display_restore_atomic(display, true); + struct drm_device *dev = display->dev; + int ret; + + if (!force && !drm_master_block(dev)) + return -EBUSY; + + if (drm_drv_uses_atomic_modeset(dev)) + ret = drm_client_display_restore_atomic(display, true); else - return drm_client_display_restore_legacy(display); + ret = drm_client_display_restore_legacy(display); + + if (!force) + drm_master_unblock(dev); + + return ret; } EXPORT_SYMBOL(drm_client_display_restore); @@ -354,13 +368,23 @@ static void drm_client_display_dpms_legacy(struct drm_client_display *display, i * drm_client_display_dpms() - Set display DPMS mode * @display: Client display * @mode: DPMS mode + * + * Returns: + * Zero on success, -EBUSY if there's a DRM master. */ -void drm_client_display_dpms(struct drm_client_display *display, int mode) +int drm_client_display_dpms(struct drm_client_display *display, int mode) { + if (!drm_master_block(display->dev)) + return -EBUSY; + if (drm_drv_uses_atomic_modeset(display->dev)) drm_client_display_restore_atomic(display, mode == DRM_MODE_DPMS_ON); else drm_client_display_dpms_legacy(display, mode); + + drm_master_unblock(display->dev); + + return 0; } EXPORT_SYMBOL(drm_client_display_dpms); diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c index 01d8840930a3..98e5bc92c9f2 100644 --- a/drivers/gpu/drm/drm_fb_helper.c +++ b/drivers/gpu/drm/drm_fb_helper.c @@ -181,7 +181,7 @@ int drm_fb_helper_restore_fbdev_mode_unlocked(struct drm_fb_helper *fb_helper) return 0; mutex_lock(&fb_helper->lock); - ret = drm_client_display_restore(fb_helper->display); + ret = drm_client_display_restore(fb_helper->display, false); do_delayed = fb_helper->delayed_hotplug; if (do_delayed) @@ -243,7 +243,7 @@ static bool drm_fb_helper_force_kernel_mode(void) continue; mutex_lock(&helper->lock); - ret = drm_client_display_restore(helper->display); + ret = drm_client_display_restore(helper->display, true); if (ret) error = true; mutex_unlock(&helper->lock); @@ -1254,7 +1254,7 @@ static int pan_display_atomic(struct fb_var_screeninfo *var, pan_set(fb_helper, var->xoffset, var->yoffset); - ret = drm_client_display_restore(fb_helper->display); + ret = drm_client_display_restore(fb_helper->display, false); if (!ret) { info->var.xoffset = var->xoffset; info->var.yoffset = var->yoffset; @@ -1423,7 +1423,7 @@ static int drm_fb_helper_single_fb_probe(struct drm_fb_helper *fb_helper, /* First time: disable all crtc's.. */ if (!fb_helper->deferred_setup && !READ_ONCE(fb_helper->dev->master)) - drm_client_display_restore(fb_helper->display); + drm_client_display_restore(fb_helper->display, false); return -EAGAIN; } diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h index 3f5d7706bcc9..f38dcaf139d7 100644 --- a/drivers/gpu/drm/drm_internal.h +++ b/drivers/gpu/drm/drm_internal.h @@ -92,6 +92,8 @@ int drm_dropmaster_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv); int drm_master_open(struct drm_file *file_priv); void drm_master_release(struct drm_file *file_priv); +bool drm_master_block(struct drm_device *dev); +void drm_master_unblock(struct drm_device *dev); /* drm_sysfs.c */ extern struct class *drm_class; diff --git a/include/drm/drm_client.h b/include/drm/drm_client.h index 27d2a46cd94a..3befd879a0b0 100644 --- a/include/drm/drm_client.h +++ b/include/drm/drm_client.h @@ -46,8 +46,8 @@ drm_client_display_find_modeset(struct drm_client_display *display, struct drm_c bool drm_client_display_panel_rotation(struct drm_connector *connector, struct drm_plane *plane, unsigned int *rotation); -int drm_client_display_restore(struct drm_client_display *display); -void drm_client_display_dpms(struct drm_client_display *display, int mode); +int drm_client_display_restore(struct drm_client_display *display, bool force); +int drm_client_display_dpms(struct drm_client_display *display, int mode); struct drm_client_display * drm_client_find_display(struct drm_device *dev, unsigned int width, unsigned int height); -- 2.15.1 _______________________________________________ dri-devel mailing list dri-devel@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/dri-devel