Blob Blame History Raw
From f76757f9dd63407686b24c98e5c2290502bcbb93 Mon Sep 17 00:00:00 2001
From: Hans de Goede <hdegoede@redhat.com>
Date: Tue, 26 Mar 2019 15:10:28 -0400
Subject: [PATCH] ply-device-manager: Fix race causing undesired creation of
 non-gfx devs

On systems with working drm/kms devices we still sometimes see:
"Creating non-graphical devices, since there's no suitable graphics hardware"
in the logs (and actually create non-gfx devices).

This is caused by a race where the create_devices_from_udev timeout handler
runs just after the pivot-root, just at the time when the "udev trigger"
from the real root is done.

This causes create_devices_for_subsystem() to hit the "it's not initialized"
code-path for all drm and fb devices, even though before (from the initrd)
drm-devices where already setup successfully.

One way of solving this would be to stop the timer as soon as we successfully
enumerate the first drm device. But we need the timer to enumerate fb devices
so on machines where some outputs only have a fbdev driver (corner case) this
would break support for those outputs.

Instead this commit moves the found_drm_device and found_fb_device to the
global manager state and sets them from create_devices_for_udev_device().
This way they will be set when we check them from the create_devices_from_udev
timeout handler even if create_devices_for_subsystem skips over the devices
because of the udev trigger race.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
---
 src/libply-splash-core/ply-device-manager.c |  19 +-
 1 files changed, 63 insertions(+), 60 deletions(-)

