From 1c92a85bdb460cee779c207999faf16c7ecdd196 Mon Sep 17 00:00:00 2001 From: Thomas Hellstrom Date: Sat, 1 Mar 2008 17:01:57 +0100 Subject: [PATCH] Copy back buffer validate replies immediately after validation succeeds. If we hit an -EAGAIN, restore the original buffer validate arguments. --- shared-core/i915_dma.c | 77 ++++++++++++++++++++++++++++++++++-------------- 1 files changed, 55 insertions(+), 22 deletions(-) diff --git a/shared-core/i915_dma.c b/shared-core/i915_dma.c index f9e02c7..eda9570 100644 --- a/shared-core/i915_dma.c +++ b/shared-core/i915_dma.c @@ -810,10 +810,9 @@ struct i915_relocatee_info { struct drm_i915_validate_buffer { struct drm_buffer_object *buffer; - struct drm_bo_info_rep rep; + struct drm_bo_op_req req; int presumed_offset_correct; void __user *data; - int ret; }; static void i915_dereference_buffers_locked(struct drm_i915_validate_buffer *buffers, @@ -1071,6 +1070,7 @@ int i915_validate_buffer_list(struct drm { struct drm_i915_op_arg arg; struct drm_bo_op_req *req = &arg.d.req; + struct drm_bo_arg_rep rep; int ret = 0; unsigned buf_count = 0; uint32_t buf_handle; @@ -1078,31 +1078,31 @@ int i915_validate_buffer_list(struct drm struct drm_i915_validate_buffer *item = buffers; do { + item = buffers + buf_count; + item->data = (void __user *) (unsigned long) data; + item->buffer = NULL; + item->presumed_offset_correct = 0; + if (buf_count >= *num_buffers) { DRM_ERROR("Buffer count exceeded %d\n.", *num_buffers); ret = -EINVAL; goto out_err; } - item = buffers + buf_count; - item->buffer = NULL; - item->presumed_offset_correct = 0; buffers[buf_count].buffer = NULL; if (copy_from_user(&arg, (void __user *)(unsigned long)data, sizeof(arg))) { ret = -EFAULT; - goto out_err; + goto out_err_copy; } - ret = 0; + if (req->op != drm_bo_validate) { DRM_ERROR ("Buffer object operation wasn't \"validate\".\n"); ret = -EINVAL; - goto out_err; + goto out_err_copy; } - item->ret = 0; - item->data = (void __user *) (unsigned long) data; buf_handle = req->bo_req.handle; reloc_user_ptr = (uint32_t *)(unsigned long)arg.reloc_ptr; @@ -1114,32 +1114,52 @@ int i915_validate_buffer_list(struct drm DRM_MEMORYBARRIER(); } + arg.handled = 1; ret = drm_bo_handle_validate(file_priv, req->bo_req.handle, req->bo_req.flags, req->bo_req.mask, req->bo_req.hint, req->bo_req.fence_class, 0, - &item->rep, + &rep.bo_info, &item->buffer); if (ret) { DRM_ERROR("error on handle validate %d\n", ret); - goto out_err; + goto out_err_copy; } + item->req = *req; buf_count++; + rep.ret = 0; ret = i915_check_presumed(&arg, item->buffer, (uint32_t __user *) (unsigned long) data, &item->presumed_offset_correct); + arg.d.rep = rep; + if (ret) + goto out_err; + + ret = __copy_to_user(item->data, &arg, sizeof(arg)); if (ret) goto out_err; data = arg.next; } while (data != 0); + +out_err_copy: + + /* + * Buffer specific error. + */ + + if (ret && (ret != -EAGAIN)) { + rep.ret = ret; + arg.handled = 1; + if (__copy_to_user(item->data, &arg, sizeof(arg))) + ret = -EFAULT; + } out_err: *num_buffers = buf_count; - item->ret = (ret != -EAGAIN) ? ret : 0; return ret; } @@ -1149,8 +1169,8 @@ out_err: * If the execbuffer operation was aborted, for example due to a signal, * this also make sure that buffers retain their original state and * fence pointers. - * Copy back buffer information to user-space unless we were interrupted - * by a signal. In which case the IOCTL must be rerun. + * Restore the origininal IOCTL arguments in case we've hit an EAGAIN and + * the IOCTL needs to be rerun. */ static int i915_handle_copyback(struct drm_device *dev, @@ -1159,17 +1179,30 @@ static int i915_handle_copyback(struct d { int err = ret; int i; - struct drm_i915_op_arg arg; - + uint8_t __user *user_req; if (ret) drm_putback_buffer_objects(dev); - if (ret != -EAGAIN) { + if (ret == -EAGAIN) { for (i = 0; i < num_buffers; ++i) { - arg.handled = 1; - arg.d.rep.ret = buffers->ret; - arg.d.rep.bo_info = buffers->rep; - if (__copy_to_user(buffers->data, &arg, sizeof(arg))) + + /* + * Set arg.handled to zero. + */ + + user_req = buffers->data; + user_req += offsetof(struct drm_i915_op_arg, handled); + if (__put_user(0, (int __user *)user_req)) + err = -EFAULT; + + /* + * Restore the original arg.d.req member. + */ + + user_req = buffers->data; + user_req += offsetof(struct drm_i915_op_arg, d.req); + if (__copy_to_user(user_req, &buffers->req, + sizeof(buffers->req))) err = -EFAULT; buffers++; } -- 1.4.1