aboutsummaryrefslogtreecommitdiffstats
path: root/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.19.8/3153-drm-syncobj-fix-leaking-dma_fence-in-drm_syncobj_que.patch
blob: 232f500868f447c13f2fa421bdc89528832a5cbe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
From 4352bbe79144d6293cab9514012b625a820207f9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Christian=20K=C3=B6nig?= <christian.koenig@amd.com>
Date: Mon, 22 Jul 2019 14:56:25 +0200
Subject: [PATCH 3153/4256] drm/syncobj: fix leaking dma_fence in
 drm_syncobj_query_ioctl
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

We need to check the context number instead if the previous sequence to detect
an error and if an error is detected we need to drop the reference to the
current fence or otherwise would leak it.

Signed-off-by: Christian König <christian.koenig@amd.com>
Reviewed-by: Lionel Landwerlin <lionel.g.landwerlin@intel.com>
Fixes: 27b575a9aa2f ("drm/syncobj: add timeline payload query ioctl v6")
Link: https://patchwork.freedesktop.org/patch/319123/
---
 drivers/gpu/drm/drm_syncobj.c | 62 +++++++++++++++++++++++++++++++++++
 include/uapi/drm/drm.h        |  7 ++++
 2 files changed, 69 insertions(+)

diff --git a/drivers/gpu/drm/drm_syncobj.c b/drivers/gpu/drm/drm_syncobj.c
index 74482832c759..abda0a01d8dc 100644
--- a/drivers/gpu/drm/drm_syncobj.c
+++ b/drivers/gpu/drm/drm_syncobj.c
@@ -1069,3 +1069,65 @@ drm_syncobj_signal_ioctl(struct drm_device *dev, void *data,
 
 	return ret;
 }
+
+int drm_syncobj_query_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_private)
+{
+        struct drm_syncobj_timeline_array *args = data;
+        struct drm_syncobj **syncobjs;
+        uint64_t __user *points = u64_to_user_ptr(args->points);
+        uint32_t i;
+        int ret;
+
+        if (!drm_core_check_feature(dev, DRIVER_SYNCOBJ))
+                return -ENODEV;
+
+        if (args->pad != 0)
+                return -EINVAL;
+
+        if (args->count_handles == 0)
+                return -EINVAL;
+
+        ret = drm_syncobj_array_find(file_private,
+                                     u64_to_user_ptr(args->handles),
+                                     args->count_handles,
+                                     &syncobjs);
+        if (ret < 0)
+                return ret;
+
+        for (i = 0; i < args->count_handles; i++) {
+                struct dma_fence_chain *chain;
+                struct dma_fence *fence;
+                uint64_t point;
+
+                fence = drm_syncobj_fence_get(syncobjs[i]);
+                chain = to_dma_fence_chain(fence);
+                if (chain) {
+                        struct dma_fence *iter, *last_signaled = NULL;
+
+                        dma_fence_chain_for_each(iter, fence) {
+                                if (iter->context != fence->context) {
+                                        dma_fence_put(iter);
+                                        /* It is most likely that timeline has
+                                         * unorder points. */
+                                        break;
+                                }
+                                dma_fence_put(last_signaled);
+                                last_signaled = dma_fence_get(iter);
+                        }
+                        point = dma_fence_is_signaled(last_signaled) ?
+                                last_signaled->seqno :
+                                to_dma_fence_chain(last_signaled)->prev_seqno;
+                        dma_fence_put(last_signaled);
+                } else {
+                        point = 0;
+                }
+                ret = copy_to_user(&points[i], &point, sizeof(uint64_t));
+                ret = ret ? -EFAULT : 0;
+                if (ret)
+                        break;
+        }
+        drm_syncobj_array_free(syncobjs, args->count_handles);
+
+        return ret;
+}
diff --git a/include/uapi/drm/drm.h b/include/uapi/drm/drm.h
index 300f336633f2..c18616d7fcd5 100644
--- a/include/uapi/drm/drm.h
+++ b/include/uapi/drm/drm.h
@@ -753,6 +753,13 @@ struct drm_syncobj_array {
 	__u32 pad;
 };
 
+struct drm_syncobj_timeline_array {
+        __u64 handles;
+        __u64 points;
+        __u32 count_handles;
+        __u32 pad;
+};
+
 /* Query current scanout sequence number */
 struct drm_crtc_get_sequence {
 	__u32 crtc_id;		/* requested crtc_id */
-- 
2.17.1