Skip to content

Commit

Permalink
drm/nouveau: add locking around instobj list operations
Browse files Browse the repository at this point in the history
Fixes memory corruptions, oopses, etc. when multiple gpuobjs are
simultaneously created or destroyed.

Signed-off-by: Marcin Slusarz <marcin.slusarz@gmail.com>
Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
Cc: stable@vger.kernel.org
  • Loading branch information
Marcin Slusarz authored and Ben Skeggs committed Jan 13, 2013
1 parent 1a1841d commit 4c4101d
Showing 1 changed file with 27 additions and 8 deletions.
35 changes: 27 additions & 8 deletions drivers/gpu/drm/nouveau/core/subdev/instmem/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,21 @@ nouveau_instobj_create_(struct nouveau_object *parent,
if (ret)
return ret;

mutex_lock(&imem->base.mutex);
list_add(&iobj->head, &imem->list);
mutex_unlock(&imem->base.mutex);
return 0;
}

void
nouveau_instobj_destroy(struct nouveau_instobj *iobj)
{
if (iobj->head.prev)
list_del(&iobj->head);
struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine);

mutex_lock(&subdev->mutex);
list_del(&iobj->head);
mutex_unlock(&subdev->mutex);

return nouveau_object_destroy(&iobj->base);
}

Expand Down Expand Up @@ -88,6 +94,8 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
if (ret)
return ret;

mutex_lock(&imem->base.mutex);

list_for_each_entry(iobj, &imem->list, head) {
if (iobj->suspend) {
for (i = 0; i < iobj->size; i += 4)
Expand All @@ -97,24 +105,35 @@ nouveau_instmem_init(struct nouveau_instmem *imem)
}
}

mutex_unlock(&imem->base.mutex);

return 0;
}

int
nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend)
{
struct nouveau_instobj *iobj;
int i;
int i, ret = 0;

if (suspend) {
mutex_lock(&imem->base.mutex);

list_for_each_entry(iobj, &imem->list, head) {
iobj->suspend = vmalloc(iobj->size);
if (iobj->suspend) {
for (i = 0; i < iobj->size; i += 4)
iobj->suspend[i / 4] = nv_ro32(iobj, i);
} else
return -ENOMEM;
if (!iobj->suspend) {
ret = -ENOMEM;
break;
}

for (i = 0; i < iobj->size; i += 4)
iobj->suspend[i / 4] = nv_ro32(iobj, i);
}

mutex_unlock(&imem->base.mutex);

if (ret)
return ret;
}

return nouveau_subdev_fini(&imem->base, suspend);
Expand Down

0 comments on commit 4c4101d

Please sign in to comment.