[Nouveau] [PATCH] nouveau: safen up nouveau_device list usage against concurrent access
Ben Skeggs
skeggsb at gmail.com
Tue Mar 25 21:50:23 PDT 2014
On Thu, Mar 13, 2014 at 12:05 PM, Ilia Mirkin <imirkin at alum.mit.edu> wrote:
> Signed-off-by: Ilia Mirkin <imirkin at alum.mit.edu>
Already said on IRC, but for posterity:
Reviewed-by: Ben Skeggs <bskeggs at redhat.com>
> ---
> nouveau/nouveau.c | 29 ++++++++++++++++++++++++++++-
> nouveau/private.h | 3 ++-
> 2 files changed, 30 insertions(+), 2 deletions(-)
>
> diff --git a/nouveau/nouveau.c b/nouveau/nouveau.c
> index ee7893b..72c31cf 100644
> --- a/nouveau/nouveau.c
> +++ b/nouveau/nouveau.c
> @@ -85,6 +85,12 @@ nouveau_device_wrap(int fd, int close, struct nouveau_device **pdev)
>
> if (!nvdev)
> return -ENOMEM;
> + ret = pthread_mutex_init(&nvdev->lock, NULL);
> + if (ret) {
> + free(nvdev);
> + return ret;
> + }
> +
> nvdev->base.fd = fd;
>
> ver = drmGetVersion(fd);
> @@ -161,6 +167,7 @@ nouveau_device_del(struct nouveau_device **pdev)
> if (nvdev->close)
> drmClose(nvdev->base.fd);
> free(nvdev->client);
> + pthread_mutex_destroy(&nvdev->lock);
> free(nvdev);
> *pdev = NULL;
> }
> @@ -191,6 +198,8 @@ nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient)
> int id = 0, i, ret = -ENOMEM;
> uint32_t *clients;
>
> + pthread_mutex_lock(&nvdev->lock);
> +
> for (i = 0; i < nvdev->nr_client; i++) {
> id = ffs(nvdev->client[i]) - 1;
> if (id >= 0)
> @@ -199,7 +208,7 @@ nouveau_client_new(struct nouveau_device *dev, struct nouveau_client **pclient)
>
> clients = realloc(nvdev->client, sizeof(uint32_t) * (i + 1));
> if (!clients)
> - return ret;
> + goto unlock;
> nvdev->client = clients;
> nvdev->client[i] = 0;
> nvdev->nr_client++;
> @@ -214,6 +223,9 @@ out:
> }
>
> *pclient = &pcli->base;
> +
> +unlock:
> + pthread_mutex_unlock(&nvdev->lock);
> return ret;
> }
>
> @@ -225,7 +237,9 @@ nouveau_client_del(struct nouveau_client **pclient)
> if (pcli) {
> int id = pcli->base.id;
> nvdev = nouveau_device(pcli->base.device);
> + pthread_mutex_lock(&nvdev->lock);
> nvdev->client[id / 32] &= ~(1 << (id % 32));
> + pthread_mutex_unlock(&nvdev->lock);
> free(pcli->kref);
> free(pcli);
> }
> @@ -331,9 +345,12 @@ nouveau_object_find(struct nouveau_object *obj, uint32_t pclass)
> static void
> nouveau_bo_del(struct nouveau_bo *bo)
> {
> + struct nouveau_device_priv *nvdev = nouveau_device(bo->device);
> struct nouveau_bo_priv *nvbo = nouveau_bo(bo);
> struct drm_gem_close req = { bo->handle };
> + pthread_mutex_lock(&nvdev->lock);
> DRMLISTDEL(&nvbo->head);
> + pthread_mutex_unlock(&nvdev->lock);
> if (bo->map)
> munmap(bo->map, bo->size);
> drmIoctl(bo->device->fd, DRM_IOCTL_GEM_CLOSE, &req);
> @@ -363,7 +380,9 @@ nouveau_bo_new(struct nouveau_device *dev, uint32_t flags, uint32_t align,
> return ret;
> }
>
> + pthread_mutex_lock(&nvdev->lock);
> DRMLISTADD(&nvbo->head, &nvdev->bo_list);
> + pthread_mutex_unlock(&nvdev->lock);
>
> *pbo = bo;
> return 0;
> @@ -378,13 +397,16 @@ nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
> struct nouveau_bo_priv *nvbo;
> int ret;
>
> + pthread_mutex_lock(&nvdev->lock);
> DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) {
> if (nvbo->base.handle == handle) {
> + pthread_mutex_unlock(&nvdev->lock);
> *pbo = NULL;
> nouveau_bo_ref(&nvbo->base, pbo);
> return 0;
> }
> }
> + pthread_mutex_unlock(&nvdev->lock);
>
> ret = drmCommandWriteRead(dev->fd, DRM_NOUVEAU_GEM_INFO,
> &req, sizeof(req));
> @@ -396,7 +418,9 @@ nouveau_bo_wrap(struct nouveau_device *dev, uint32_t handle,
> atomic_set(&nvbo->refcnt, 1);
> nvbo->base.device = dev;
> abi16_bo_info(&nvbo->base, &req);
> + pthread_mutex_lock(&nvdev->lock);
> DRMLISTADD(&nvbo->head, &nvdev->bo_list);
> + pthread_mutex_unlock(&nvdev->lock);
> *pbo = &nvbo->base;
> return 0;
> }
> @@ -413,13 +437,16 @@ nouveau_bo_name_ref(struct nouveau_device *dev, uint32_t name,
> struct drm_gem_open req = { .name = name };
> int ret;
>
> + pthread_mutex_lock(&nvdev->lock);
> DRMLISTFOREACHENTRY(nvbo, &nvdev->bo_list, head) {
> if (nvbo->name == name) {
> + pthread_mutex_unlock(&nvdev->lock);
> *pbo = NULL;
> nouveau_bo_ref(&nvbo->base, pbo);
> return 0;
> }
> }
> + pthread_mutex_unlock(&nvdev->lock);
>
> ret = drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req);
> if (ret == 0) {
> diff --git a/nouveau/private.h b/nouveau/private.h
> index 60714b8..4f337ad 100644
> --- a/nouveau/private.h
> +++ b/nouveau/private.h
> @@ -3,6 +3,7 @@
>
> #include <xf86drm.h>
> #include <xf86atomic.h>
> +#include <pthread.h>
> #include "nouveau_drm.h"
>
> #include "nouveau.h"
> @@ -94,7 +95,7 @@ nouveau_bo(struct nouveau_bo *bo)
> struct nouveau_device_priv {
> struct nouveau_device base;
> int close;
> - atomic_t lock;
> + pthread_mutex_t lock;
> struct nouveau_list bo_list;
> uint32_t *client;
> int nr_client;
> --
> 1.8.3.2
>
> _______________________________________________
> Nouveau mailing list
> Nouveau at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/nouveau
More information about the Nouveau
mailing list