aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Wilson2010-01-06 09:19:25 -0600
committerChris Wilson2010-01-06 09:33:21 -0600
commitd1308f4fe7f94aae51ca9f70947aea8e09597f37 (patch)
tree4db0684c9479c8cebe3003dbd4327bf8415ab197 /xf86drmMode.c
parent5dbc1b333b85695735dc5b484372758b9979b693 (diff)
downloadlibdrm-d1308f4fe7f94aae51ca9f70947aea8e09597f37.tar.gz
libdrm-d1308f4fe7f94aae51ca9f70947aea8e09597f37.tar.xz
libdrm-d1308f4fe7f94aae51ca9f70947aea8e09597f37.zip
modes: Retry GETRESOURCES if a hotplug event occurs between the two ioctls
Peter Clifton hit an issue whereby he had a spurious TV hotplug event that occurred between the two GETRESOURCES ioctls that caused the kernel to skip filling one array and led to a crash (as the size of the allocated and initialised block of memory differed from the reported size). Fixes: http://bugs.freedesktop.org/show_bug.cgi?id=25912 Crash whilst probing modes Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reported-by: Peter Clifton <pcjc2@cam.ac.uk>
Diffstat (limited to 'xf86drmMode.c')
-rw-r--r--xf86drmMode.c29
1 files changed, 22 insertions, 7 deletions
diff --git a/xf86drmMode.c b/xf86drmMode.c
index ca36b71b..7edc625a 100644
--- a/xf86drmMode.c
+++ b/xf86drmMode.c
@@ -136,14 +136,16 @@ void drmModeFreeEncoder(drmModeEncoderPtr ptr)
136 136
137drmModeResPtr drmModeGetResources(int fd) 137drmModeResPtr drmModeGetResources(int fd)
138{ 138{
139 struct drm_mode_card_res res; 139 struct drm_mode_card_res res, counts;
140 drmModeResPtr r = 0; 140 drmModeResPtr r = 0;
141 141
142retry:
142 memset(&res, 0, sizeof(struct drm_mode_card_res)); 143 memset(&res, 0, sizeof(struct drm_mode_card_res));
143
144 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) 144 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
145 return 0; 145 return 0;
146 146
147 counts = res;
148
147 if (res.count_fbs) 149 if (res.count_fbs)
148 res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t))); 150 res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
149 if (res.count_crtcs) 151 if (res.count_crtcs)
@@ -153,18 +155,31 @@ drmModeResPtr drmModeGetResources(int fd)
153 if (res.count_encoders) 155 if (res.count_encoders)
154 res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t))); 156 res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
155 157
156 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) { 158 if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
157 r = NULL;
158 goto err_allocs; 159 goto err_allocs;
160
161 /* The number of available connectors and etc may have changed with a
162 * hotplug event in between the ioctls, in which case the field is
163 * silently ignored by the kernel.
164 */
165 if (counts.count_fbs < res.count_fbs ||
166 counts.count_crtcs < res.count_crtcs ||
167 counts.count_connectors < res.count_connectors ||
168 counts.count_encoders < res.count_encoders)
169 {
170 drmFree(U642VOID(res.fb_id_ptr));
171 drmFree(U642VOID(res.crtc_id_ptr));
172 drmFree(U642VOID(res.connector_id_ptr));
173 drmFree(U642VOID(res.encoder_id_ptr));
174
175 goto retry;
159 } 176 }
160 177
161 /* 178 /*
162 * return 179 * return
163 */ 180 */
164
165
166 if (!(r = drmMalloc(sizeof(*r)))) 181 if (!(r = drmMalloc(sizeof(*r))))
167 return 0; 182 goto err_allocs;
168 183
169 r->min_width = res.min_width; 184 r->min_width = res.min_width;
170 r->max_width = res.max_width; 185 r->max_width = res.max_width;