diff --git a/src/libply-splash-core/ply-device-manager.c b/src/libply-splash-core/ply-device-manager.c
index 3a2db06..b6437c5 100644
--- a/src/libply-splash-core/ply-device-manager.c
+++ b/src/libply-splash-core/ply-device-manager.c
@@ -47,60 +47,63 @@ static bool create_devices_for_terminal_and_renderer_type (ply_device_manager_t
                                                            ply_renderer_type_t   renderer_type);
 struct _ply_device_manager
 {
   ply_device_manager_flags_t  flags;
   ply_event_loop_t           *loop;
   ply_hashtable_t            *terminals;
   ply_hashtable_t            *renderers;
   ply_terminal_t             *local_console_terminal;
   ply_list_t                 *keyboards;
   ply_list_t                 *text_displays;
   ply_list_t                 *pixel_displays;
   struct udev                *udev_context;
   struct udev_queue          *udev_queue;
   int                         udev_queue_fd;
   ply_fd_watch_t             *udev_queue_fd_watch;
   struct udev_monitor        *udev_monitor;
 
   ply_keyboard_added_handler_t         keyboard_added_handler;
   ply_keyboard_removed_handler_t       keyboard_removed_handler;
   ply_pixel_display_added_handler_t    pixel_display_added_handler;
   ply_pixel_display_removed_handler_t  pixel_display_removed_handler;
   ply_text_display_added_handler_t     text_display_added_handler;
   ply_text_display_removed_handler_t   text_display_removed_handler;
   void                                *event_handler_data;
 
   uint32_t                    local_console_managed : 1;
   uint32_t                    local_console_is_text : 1;
   uint32_t                    serial_consoles_detected : 1;
   uint32_t                    renderers_activated : 1;
   uint32_t                    keyboards_activated : 1;
+
+  uint32_t                    found_drm_device : 1;
+  uint32_t                    found_fb_device : 1;
 };
 
 static void
 detach_from_event_loop (ply_device_manager_t *manager)
 {
   assert (manager != NULL);
 
   manager->loop = NULL;
 }
 
 static void
 attach_to_event_loop (ply_device_manager_t *manager,
                       ply_event_loop_t     *loop)
 {
   assert (manager != NULL);
   assert (loop != NULL);
   assert (manager->loop == NULL);
 
   manager->loop = loop;
 
   ply_event_loop_watch_for_exit (loop, (ply_event_loop_exit_handler_t)
                                  detach_from_event_loop,
                                  manager);
 }
 
 static bool
 drm_device_in_use (ply_device_manager_t *manager,
                    const char           *device_path)
 {
   ply_renderer_t *renderer;
@@ -183,60 +186,68 @@ create_devices_for_udev_device (ply_device_manager_t *manager,
         {
           ply_trace ("found DRM device %s", device_path);
           renderer_type = PLY_RENDERER_TYPE_DRM;
         }
       else if (strcmp (subsystem, SUBSYSTEM_FRAME_BUFFER) == 0)
         {
           ply_trace ("found frame buffer device %s", device_path);
           if (!fb_device_has_drm_device (manager, device))
             {
               renderer_type = PLY_RENDERER_TYPE_FRAME_BUFFER;
             }
           else
             {
               ply_trace ("ignoring, since there's a DRM device associated with it");
             }
         }
 
       if (renderer_type != PLY_RENDERER_TYPE_NONE)
         {
           ply_terminal_t *terminal = NULL;
 
           if (!manager->local_console_managed)
             {
               terminal = manager->local_console_terminal;
             }
 
           created = create_devices_for_terminal_and_renderer_type (manager,
                                                                    device_path,
                                                                    terminal,
                                                                    renderer_type);
+
+          if (created)
+            {
+              if (renderer_type == PLY_RENDERER_TYPE_DRM)
+                manager->found_drm_device = 1;
+              if (renderer_type == PLY_RENDERER_TYPE_FRAME_BUFFER)
+                manager->found_fb_device = 1;
+            }
        }
     }
     return created;
 }
 
 static void
 free_displays_for_renderer (ply_device_manager_t *manager,
                             ply_renderer_t       *renderer)
 {
   ply_list_node_t *node;
 
   node = ply_list_get_first_node (manager->pixel_displays);
   while (node != NULL)
     {
       ply_list_node_t *next_node;
       ply_pixel_display_t *display;
       ply_renderer_t *display_renderer;
 
       display = ply_list_node_get_data (node);
       next_node = ply_list_get_next_node (manager->pixel_displays, node);
       display_renderer = ply_pixel_display_get_renderer (display);
 
       if (display_renderer == renderer)
         {
           if (manager->pixel_display_removed_handler != NULL)
             manager->pixel_display_removed_handler (manager->event_handler_data, display);
 
           ply_pixel_display_free (display);
           ply_list_remove_node (manager->pixel_displays, node);
         }
@@ -782,68 +793,66 @@ create_devices_from_terminals (ply_device_manager_t *manager)
   ply_trace ("checking for consoles");
 
   if (manager->flags & PLY_DEVICE_MANAGER_FLAGS_IGNORE_SERIAL_CONSOLES)
     {
       has_serial_consoles = false;
       ply_trace ("ignoring all consoles but default console because explicitly told to.");
     }
   else
     {
       has_serial_consoles = add_consoles_from_file (manager, "/sys/class/tty/console/active");
     }
 
   if (has_serial_consoles)
     {
       ply_trace ("serial consoles detected, managing them with details forced");
       manager->serial_consoles_detected = true;
 
       ply_hashtable_foreach (manager->terminals,
                              (ply_hashtable_foreach_func_t *)
                              create_devices_for_terminal,
                              manager);
       return true;
     }
 
   return false;
 }
 
 static void
 create_devices_from_udev (ply_device_manager_t *manager)
 {
-  bool found_drm_device, found_fb_device;
-
   ply_trace ("Looking for devices from udev");
 
-  found_drm_device = create_devices_for_subsystem (manager, SUBSYSTEM_DRM);
-  found_fb_device = create_devices_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
+  create_devices_for_subsystem (manager, SUBSYSTEM_DRM);
+  create_devices_for_subsystem (manager, SUBSYSTEM_FRAME_BUFFER);
 
-  if (found_drm_device || found_fb_device)
+  if (manager->found_drm_device || manager->found_fb_device)
     return;
 
   ply_trace ("Creating non-graphical devices, since there's no suitable graphics hardware");
   create_devices_for_terminal_and_renderer_type (manager,
                                                  ply_terminal_get_name (manager->local_console_terminal),
                                                  manager->local_console_terminal,
                                                  PLY_RENDERER_TYPE_NONE);
 }
 
 static void
 create_fallback_devices (ply_device_manager_t *manager)
 {
   create_devices_for_terminal_and_renderer_type (manager,
                                                  ply_terminal_get_name (manager->local_console_terminal),
                                                  manager->local_console_terminal,
                                                  PLY_RENDERER_TYPE_AUTO);
 }
 
 static void
 on_udev_queue_changed (ply_device_manager_t *manager)
 {
 
   if (!udev_queue_get_queue_is_empty (manager->udev_queue))
     return;
 
   ply_trace ("udev coldplug complete");
   ply_event_loop_stop_watching_fd (manager->loop, manager->udev_queue_fd_watch);
   manager->udev_queue_fd_watch = NULL;
   udev_queue_unref (manager->udev_queue);
 
-- 
2.20.1