diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2010-11-07 20:12:29 -0500 |
---|---|---|
committer | Chris Wilson <chris@chris-wilson.co.uk> | 2010-11-08 04:19:11 -0500 |
commit | b47b30ccdaad5f2fc39a1a65921bffd150574a91 (patch) | |
tree | 9eaef1721b05daa71010de638e02b2e6b4850598 /drivers/gpu/drm/i915 | |
parent | 16a02cf08a2de0863daf7ebb91718d7c6bbe7f9c (diff) |
drm/i915: Avoid might_fault during pwrite whilst holding our mutex
... and so prevent a potential circular reference:
[ INFO: possible circular locking dependency detected ]
2.6.37-rc1-uwe1+ #4
-------------------------------------------------------
Xorg/1401 is trying to acquire lock:
(&mm->mmap_sem){++++++}, at: [<c01e4ddb>] might_fault+0x4b/0xa0
but task is already holding lock:
(&dev->struct_mutex){+.+.+.}, at: [<f869c3ac>]
i915_mutex_lock_interruptible+0x3c/0x60 [i915]
which lock already depends on the new lock.
When the locking around the pwrite ioctl was simplified, I did not spot
that the phys path never took any locks and so we introduced this
potential circular reference.
Reported-by: Uwe Helm <uwe.helm@googlemail.com>
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
Diffstat (limited to 'drivers/gpu/drm/i915')
-rw-r--r-- | drivers/gpu/drm/i915/i915_gem.c | 25 |
1 files changed, 16 insertions, 9 deletions
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index 984eb6e9db03..eba9b1615228 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -4878,17 +4878,24 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj, | |||
4878 | struct drm_file *file_priv) | 4878 | struct drm_file *file_priv) |
4879 | { | 4879 | { |
4880 | struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); | 4880 | struct drm_i915_gem_object *obj_priv = to_intel_bo(obj); |
4881 | void *obj_addr; | 4881 | void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset; |
4882 | int ret; | 4882 | char __user *user_data = (char __user *) (uintptr_t) args->data_ptr; |
4883 | char __user *user_data; | ||
4884 | 4883 | ||
4885 | user_data = (char __user *) (uintptr_t) args->data_ptr; | 4884 | DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size); |
4886 | obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset; | ||
4887 | 4885 | ||
4888 | DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size); | 4886 | if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) { |
4889 | ret = copy_from_user(obj_addr, user_data, args->size); | 4887 | unsigned long unwritten; |
4890 | if (ret) | 4888 | |
4891 | return -EFAULT; | 4889 | /* The physical object once assigned is fixed for the lifetime |
4890 | * of the obj, so we can safely drop the lock and continue | ||
4891 | * to access vaddr. | ||
4892 | */ | ||
4893 | mutex_unlock(&dev->struct_mutex); | ||
4894 | unwritten = copy_from_user(vaddr, user_data, args->size); | ||
4895 | mutex_lock(&dev->struct_mutex); | ||
4896 | if (unwritten) | ||
4897 | return -EFAULT; | ||
4898 | } | ||
4892 | 4899 | ||
4893 | drm_agp_chipset_flush(dev); | 4900 | drm_agp_chipset_flush(dev); |
4894 | return 0; | 4901 | return 0; |