nouveau: fix bugs in error handling for nouveau_gem_new(). the call to drm_gem_object_init() does not initialise the bo in this object so calling nouveau_bo_ref() (which seems to actually implement an 'unref' type functionality) is invalid. the call to nouveau_bo_init() should initialise the object, but if it can fail before caling kref_init(&bo->kref), then the contract is broken and the error path call to nouveau_bo_ref() asserts on the 0-count. to fix this, move the kref_init() calls to the top of ttm_bo_init_reserved() so that they are always initialised, regardless if this function will return an error. diff --git a/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_gem.c b/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_gem.c index 8caacff6ea67..8fbffa2c12f5 100644 --- a/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_gem.c +++ b/sys/external/bsd/drm2/dist/drm/nouveau/nouveau_gem.c @@ -202,7 +202,6 @@ nouveau_gem_new(struct nouveau_cli *cli, u64 size, int align, uint32_t domain, * to the caller, instead of a normal nouveau_bo ttm reference. */ ret = drm_gem_object_init(drm->dev, &nvbo->bo.base, size); if (ret) { - nouveau_bo_ref(NULL, &nvbo); return ret; } diff --git a/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c b/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c index d84a75ea1f6a..70fbc8ed1e75 100644 --- a/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c +++ b/sys/external/bsd/drm2/dist/drm/ttm/ttm_bo.c @@ -1304,6 +1304,10 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, unsigned long num_pages; bool locked; + /* Ensure to always return with these initialized. */ + kref_init(&bo->kref); + kref_init(&bo->list_kref); + if (sg && !drm_prime_sg_importable(bdev->dmat, sg)) { pr_err("DRM prime buffer violates DMA constraints\n"); return -EIO; @@ -1331,8 +1335,6 @@ int ttm_bo_init_reserved(struct ttm_bo_device *bdev, } bo->destroy = destroy ? destroy : ttm_bo_default_destroy; - kref_init(&bo->kref); - kref_init(&bo->list_kref); INIT_LIST_HEAD(&bo->lru); INIT_LIST_HEAD(&bo->ddestroy); INIT_LIST_HEAD(&bo->swap);