Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+27 −8
Original line number Original line Diff line number Diff line
@@ -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)
	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)
		}
		}
	}
	}


	mutex_unlock(&imem->base.mutex);

	return 0;
	return 0;
}
}


@@ -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);