diff options
Diffstat (limited to 'drivers/gpu/drm/vmwgfx')
-rw-r--r-- | drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | 94 |
1 files changed, 89 insertions, 5 deletions
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c index 54cfeb6fc3b1..8fdbe26a98d2 100644 --- a/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c +++ b/drivers/gpu/drm/vmwgfx/vmwgfx_drv.c | |||
@@ -982,12 +982,70 @@ out_no_tfile: | |||
982 | return ret; | 982 | return ret; |
983 | } | 983 | } |
984 | 984 | ||
985 | static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, | 985 | static struct vmw_master *vmw_master_check(struct drm_device *dev, |
986 | unsigned long arg) | 986 | struct drm_file *file_priv, |
987 | unsigned int flags) | ||
988 | { | ||
989 | int ret; | ||
990 | struct vmw_fpriv *vmw_fp = vmw_fpriv(file_priv); | ||
991 | struct vmw_master *vmaster; | ||
992 | |||
993 | if (file_priv->minor->type != DRM_MINOR_LEGACY || | ||
994 | !(flags & DRM_AUTH)) | ||
995 | return NULL; | ||
996 | |||
997 | ret = mutex_lock_interruptible(&dev->master_mutex); | ||
998 | if (unlikely(ret != 0)) | ||
999 | return ERR_PTR(-ERESTARTSYS); | ||
1000 | |||
1001 | if (file_priv->is_master) { | ||
1002 | mutex_unlock(&dev->master_mutex); | ||
1003 | return NULL; | ||
1004 | } | ||
1005 | |||
1006 | /* | ||
1007 | * Check if we were previously master, but now dropped. | ||
1008 | */ | ||
1009 | if (vmw_fp->locked_master) { | ||
1010 | mutex_unlock(&dev->master_mutex); | ||
1011 | DRM_ERROR("Dropped master trying to access ioctl that " | ||
1012 | "requires authentication.\n"); | ||
1013 | return ERR_PTR(-EACCES); | ||
1014 | } | ||
1015 | mutex_unlock(&dev->master_mutex); | ||
1016 | |||
1017 | /* | ||
1018 | * Taking the drm_global_mutex after the TTM lock might deadlock | ||
1019 | */ | ||
1020 | if (!(flags & DRM_UNLOCKED)) { | ||
1021 | DRM_ERROR("Refusing locked ioctl access.\n"); | ||
1022 | return ERR_PTR(-EDEADLK); | ||
1023 | } | ||
1024 | |||
1025 | /* | ||
1026 | * Take the TTM lock. Possibly sleep waiting for the authenticating | ||
1027 | * master to become master again, or for a SIGTERM if the | ||
1028 | * authenticating master exits. | ||
1029 | */ | ||
1030 | vmaster = vmw_master(file_priv->master); | ||
1031 | ret = ttm_read_lock(&vmaster->lock, true); | ||
1032 | if (unlikely(ret != 0)) | ||
1033 | vmaster = ERR_PTR(ret); | ||
1034 | |||
1035 | return vmaster; | ||
1036 | } | ||
1037 | |||
1038 | static long vmw_generic_ioctl(struct file *filp, unsigned int cmd, | ||
1039 | unsigned long arg, | ||
1040 | long (*ioctl_func)(struct file *, unsigned int, | ||
1041 | unsigned long)) | ||
987 | { | 1042 | { |
988 | struct drm_file *file_priv = filp->private_data; | 1043 | struct drm_file *file_priv = filp->private_data; |
989 | struct drm_device *dev = file_priv->minor->dev; | 1044 | struct drm_device *dev = file_priv->minor->dev; |
990 | unsigned int nr = DRM_IOCTL_NR(cmd); | 1045 | unsigned int nr = DRM_IOCTL_NR(cmd); |
1046 | struct vmw_master *vmaster; | ||
1047 | unsigned int flags; | ||
1048 | long ret; | ||
991 | 1049 | ||
992 | /* | 1050 | /* |
993 | * Do extra checking on driver private ioctls. | 1051 | * Do extra checking on driver private ioctls. |
@@ -996,18 +1054,44 @@ static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, | |||
996 | if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) | 1054 | if ((nr >= DRM_COMMAND_BASE) && (nr < DRM_COMMAND_END) |
997 | && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { | 1055 | && (nr < DRM_COMMAND_BASE + dev->driver->num_ioctls)) { |
998 | const struct drm_ioctl_desc *ioctl = | 1056 | const struct drm_ioctl_desc *ioctl = |
999 | &vmw_ioctls[nr - DRM_COMMAND_BASE]; | 1057 | &vmw_ioctls[nr - DRM_COMMAND_BASE]; |
1000 | 1058 | ||
1001 | if (unlikely(ioctl->cmd_drv != cmd)) { | 1059 | if (unlikely(ioctl->cmd_drv != cmd)) { |
1002 | DRM_ERROR("Invalid command format, ioctl %d\n", | 1060 | DRM_ERROR("Invalid command format, ioctl %d\n", |
1003 | nr - DRM_COMMAND_BASE); | 1061 | nr - DRM_COMMAND_BASE); |
1004 | return -EINVAL; | 1062 | return -EINVAL; |
1005 | } | 1063 | } |
1064 | flags = ioctl->flags; | ||
1065 | } else if (!drm_ioctl_flags(nr, &flags)) | ||
1066 | return -EINVAL; | ||
1067 | |||
1068 | vmaster = vmw_master_check(dev, file_priv, flags); | ||
1069 | if (unlikely(IS_ERR(vmaster))) { | ||
1070 | DRM_INFO("IOCTL ERROR %d\n", nr); | ||
1071 | return PTR_ERR(vmaster); | ||
1006 | } | 1072 | } |
1007 | 1073 | ||
1008 | return drm_ioctl(filp, cmd, arg); | 1074 | ret = ioctl_func(filp, cmd, arg); |
1075 | if (vmaster) | ||
1076 | ttm_read_unlock(&vmaster->lock); | ||
1077 | |||
1078 | return ret; | ||
1079 | } | ||
1080 | |||
1081 | static long vmw_unlocked_ioctl(struct file *filp, unsigned int cmd, | ||
1082 | unsigned long arg) | ||
1083 | { | ||
1084 | return vmw_generic_ioctl(filp, cmd, arg, &drm_ioctl); | ||
1009 | } | 1085 | } |
1010 | 1086 | ||
1087 | #ifdef CONFIG_COMPAT | ||
1088 | static long vmw_compat_ioctl(struct file *filp, unsigned int cmd, | ||
1089 | unsigned long arg) | ||
1090 | { | ||
1091 | return vmw_generic_ioctl(filp, cmd, arg, &drm_compat_ioctl); | ||
1092 | } | ||
1093 | #endif | ||
1094 | |||
1011 | static void vmw_lastclose(struct drm_device *dev) | 1095 | static void vmw_lastclose(struct drm_device *dev) |
1012 | { | 1096 | { |
1013 | struct drm_crtc *crtc; | 1097 | struct drm_crtc *crtc; |
@@ -1315,7 +1399,7 @@ static const struct file_operations vmwgfx_driver_fops = { | |||
1315 | .poll = vmw_fops_poll, | 1399 | .poll = vmw_fops_poll, |
1316 | .read = vmw_fops_read, | 1400 | .read = vmw_fops_read, |
1317 | #if defined(CONFIG_COMPAT) | 1401 | #if defined(CONFIG_COMPAT) |
1318 | .compat_ioctl = drm_compat_ioctl, | 1402 | .compat_ioctl = vmw_compat_ioctl, |
1319 | #endif | 1403 | #endif |
1320 | .llseek = noop_llseek, | 1404 | .llseek = noop_llseek, |
1321 | }; | 1405 | }; |