From a8007af22bb1580998c81416b20a8c6e1e9ecd86 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Mon, 8 Nov 2010 01:12:29 +0000 Subject: [PATCH] --- yaml --- r: 221773 b: refs/heads/master c: b47b30ccdaad5f2fc39a1a65921bffd150574a91 h: refs/heads/master i: 221771: 584548815efe7182378aa1e09d6acac710f74899 v: v3 --- [refs] | 2 +- trunk/drivers/gpu/drm/i915/i915_gem.c | 25 ++++++++++++++++--------- 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/[refs] b/[refs] index 3031ac07dbec..55cba65a2c53 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 16a02cf08a2de0863daf7ebb91718d7c6bbe7f9c +refs/heads/master: b47b30ccdaad5f2fc39a1a65921bffd150574a91 diff --git a/trunk/drivers/gpu/drm/i915/i915_gem.c b/trunk/drivers/gpu/drm/i915/i915_gem.c index 984eb6e9db03..eba9b1615228 100644 --- a/trunk/drivers/gpu/drm/i915/i915_gem.c +++ b/trunk/drivers/gpu/drm/i915/i915_gem.c @@ -4878,17 +4878,24 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, struct drm_file *file_priv) { struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); - void *obj_addr; - int ret; - char __user *user_data; + void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset; + char __user *user_data = (char __user *) (uintptr_t) args->data_ptr; - user_data = (char __user *) (uintptr_t) args->data_ptr; - obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset; + DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size); - DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size); - ret = copy_from_user(obj_addr, user_data, args->size); - if (ret) - return -EFAULT; + if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { + unsigned long unwritten; + + /* The physical object once assigned is fixed for the lifetime + * of the obj, so we can safely drop the lock and continue + * to access vaddr. + */ + mutex_unlock(&dev->struct_mutex); + unwritten = copy_from_user(vaddr, user_data, args->size); + mutex_lock(&dev->struct_mutex); + if (unwritten) + return -EFAULT; + } drm_agp_chipset_flush(dev); return 0;