Commit 4c4101d2 authored by Marcin Slusarz's avatar Marcin Slusarz Committed by Ben Skeggs

drm/nouveau: add locking around instobj list operations

Fixes memory corruptions, oopses, etc. when multiple gpuobjs are
simultaneously created or destroyed.
Signed-off-by: default avatarMarcin Slusarz <marcin.slusarz@gmail.com>
Signed-off-by: default avatarBen Skeggs <bskeggs@redhat.com>
Cc: stable@vger.kernel.org
parent 1a1841d3
...@@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent, ...@@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent,
if (ret) if (ret)
return ret; return ret;
mutex_lock(&imem->base.mutex);
list_add(&iobj->head, &imem->list); list_add(&iobj->head, &imem->list);
mutex_unlock(&imem->base.mutex);
return 0; return 0;
} }
void void
nouveau_instobj_destroy(struct nouveau_instobj *iobj) nouveau_instobj_destroy(struct nouveau_instobj *iobj)
{ {
if (iobj->head.prev) struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine);
mutex_lock(&subdev->mutex);
list_del(&iobj->head); list_del(&iobj->head);
mutex_unlock(&subdev->mutex);
return nouveau_object_destroy(&iobj->base); return nouveau_object_destroy(&iobj->base);
} }
...@@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) ...@@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
if (ret) if (ret)
return ret; return ret;
mutex_lock(&imem->base.mutex);
list_for_each_entry(iobj, &imem->list, head) { list_for_each_entry(iobj, &imem->list, head) {
if (iobj->suspend) { if (iobj->suspend) {
for (i = 0; i < iobj->size; i += 4) for (i = 0; i < iobj->size; i += 4)
...@@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem) ...@@ -97,6 +105,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
} }
} }
mutex_unlock(&imem->base.mutex);
return 0; return 0;
} }
...@@ -104,17 +114,26 @@ int ...@@ -104,17 +114,26 @@ int
nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend) nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend)
{ {
struct nouveau_instobj *iobj; struct nouveau_instobj *iobj;
int i; int i, ret = 0;
if (suspend) { if (suspend) {
mutex_lock(&imem->base.mutex);
list_for_each_entry(iobj, &imem->list, head) { list_for_each_entry(iobj, &imem->list, head) {
iobj->suspend = vmalloc(iobj->size); iobj->suspend = vmalloc(iobj->size);
if (iobj->suspend) { if (!iobj->suspend) {
ret = -ENOMEM;
break;
}
for (i = 0; i < iobj->size; i += 4) for (i = 0; i < iobj->size; i += 4)
iobj->suspend[i / 4] = nv_ro32(iobj, i); iobj->suspend[i / 4] = nv_ro32(iobj, i);
} else
return -ENOMEM;
} }
mutex_unlock(&imem->base.mutex);
if (ret)
return ret;
} }
return nouveau_subdev_fini(&imem->base, suspend); return nouveau_subdev_fini(&imem->base, suspend);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment