Annying implementation details between ioctls in OpenBSD and Linux.
On OpenBSD we don't copyout the ioctl arguments back to userland if
the ioctl fails, whereas Linux does.  And of course the Intel
engineers designed an ioctl (DRM_IOCTL_I915_GEM_WAIT) that relies on
this :(.  If interrupted (so the ioctl fails with EINTR) it is
supposed to return the time remaining, such that userland can restart
without running the risk of waiting until the death of the universe.
Not entirely unreasonable, but nevertheless rather annoying.

Easiest way around this is to do the copyin/copyout ourselves in the
implementation of this ioctl.  Unfortunately that means a kernel ABI
break as we have to change the definition of the ioctl.  And our
i915_drm.h diverges a bit more from the Linux one.

ok?


Index: i915_drm.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915_drm.h,v
retrieving revision 1.19
diff -u -p -r1.19 i915_drm.h
--- i915_drm.h  15 Jun 2013 11:27:59 -0000      1.19
+++ i915_drm.h  19 Dec 2013 11:31:23 -0000
@@ -235,7 +235,7 @@ typedef struct drm_i915_sarea {
 #define DRM_IOCTL_I915_OVERLAY_ATTRS   DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_OVERLAY_ATTRS, struct drm_intel_overlay_attrs)
 #define DRM_IOCTL_I915_SET_SPRITE_COLORKEY     DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_SET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
 #define DRM_IOCTL_I915_GET_SPRITE_COLORKEY     DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_GET_SPRITE_COLORKEY, struct drm_intel_sprite_colorkey)
-#define DRM_IOCTL_I915_GEM_WAIT                DRM_IOWR(DRM_COMMAND_BASE + 
DRM_I915_GEM_WAIT, struct drm_i915_gem_wait)
+#define DRM_IOCTL_I915_GEM_WAIT                DRM_IO(  DRM_COMMAND_BASE + 
DRM_I915_GEM_WAIT /*, struct drm_i915_gem_wait */)
 #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE      DRM_IOWR (DRM_COMMAND_BASE + 
DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create)
 #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY     DRM_IOW (DRM_COMMAND_BASE + 
DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy)
 #define DRM_IOCTL_I915_REG_READ                        DRM_IOWR 
(DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read)
Index: i915/i915_gem.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/i915/i915_gem.c,v
retrieving revision 1.60
diff -u -p -r1.60 i915_gem.c
--- i915/i915_gem.c     15 Dec 2013 11:42:10 -0000      1.60
+++ i915/i915_gem.c     19 Dec 2013 11:31:23 -0000
@@ -2501,13 +2509,17 @@ i915_gem_object_flush_active(struct drm_
 int
 i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
 {
-       struct drm_i915_gem_wait *args = data;
+       struct drm_i915_gem_wait stkbuf;
+       struct drm_i915_gem_wait *args = &stkbuf;
        struct drm_i915_gem_object *obj;
        struct intel_ring_buffer *ring = NULL;
        struct timespec timeout_stack, *timeout = NULL;
        u32 seqno = 0;
        int ret = 0;
 
+       if (copyin(*(caddr_t *)data, &stkbuf, sizeof(stkbuf)))
+               return -EFAULT;
+
        if (args->timeout_ns >= 0) {
                timeout_stack = ns_to_timespec(args->timeout_ns);
                timeout = &timeout_stack;
@@ -2552,6 +2564,8 @@ i915_gem_wait_ioctl(struct drm_device *d
                WARN_ON(!timespec_valid(timeout));
                args->timeout_ns = timespec_to_ns(timeout);
        }
+       if (copyout(&stkbuf, *(caddr_t *)data, sizeof(stkbuf)))
+               return -EFAULT;
        return ret;
 
 out:

Reply via email to