[PATCH 3/3] drm: do not sleep on vblank while holding a mutex

Ilija Hadzic ihadzic at research.bell-labs.com
Wed Oct 26 15:33:24 PDT 2011



On Wed, 26 Oct 2011, Daniel Vetter wrote:

>
> While you mess around with this code, please use the standard linux
> wait_event_* infrastructure.

Right now the order of entering the queue is guaranteed to be the same as 
the order of entering the ioctl, which reflects the order of progressing 
vblank sequence. I wanted to preserve this semantic, so I need a wait 
function that puts the task into the queue and then unlocks the mutex 
(essentially a kernel equivalent of pthread_cond_wait that POSIX threads 
library implements).

The closest "approximation" of that wait_event_interruptable_locked, but 
that requires a spinlock, not mutex (and thus the rework to 
drm_wait_vblank ioctl would be more radical.

> I want to stop that DRM_FOO yelling from
> spreading around - the idea of the drm core being os agnostic died quite a
> while ago.
>

Is DRM support for other OS-es officially dead ? I know it's not in best 
shape on BSD and friends, but I am not sure if I should make it worse (or 
inconsistent with the current code shape and form).

Anyway, the primary reason for implementing the DRM_WAIT_ON_LOCKED
is because I didn't have the function that enqueues the task and then 
releases the mutex.

> Again, have you carefully checked whether this is safe and how the
> relevant data structures (vblank counting) are proctected?
>

I am only moving the global lock further down in the function. The 
structures moved out of the critical section are only local vars. and 
arguments. So it's safe. Had I changed the mutex to something other than 
global one (which is the right thing to do in a long run) then a more 
careful review would be warranted.

Also note that running drm_wait_ioctl as DRM_LOCKED is a severe problem 
that we have to address quickly. So I'd like to get *some* kind of decent 
fix in this merge window and then follow up with more polishing later.

For example, try compiling and running this code (which any bozo in the 
userland can do):

#include <stdio.h>
#include <xf86drm.h>

main()
{
     int fd;
     drmVBlank vbl;

     fd = open("/dev/dri/card0", 0);
     printf("fd=%d\n", fd);

     while(1) {
         vbl.request.type =  DRM_VBLANK_RELATIVE ;
         vbl.request.sequence = 60;
         printf("waiting on vblank\n");
         ioctl(fd, DRM_IOCTL_WAIT_VBLANK, &vbl);
     }
}

Then start glxgears (on CRTC-0) and watch the hell break loose. The 
hostile code will cause any OpenGL application to hang for a full second 
before it can even enter the vblank_wait. Now because all vblank waits go 
through a common function in DDX, the whole windowing system will 
consequently go into a crawl. Run it with Compiz and things are even worse 
(the whole windowing system goes "stupid" as soon as the hostile 
application is started).


>> +	add_wait_queue(&(queue), &entry);			\
>> +	mutex_unlock(&drm_global_mutex);			\
>
> Hiding a lock-dropping in this fashion is horrible.
>

I explained above why am I have to release the lock inside the macro. 
That's equivalent to what you can find in the userland in POSIX threads, 
like I said. So that's not bad.

What *is* bad is that I should have passed the mutex as an argument to 
DRM_WAIT_ON_LOCKED and that I'll fix.

-- Ilija


More information about the dri-devel mailing list