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>main
parent
5dbc1b333b
commit
d1308f4fe7
|
@ -136,14 +136,16 @@ void drmModeFreeEncoder(drmModeEncoderPtr ptr)
|
||||||
|
|
||||||
drmModeResPtr drmModeGetResources(int fd)
|
drmModeResPtr drmModeGetResources(int fd)
|
||||||
{
|
{
|
||||||
struct drm_mode_card_res res;
|
struct drm_mode_card_res res, counts;
|
||||||
drmModeResPtr r = 0;
|
drmModeResPtr r = 0;
|
||||||
|
|
||||||
|
retry:
|
||||||
memset(&res, 0, sizeof(struct drm_mode_card_res));
|
memset(&res, 0, sizeof(struct drm_mode_card_res));
|
||||||
|
|
||||||
if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
|
if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
counts = res;
|
||||||
|
|
||||||
if (res.count_fbs)
|
if (res.count_fbs)
|
||||||
res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
|
res.fb_id_ptr = VOID2U64(drmMalloc(res.count_fbs*sizeof(uint32_t)));
|
||||||
if (res.count_crtcs)
|
if (res.count_crtcs)
|
||||||
|
@ -153,18 +155,31 @@ drmModeResPtr drmModeGetResources(int fd)
|
||||||
if (res.count_encoders)
|
if (res.count_encoders)
|
||||||
res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
|
res.encoder_id_ptr = VOID2U64(drmMalloc(res.count_encoders*sizeof(uint32_t)));
|
||||||
|
|
||||||
if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res)) {
|
if (drmIoctl(fd, DRM_IOCTL_MODE_GETRESOURCES, &res))
|
||||||
r = NULL;
|
|
||||||
goto err_allocs;
|
goto err_allocs;
|
||||||
|
|
||||||
|
/* The number of available connectors and etc may have changed with a
|
||||||
|
* hotplug event in between the ioctls, in which case the field is
|
||||||
|
* silently ignored by the kernel.
|
||||||
|
*/
|
||||||
|
if (counts.count_fbs < res.count_fbs ||
|
||||||
|
counts.count_crtcs < res.count_crtcs ||
|
||||||
|
counts.count_connectors < res.count_connectors ||
|
||||||
|
counts.count_encoders < res.count_encoders)
|
||||||
|
{
|
||||||
|
drmFree(U642VOID(res.fb_id_ptr));
|
||||||
|
drmFree(U642VOID(res.crtc_id_ptr));
|
||||||
|
drmFree(U642VOID(res.connector_id_ptr));
|
||||||
|
drmFree(U642VOID(res.encoder_id_ptr));
|
||||||
|
|
||||||
|
goto retry;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* return
|
* return
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
if (!(r = drmMalloc(sizeof(*r))))
|
if (!(r = drmMalloc(sizeof(*r))))
|
||||||
return 0;
|
goto err_allocs;
|
||||||
|
|
||||||
r->min_width = res.min_width;
|
r->min_width = res.min_width;
|
||||||
r->max_width = res.max_width;
|
r->max_width = res.max_width;
|
||||||
|
|
Loading…
Reference in New Issue