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>
This commit is contained in:
@@ -4878,17 +4878,24 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
|
|||||||
struct drm_file *file_priv)
|
struct drm_file *file_priv)
|
||||||
{
|
{
|
||||||
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
|
struct drm_i915_gem_object *obj_priv = to_intel_bo(obj);
|
||||||
void *obj_addr;
|
void *vaddr = obj_priv->phys_obj->handle->vaddr + args->offset;
|
||||||
int ret;
|
char __user *user_data = (char __user *) (uintptr_t) args->data_ptr;
|
||||||
char __user *user_data;
|
|
||||||
|
|
||||||
user_data = (char __user *) (uintptr_t) args->data_ptr;
|
DRM_DEBUG_DRIVER("vaddr %p, %lld\n", vaddr, args->size);
|
||||||
obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
|
|
||||||
|
|
||||||
DRM_DEBUG_DRIVER("obj_addr %p, %lld\n", obj_addr, args->size);
|
if (__copy_from_user_inatomic_nocache(vaddr, user_data, args->size)) {
|
||||||
ret = copy_from_user(obj_addr, user_data, args->size);
|
unsigned long unwritten;
|
||||||
if (ret)
|
|
||||||
return -EFAULT;
|
/* 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);
|
drm_agp_chipset_flush(dev);
|
||||||
return 0;
|
return 0;
|
||||||
|
Reference in New Issue
Block a user