[Mesa-dev] [PATCH] nouveau: Use dup fd as key in drm-winsys hash table to fix ZaphodHeads.

Mario Kleiner mario.kleiner.de at gmail.com
Sat Jun 27 17:58:18 PDT 2015

On 06/05/2015 03:57 PM, Mario Kleiner wrote:
> On 06/05/2015 03:50 PM, Ilia Mirkin wrote:
>> This scheme is copied from radeon, does it need a similar fix? I'm away
>> from computers for another week or so, will be able to look then.
> For some reason, no. Testing on Radeon multi-x-screen ZaphodHeads never
> showed such problems over multiple years and many mesa versions.
> Apparently it does something slightly different, although i saw the
> hashing logic with fstat() is the same. Maybe correct by slightly
> different design, or maybe we just get lucky because the same fd's
> aren't recycled on successive glXQueryVersion() calls?
> thanks,
> -mario

And to contradict myself, yes, it needs a similar fix for radeon, as 
both code inspection and testing showed. Not sure why this (seemed?) to 
work without problems for me for a long time, but at least on Mesa 10.5+ 
it crashes nicely in the expected way.

I'll send out a patch in the next minute which fixes the problem, as 
tested on a triple-display Radeon HD-5770 setup with different single 
x-screen and multi-x-screen ZaphodHeads configs.


>> On Jun 5, 2015 4:37 PM, "Mario Kleiner" <mario.kleiner.de at gmail.com
>> <mailto:mario.kleiner.de at gmail.com>> wrote:
>>     The dup'ed fd owned by the nouveau_screen for a device node
>>     must also be used as key for the winsys hash table, instead
>>     of using the original fd passed in for a screen, to make
>>     multi-x-screen ZaphodHeads configurations work on nouveau.
>>     This prevents the following crash scenario that was observed
>>     when a dynamically loaded rendering plugin used OpenGL on a
>>     ZaphodHeads setup, e.g., on a dual x-screen setup. At first
>>     load the plugin worked, but after unloading and reloading it,
>>     the next rendering operation crashed:
>>     1. Client, e.g., a plugin, calls glXQueryVersion.
>>     2. DRI screens for the x-screens 0 and 1 are created, one shared
>>         nouveau_screen is created for the shared device node of both
>>         screens, but the original fd of x-screen 0 is used as identifying
>>         key in the hash table, instead of the dup()ed fd of x-screen 0
>>         which is owned by the nouveau_screen. nouveau_screen's refcount
>>         is now 2.
>>     3. Regular rendering happens by the client plugin, then the plugin
>>         gets unloaded.
>>     4. XCloseDisplay(). x-screen 0 gets its DRI screen destroyed,
>>         nouveau_drm_screen_unref() drops the refcount to 1, calling mesa
>>         code then closes the fd of x-screen 0, so now the fd which is
>>         used as key in the hash table is invalid. x-screen 1 gets
>>         destroyed, nouveau_drm_screen_unref() drops the refcount to 0,
>>         the nouveau_screen gets destroyed, but removal of its entry
>>         in the hash table fails, because the invalid fd in the hash
>>         table no longer matches anything (fstat() on the fd is used
>>         for hashing and key comparison, but fstat() on an already closed
>>         fd fails and returns bogus results). x-screen 1 closes its fd.
>>         Now all fd's are closed, the nouveau_screen destroyed, but
>>         there is a dangling reference to the nouveau_screen in the
>>         hash table.
>>     5. Some OpenGL client plugin gets loaded again and calls
>>         glXQueryVersion. Step 2 above repeats, but because a
>>         dangling reference with a matching fd is found in the winsys
>>         hash table, no new nouveau_screen is created this time. Instead
>>         the invalid pointer to the old nouveau_screen is recycled,
>>         which points to nirvana -> Crash.
>>     This problem is avoided by use of the dup()ed fd which is
>>     owned by the nouveau_screen and has the same lifetime as
>>     the nouveau_screen itself.
>>     Cc: "10.3 10.4 10.5 10.6" <mesa-stable at lists.freedesktop.org
>>     <mailto:mesa-stable at lists.freedesktop.org>>
>>     Signed-off-by: Mario Kleiner <mario.kleiner.de at gmail.com
>>     <mailto:mario.kleiner.de at gmail.com>>
>>     Cc: Ilia Mirkin <imirkin at alum.mit.edu <mailto:imirkin at alum.mit.edu>>
>>     ---
>>       src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c | 3 ++-
>>       1 file changed, 2 insertions(+), 1 deletion(-)
>>     diff --git a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
>>     b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
>>     index 0635246..dbc3cae 100644
>>     --- a/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
>>     +++ b/src/gallium/winsys/nouveau/drm/nouveau_drm_winsys.c
>>     @@ -120,7 +120,8 @@ nouveau_drm_screen_create(int fd)
>>              if (!screen)
>>                      goto err;
>>     -       util_hash_table_set(fd_tab, intptr_to_pointer(fd), screen);
>>     +       /* Use dupfd in hash table, to avoid crashes in ZaphodHeads
>>     configs */
>>     +       util_hash_table_set(fd_tab, intptr_to_pointer(dupfd),
>> screen);
>>              screen->refcount = 1;
>>              pipe_mutex_unlock(nouveau_screen_mutex);
>>              return &screen->base;
>>     --
>>     2.1.4

More information about the mesa-dev mailing list