diff options
Diffstat (limited to 'common/recipes-kernel/linux/files/0559-drm-amdgpu-unwind-properly-in-amdgpu_cs_parser_init.patch')
-rw-r--r-- | common/recipes-kernel/linux/files/0559-drm-amdgpu-unwind-properly-in-amdgpu_cs_parser_init.patch | 199 |
1 files changed, 199 insertions, 0 deletions
diff --git a/common/recipes-kernel/linux/files/0559-drm-amdgpu-unwind-properly-in-amdgpu_cs_parser_init.patch b/common/recipes-kernel/linux/files/0559-drm-amdgpu-unwind-properly-in-amdgpu_cs_parser_init.patch new file mode 100644 index 00000000..5bd16b0b --- /dev/null +++ b/common/recipes-kernel/linux/files/0559-drm-amdgpu-unwind-properly-in-amdgpu_cs_parser_init.patch @@ -0,0 +1,199 @@ +From 1d263474c4416efb6d0feca98fe6d462b0d28f56 Mon Sep 17 00:00:00 2001 +From: Dan Carpenter <dan.carpenter@oracle.com> +Date: Wed, 23 Sep 2015 13:59:28 +0300 +Subject: [PATCH 0559/1050] drm/amdgpu: unwind properly in + amdgpu_cs_parser_init() +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The amdgpu_cs_parser_init() function doesn't clean up after itself but +instead the caller uses a free everything function amdgpu_cs_parser_fini() +on failure. This style of error handling is often buggy. In this +example, we call "drm_free_large(parser->chunks[i].kdata);" when it is +an unintialized pointer or when "parser->chunks" is NULL. + +I fixed this bug by adding unwind code so that it frees everything that +it allocates. + +I also mode some other very minor changes: +1) Renamed "r" to "ret". +2) Moved the chunk_array allocation to the start of the function. +3) Removed some initializers which are no longer needed. + +Reviewed-by: Christian König <christian.koenig@amd.com> +Reported-by: Ilja Van Sprundel <ivansprundel@ioactive.com> +Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com> +Signed-off-by: Alex Deucher <alexander.deucher@amd.com> +--- + drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c | 85 ++++++++++++++++++++-------------- + 1 file changed, 51 insertions(+), 34 deletions(-) + +diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +index b74b6a8..749420f 100644 +--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c ++++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_cs.c +@@ -154,42 +154,41 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) + { + union drm_amdgpu_cs *cs = data; + uint64_t *chunk_array_user; +- uint64_t *chunk_array = NULL; ++ uint64_t *chunk_array; + struct amdgpu_fpriv *fpriv = p->filp->driver_priv; + unsigned size, i; +- int r = 0; ++ int ret; + +- if (!cs->in.num_chunks) +- goto out; ++ if (cs->in.num_chunks == 0) ++ return 0; ++ ++ chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL); ++ if (!chunk_array) ++ return -ENOMEM; + + p->ctx = amdgpu_ctx_get(fpriv, cs->in.ctx_id); + if (!p->ctx) { +- r = -EINVAL; +- goto out; ++ ret = -EINVAL; ++ goto free_chunk; + } ++ + p->bo_list = amdgpu_bo_list_get(fpriv, cs->in.bo_list_handle); + + /* get chunks */ + INIT_LIST_HEAD(&p->validated); +- chunk_array = kmalloc_array(cs->in.num_chunks, sizeof(uint64_t), GFP_KERNEL); +- if (chunk_array == NULL) { +- r = -ENOMEM; +- goto out; +- } +- + chunk_array_user = (uint64_t __user *)(cs->in.chunks); + if (copy_from_user(chunk_array, chunk_array_user, + sizeof(uint64_t)*cs->in.num_chunks)) { +- r = -EFAULT; +- goto out; ++ ret = -EFAULT; ++ goto put_bo_list; + } + + p->nchunks = cs->in.num_chunks; + p->chunks = kmalloc_array(p->nchunks, sizeof(struct amdgpu_cs_chunk), + GFP_KERNEL); +- if (p->chunks == NULL) { +- r = -ENOMEM; +- goto out; ++ if (!p->chunks) { ++ ret = -ENOMEM; ++ goto put_bo_list; + } + + for (i = 0; i < p->nchunks; i++) { +@@ -200,8 +199,9 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) + chunk_ptr = (void __user *)chunk_array[i]; + if (copy_from_user(&user_chunk, chunk_ptr, + sizeof(struct drm_amdgpu_cs_chunk))) { +- r = -EFAULT; +- goto out; ++ ret = -EFAULT; ++ i--; ++ goto free_partial_kdata; + } + p->chunks[i].chunk_id = user_chunk.chunk_id; + p->chunks[i].length_dw = user_chunk.length_dw; +@@ -212,13 +212,14 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) + + p->chunks[i].kdata = drm_malloc_ab(size, sizeof(uint32_t)); + if (p->chunks[i].kdata == NULL) { +- r = -ENOMEM; +- goto out; ++ ret = -ENOMEM; ++ i--; ++ goto free_partial_kdata; + } + size *= sizeof(uint32_t); + if (copy_from_user(p->chunks[i].kdata, cdata, size)) { +- r = -EFAULT; +- goto out; ++ ret = -EFAULT; ++ goto free_partial_kdata; + } + + switch (p->chunks[i].chunk_id) { +@@ -238,15 +239,15 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) + gobj = drm_gem_object_lookup(p->adev->ddev, + p->filp, handle); + if (gobj == NULL) { +- r = -EINVAL; +- goto out; ++ ret = -EINVAL; ++ goto free_partial_kdata; + } + + p->uf.bo = gem_to_amdgpu_bo(gobj); + p->uf.offset = fence_data->offset; + } else { +- r = -EINVAL; +- goto out; ++ ret = -EINVAL; ++ goto free_partial_kdata; + } + break; + +@@ -254,19 +255,35 @@ int amdgpu_cs_parser_init(struct amdgpu_cs_parser *p, void *data) + break; + + default: +- r = -EINVAL; +- goto out; ++ ret = -EINVAL; ++ goto free_partial_kdata; + } + } + + + p->ibs = kcalloc(p->num_ibs, sizeof(struct amdgpu_ib), GFP_KERNEL); +- if (!p->ibs) +- r = -ENOMEM; ++ if (!p->ibs) { ++ ret = -ENOMEM; ++ goto free_all_kdata; ++ } + +-out: + kfree(chunk_array); +- return r; ++ return 0; ++ ++free_all_kdata: ++ i = p->nchunks - 1; ++free_partial_kdata: ++ for (; i >= 0; i--) ++ drm_free_large(p->chunks[i].kdata); ++ kfree(p->chunks); ++put_bo_list: ++ if (p->bo_list) ++ amdgpu_bo_list_put(p->bo_list); ++ amdgpu_ctx_put(p->ctx); ++free_chunk: ++ kfree(chunk_array); ++ ++ return ret; + } + + /* Returns how many bytes TTM can move per IB. +@@ -810,7 +827,7 @@ int amdgpu_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *filp) + r = amdgpu_cs_parser_init(parser, data); + if (r) { + DRM_ERROR("Failed to initialize parser !\n"); +- amdgpu_cs_parser_fini(parser, r, false); ++ kfree(parser); + up_read(&adev->exclusive_lock); + r = amdgpu_cs_handle_lockup(adev, r); + return r; +-- +1.9.1 + |