neil / rpms / udisks2

Forked from rpms/udisks2 a year ago
Clone
049be7
From 8d5c90a1f4bbe548a1ae361f8d69970669d6e72e Mon Sep 17 00:00:00 2001
049be7
From: Tomas Bzatek <tbzatek@redhat.com>
049be7
Date: Fri, 13 Nov 2020 16:52:11 +0100
049be7
Subject: [PATCH 1/2] udisksdaemonutil: Refactor
049be7
 udisks_daemon_util_trigger_uevent() out of UDisksLinuxBlockObject
049be7
049be7
This decouples uevent triggering from UDisksLinuxBlockObject as sometimes
049be7
we don't have a block object yet or it's outdated.
049be7
---
049be7
 doc/udisks2-sections.txt.daemon.sections.in |   2 +
049be7
 src/udisksdaemonutil.c                      | 230 ++++++++++++++++++++
049be7
 src/udisksdaemonutil.h                      |   7 +
049be7
 src/udiskslinuxblockobject.c                | 180 ++-------------
049be7
 4 files changed, 253 insertions(+), 166 deletions(-)
049be7
049be7
diff --git a/doc/udisks2-sections.txt.daemon.sections.in b/doc/udisks2-sections.txt.daemon.sections.in
049be7
index 26c3c2cd..3030fa95 100644
049be7
--- a/doc/udisks2-sections.txt.daemon.sections.in
049be7
+++ b/doc/udisks2-sections.txt.daemon.sections.in
049be7
@@ -307,6 +307,8 @@ udisks_daemon_util_file_set_contents
049be7
 udisks_daemon_util_on_user_seat
049be7
 udisks_daemon_util_get_free_mdraid_device
049be7
 udisks_ata_identify_get_word
049be7
+udisks_daemon_util_trigger_uevent
049be7
+udisks_daemon_util_trigger_uevent_sync
049be7
 </SECTION>
049be7
 
049be7
 <SECTION>
049be7
diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c
049be7
index 75b877a0..d16c0766 100644
049be7
--- a/src/udisksdaemonutil.c
049be7
+++ b/src/udisksdaemonutil.c
049be7
@@ -34,10 +34,14 @@
049be7
 #include <limits.h>
049be7
 #include <stdlib.h>
049be7
 
049be7
+#include <blockdev/blockdev.h>
049be7
+
049be7
 #include "udisksdaemon.h"
049be7
 #include "udisksdaemonutil.h"
049be7
 #include "udisksstate.h"
049be7
 #include "udiskslogging.h"
049be7
+#include "udiskslinuxdevice.h"
049be7
+#include "udiskslinuxprovider.h"
049be7
 #include "udiskslinuxblockobject.h"
049be7
 #include "udiskslinuxdriveobject.h"
049be7
 
049be7
@@ -1626,3 +1630,229 @@ udisks_ata_identify_get_word (const guchar *identify_data, guint word_number)
049be7
  out:
049be7
   return ret;
049be7
 }
049be7
+
049be7
+
049be7
+/* ---------------------------------------------------------------------------------------------------- */
049be7
+
049be7
+static volatile guint uevent_serial = 0;
049be7
+
049be7
+static gboolean
049be7
+trigger_uevent (const gchar *path, const gchar *str)
049be7
+{
049be7
+  gint fd;
049be7
+
049be7
+  fd = open (path, O_WRONLY);
049be7
+  if (fd < 0)
049be7
+    {
049be7
+      udisks_warning ("Error opening %s while triggering uevent: %m", path);
049be7
+      return FALSE;
049be7
+    }
049be7
+
049be7
+  if (write (fd, str, strlen (str)) != (ssize_t) strlen (str))
049be7
+    {
049be7
+      udisks_warning ("Error writing '%s' to file %s: %m", str, path);
049be7
+      close (fd);
049be7
+      return FALSE;
049be7
+    }
049be7
+
049be7
+  close (fd);
049be7
+  return TRUE;
049be7
+}
049be7
+
049be7
+typedef struct
049be7
+{
049be7
+  UDisksDaemon *daemon;
049be7
+  GMainLoop *main_loop;
049be7
+  guint serial;
049be7
+  gchar *uevent_path;
049be7
+  gboolean success;
049be7
+} SynthUeventData;
049be7
+
049be7
+static gboolean
049be7
+trigger_uevent_idle_cb (gpointer user_data)
049be7
+{
049be7
+  SynthUeventData *data = user_data;
049be7
+  gchar *str;
049be7
+
049be7
+  str = g_strdup_printf ("change %s UDISKSSERIAL=%u", udisks_daemon_get_uuid (data->daemon), data->serial);
049be7
+
049be7
+  if (! trigger_uevent (data->uevent_path, str))
049be7
+    {
049be7
+      /* kernel refused our string, try simple "change" but don't wait for it */
049be7
+      trigger_uevent (data->uevent_path, "change");
049be7
+      data->success = FALSE;
049be7
+      g_main_loop_quit (data->main_loop);
049be7
+    }
049be7
+  g_free (str);
049be7
+
049be7
+  /* remove the source */
049be7
+  return FALSE;
049be7
+}
049be7
+
049be7
+static gboolean
049be7
+uevent_wait_timeout_cb (gpointer user_data)
049be7
+{
049be7
+  SynthUeventData *data = user_data;
049be7
+
049be7
+  data->success = FALSE;
049be7
+  g_main_loop_quit (data->main_loop);
049be7
+
049be7
+  /* remove the source */
049be7
+  return FALSE;
049be7
+}
049be7
+
049be7
+static void
049be7
+uevent_probed_cb (UDisksLinuxProvider *provider,
049be7
+                  const gchar         *action,
049be7
+                  UDisksLinuxDevice   *device,
049be7
+                  gpointer             user_data)
049be7
+{
049be7
+  SynthUeventData *data = user_data;
049be7
+  const gchar *received_serial_str;
049be7
+  gint64 received_serial;
049be7
+  gchar *endptr;
049be7
+
049be7
+  received_serial_str = g_udev_device_get_property (device->udev_device, "SYNTH_ARG_UDISKSSERIAL");
049be7
+  if (received_serial_str != NULL)
049be7
+    {
049be7
+      endptr = (gchar *) received_serial_str;
049be7
+      received_serial = g_ascii_strtoll (received_serial_str, &endptr, 0);
049be7
+      if (endptr != received_serial_str && received_serial == data->serial)
049be7
+        {
049be7
+          data->success = TRUE;
049be7
+          g_main_loop_quit (data->main_loop);
049be7
+        }
049be7
+    }
049be7
+}
049be7
+
049be7
+/**
049be7
+ * udisks_daemon_util_trigger_uevent:
049be7
+ * @daemon: A #UDisksDaemon.
049be7
+ * @device_path: Block device path.
049be7
+ *
049be7
+ * Triggers a 'change' uevent in the kernel.
049be7
+ *
049be7
+ * The triggered event will bubble up from the kernel through the udev
049be7
+ * stack and will eventually be received by the udisks daemon process
049be7
+ * itself. This method does not wait for the event to be received.
049be7
+ */
049be7
+void
049be7
+udisks_daemon_util_trigger_uevent (UDisksDaemon *daemon,
049be7
+                                   const gchar  *device_path)
049be7
+{
049be7
+  GUdevClient *gudev_client;
049be7
+  GUdevDevice *gudev_device;
049be7
+  gchar *path;
049be7
+
049be7
+  g_return_if_fail (UDISKS_IS_DAEMON (daemon));
049be7
+  g_return_if_fail (device_path != NULL);
049be7
+
049be7
+  gudev_client = udisks_linux_provider_get_udev_client (udisks_daemon_get_linux_provider (daemon));
049be7
+  gudev_device = g_udev_client_query_by_device_file (gudev_client, device_path);
049be7
+  if (gudev_device == NULL)
049be7
+    {
049be7
+      udisks_critical ("Device %s not found in udev database, skipping uevent trigger", device_path);
049be7
+      return;
049be7
+    }
049be7
+
049be7
+  path = g_build_filename (g_udev_device_get_sysfs_path (gudev_device), "uevent", NULL);
049be7
+  trigger_uevent (path, "change");
049be7
+  g_free (path);
049be7
+
049be7
+  g_object_unref (gudev_device);
049be7
+}
049be7
+
049be7
+/**
049be7
+ * udisks_daemon_util_trigger_uevent_sync:
049be7
+ * @daemon: A #UDisksDaemon.
049be7
+ * @device_path: Block device path.
049be7
+ * @timeout_seconds: Maximum time to wait for the uevent (in seconds).
049be7
+ *
049be7
+ * Triggers a 'change' uevent in the kernel and waits until it's received and
049be7
+ * processed by udisks.
049be7
+ *
049be7
+ * Unlike udisks_daemon_util_trigger_uevent() that just triggers
049be7
+ * a synthetic uevent to the kernel, this call will actually block and wait until
049be7
+ * the #UDisksLinuxProvider receives the uevent, performs probing and processes
049be7
+ * the uevent further down the UDisks object stack. Upon returning from this
049be7
+ * function call the caller may assume the event has been fully processed, all
049be7
+ * D-Bus objects are updated and settled. Typically used in busy wait for
049be7
+ * a particular D-Bus interface.
049be7
+ *
049be7
+ * Note that this uses synthetic uevent tagging and only works on linux kernel
049be7
+ * 4.13 and higher. In case an older kernel is detected this acts like the classic
049be7
+ * udisks_daemon_util_trigger_uevent() call and %FALSE is returned.
049be7
+ *
049be7
+ * Returns: %TRUE if the uevent has been successfully received, %FALSE otherwise
049be7
+ * or when the kernel version is too old.
049be7
+ */
049be7
+gboolean
049be7
+udisks_daemon_util_trigger_uevent_sync (UDisksDaemon *daemon,
049be7
+                                        const gchar  *device_path,
049be7
+                                        guint         timeout_seconds)
049be7
+{
049be7
+  UDisksLinuxProvider *provider;
049be7
+  GUdevClient *gudev_client;
049be7
+  GUdevDevice *gudev_device;
049be7
+  SynthUeventData data;
049be7
+  GMainContext *main_context;
049be7
+  GSource *idle_source;
049be7
+  GSource *timeout_source;
049be7
+
049be7
+  g_return_val_if_fail (UDISKS_IS_DAEMON (daemon), FALSE);
049be7
+  g_return_val_if_fail (device_path != NULL, FALSE);
049be7
+
049be7
+  if (bd_utils_check_linux_version (4, 13, 0) < 0)
049be7
+    {
049be7
+      udisks_daemon_util_trigger_uevent (daemon, device_path);
049be7
+      return FALSE;
049be7
+    }
049be7
+
049be7
+  provider = udisks_daemon_get_linux_provider (daemon);
049be7
+  gudev_client = udisks_linux_provider_get_udev_client (provider);
049be7
+  gudev_device = g_udev_client_query_by_device_file (gudev_client, device_path);
049be7
+  if (gudev_device == NULL)
049be7
+    {
049be7
+      udisks_critical ("Device %s not found in udev database, skipping uevent trigger", device_path);
049be7
+      return FALSE;
049be7
+    }
049be7
+
049be7
+  data.daemon = daemon;
049be7
+  data.uevent_path = g_build_filename (g_udev_device_get_sysfs_path (gudev_device), "uevent", NULL);
049be7
+  data.serial = g_atomic_int_add (&uevent_serial, 1);
049be7
+
049be7
+  main_context = g_main_context_new ();
049be7
+  g_main_context_push_thread_default (main_context);
049be7
+  data.main_loop = g_main_loop_new (main_context, FALSE);
049be7
+
049be7
+  /* queue the actual trigger in the loop */
049be7
+  idle_source = g_idle_source_new ();
049be7
+  g_source_set_callback (idle_source, (GSourceFunc) trigger_uevent_idle_cb, &data, NULL);
049be7
+  g_source_attach (idle_source, main_context);
049be7
+  g_source_unref (idle_source);
049be7
+
049be7
+  /* add timeout as a fallback */
049be7
+  timeout_source = g_timeout_source_new_seconds (timeout_seconds);
049be7
+  g_source_set_callback (timeout_source, (GSourceFunc) uevent_wait_timeout_cb, &data, NULL);
049be7
+  g_source_attach (timeout_source, main_context);
049be7
+  g_source_unref (timeout_source);
049be7
+
049be7
+  /* catch incoming uevents */
049be7
+  g_signal_connect (provider, "uevent-probed", G_CALLBACK (uevent_probed_cb), &data);
049be7
+
049be7
+  data.success = FALSE;
049be7
+  g_main_loop_run (data.main_loop);
049be7
+
049be7
+  g_signal_handlers_disconnect_by_func (provider, uevent_probed_cb, &data);
049be7
+  g_main_context_pop_thread_default (main_context);
049be7
+
049be7
+  g_main_loop_unref (data.main_loop);
049be7
+  g_main_context_unref (main_context);
049be7
+
049be7
+  g_free (data.uevent_path);
049be7
+  g_object_unref (gudev_device);
049be7
+
049be7
+  return data.success;
049be7
+}
049be7
+
049be7
+/* ---------------------------------------------------------------------------------------------------- */
049be7
diff --git a/src/udisksdaemonutil.h b/src/udisksdaemonutil.h
049be7
index 4fe36214..2edf2122 100644
049be7
--- a/src/udisksdaemonutil.h
049be7
+++ b/src/udisksdaemonutil.h
049be7
@@ -51,6 +51,13 @@ guint64 udisks_daemon_util_block_get_size (GUdevDevice *device,
049be7
                                            gboolean    *out_media_available,
049be7
                                            gboolean    *out_media_change_detected);
049be7
 
049be7
+void udisks_daemon_util_trigger_uevent (UDisksDaemon *daemon,
049be7
+                                        const gchar  *device_path);
049be7
+
049be7
+gboolean udisks_daemon_util_trigger_uevent_sync (UDisksDaemon *daemon,
049be7
+                                                 const gchar  *device_path,
049be7
+                                                 guint         timeout_seconds);
049be7
+
049be7
 gchar *udisks_daemon_util_resolve_link (const gchar *path,
049be7
                                         const gchar *name);
049be7
 
049be7
diff --git a/src/udiskslinuxblockobject.c b/src/udiskslinuxblockobject.c
049be7
index 42ab17d7..5a68c84b 100644
049be7
--- a/src/udiskslinuxblockobject.c
049be7
+++ b/src/udiskslinuxblockobject.c
049be7
@@ -38,8 +38,6 @@
049be7
 #include <stdlib.h>
049be7
 #include <glib/gstdio.h>
049be7
 
049be7
-#include <blockdev/blockdev.h>
049be7
-
049be7
 #include "udiskslogging.h"
049be7
 #include "udisksdaemon.h"
049be7
 #include "udisksdaemonutil.h"
049be7
@@ -959,122 +957,24 @@ on_mount_monitor_mount_removed (UDisksMountMonitor  *monitor,
049be7
 
049be7
 /* ---------------------------------------------------------------------------------------------------- */
049be7
 
049be7
-static volatile guint uevent_serial = 0;
049be7
-
049be7
-static gboolean
049be7
-trigger_uevent (const gchar *path, const gchar *str)
049be7
-{
049be7
-  gint fd;
049be7
-
049be7
-  fd = open (path, O_WRONLY);
049be7
-  if (fd < 0)
049be7
-    {
049be7
-      udisks_warning ("Error opening %s while triggering uevent: %m", path);
049be7
-      return FALSE;
049be7
-    }
049be7
-
049be7
-  if (write (fd, str, strlen (str)) != (ssize_t) strlen (str))
049be7
-    {
049be7
-      udisks_warning ("Error writing '%s' to file %s: %m", str, path);
049be7
-      close (fd);
049be7
-      return FALSE;
049be7
-    }
049be7
-
049be7
-  close (fd);
049be7
-  return TRUE;
049be7
-}
049be7
-
049be7
-typedef struct
049be7
-{
049be7
-  UDisksLinuxBlockObject *object;
049be7
-  GMainLoop *main_loop;
049be7
-  guint serial;
049be7
-  gchar *uevent_path;
049be7
-  gboolean success;
049be7
-} SynthUeventData;
049be7
-
049be7
-static gboolean
049be7
-trigger_uevent_idle_cb (gpointer user_data)
049be7
-{
049be7
-  SynthUeventData *data = user_data;
049be7
-  gchar *str;
049be7
-
049be7
-  str = g_strdup_printf ("change %s UDISKSSERIAL=%u", udisks_daemon_get_uuid (data->object->daemon), data->serial);
049be7
-
049be7
-  if (! trigger_uevent (data->uevent_path, str))
049be7
-    {
049be7
-      /* kernel refused our string, try simple "change" but don't wait for it */
049be7
-      trigger_uevent (data->uevent_path, "change");
049be7
-      data->success = FALSE;
049be7
-      g_main_loop_quit (data->main_loop);
049be7
-    }
049be7
-  g_free (str);
049be7
-
049be7
-  /* remove the source */
049be7
-  return FALSE;
049be7
-}
049be7
-
049be7
-static gboolean
049be7
-uevent_wait_timeout_cb (gpointer user_data)
049be7
-{
049be7
-  SynthUeventData *data = user_data;
049be7
-
049be7
-  data->success = FALSE;
049be7
-  g_main_loop_quit (data->main_loop);
049be7
-
049be7
-  /* remove the source */
049be7
-  return FALSE;
049be7
-}
049be7
-
049be7
-static void
049be7
-uevent_probed_cb (UDisksLinuxProvider *provider,
049be7
-                  const gchar         *action,
049be7
-                  UDisksLinuxDevice   *device,
049be7
-                  gpointer             user_data)
049be7
-{
049be7
-  SynthUeventData *data = user_data;
049be7
-  const gchar *received_serial_str;
049be7
-  gint64 received_serial;
049be7
-  gchar *endptr;
049be7
-
049be7
-  received_serial_str = g_udev_device_get_property (device->udev_device, "SYNTH_ARG_UDISKSSERIAL");
049be7
-  if (received_serial_str != NULL)
049be7
-    {
049be7
-      endptr = (gchar *) received_serial_str;
049be7
-      received_serial = g_ascii_strtoll (received_serial_str, &endptr, 0);
049be7
-      if (endptr != received_serial_str && received_serial == data->serial)
049be7
-        {
049be7
-          data->success = TRUE;
049be7
-          g_main_loop_quit (data->main_loop);
049be7
-        }
049be7
-    }
049be7
-}
049be7
-
049be7
 /**
049be7
  * udisks_linux_block_object_trigger_uevent:
049be7
  * @object: A #UDisksLinuxBlockObject.
049be7
  *
049be7
  * Triggers a 'change' uevent in the kernel.
049be7
  *
049be7
- * The triggered event will bubble up from the kernel through the udev
049be7
- * stack and will eventually be received by the udisks daemon process
049be7
- * itself. This method does not wait for the event to be received.
049be7
+ * Refer to udisks_daemon_util_trigger_uevent() for detailed description.
049be7
  */
049be7
 void
049be7
 udisks_linux_block_object_trigger_uevent (UDisksLinuxBlockObject *object)
049be7
 {
049be7
-  UDisksLinuxDevice *device;
049be7
-  gchar *path;
049be7
+  gchar *device_file;
049be7
 
049be7
   g_return_if_fail (UDISKS_IS_LINUX_BLOCK_OBJECT (object));
049be7
 
049be7
-  device = udisks_linux_block_object_get_device (object);
049be7
-  path = g_strconcat (g_udev_device_get_sysfs_path (device->udev_device), "/uevent", NULL);
049be7
-
049be7
-  trigger_uevent (path, "change");
049be7
-
049be7
-  g_free (path);
049be7
-  g_object_unref (device);
049be7
+  device_file = udisks_linux_block_object_get_device_file (object);
049be7
+  udisks_daemon_util_trigger_uevent (object->daemon, device_file);
049be7
+  g_free (device_file);
049be7
 }
049be7
 
049be7
 /**
049be7
@@ -1083,19 +983,10 @@ udisks_linux_block_object_trigger_uevent (UDisksLinuxBlockObject *object)
049be7
  * @timeout_seconds: Maximum time to wait for the uevent (in seconds).
049be7
  *
049be7
  * Triggers a 'change' uevent in the kernel and waits until it's received and
049be7
- * processed by udisks.
049be7
- *
049be7
- * Unlike udisks_linux_block_object_trigger_uevent() that just triggers
049be7
- * a synthetic uevent to the kernel, this call will actually block and wait until
049be7
- * the #UDisksLinuxProvider receives the uevent, performs probing and processes
049be7
- * the uevent further down the UDisks object stack. Upon returning from this
049be7
- * function call the caller may assume the event has been fully processed, all
049be7
- * D-Bus objects are updated and settled. Typically used in busy wait for
049be7
- * a particular D-Bus interface.
049be7
+ * processed through the uevent queue.
049be7
  *
049be7
- * Note that this uses synthetic uevent tagging and only works on linux kernel
049be7
- * 4.13 and higher. In case an older kernel is detected this acts like the classic
049be7
- * udisks_linux_block_object_trigger_uevent() call and %FALSE is returned.
049be7
+ * This is a convenient wrapper around udisks_daemon_util_trigger_uevent_sync().
049be7
+ * Refer to this function for detailed documentation.
049be7
  *
049be7
  * Returns: %TRUE if the uevent has been successfully received, %FALSE otherwise
049be7
  * or when the kernel version is too old.
049be7
@@ -1104,59 +995,16 @@ gboolean
049be7
 udisks_linux_block_object_trigger_uevent_sync (UDisksLinuxBlockObject *object,
049be7
                                                guint                   timeout_seconds)
049be7
 {
049be7
-  UDisksLinuxDevice *device;
049be7
-  UDisksLinuxProvider *provider;
049be7
-  SynthUeventData data;
049be7
-  GMainContext *main_context;
049be7
-  GSource *idle_source;
049be7
-  GSource *timeout_source;
049be7
+  gchar *device_file;
049be7
+  gboolean ret;
049be7
 
049be7
   g_return_val_if_fail (UDISKS_IS_LINUX_BLOCK_OBJECT (object), FALSE);
049be7
 
049be7
-  if (bd_utils_check_linux_version (4, 13, 0) < 0)
049be7
-    {
049be7
-      udisks_linux_block_object_trigger_uevent (object);
049be7
-      return FALSE;
049be7
-    }
049be7
-
049be7
-  data.object = object;
049be7
-  device = udisks_linux_block_object_get_device (object);
049be7
-  data.uevent_path = g_strconcat (g_udev_device_get_sysfs_path (device->udev_device), "/uevent", NULL);
049be7
-  data.serial = g_atomic_int_add (&uevent_serial, 1);
049be7
-
049be7
-  main_context = g_main_context_new ();
049be7
-  g_main_context_push_thread_default (main_context);
049be7
-  data.main_loop = g_main_loop_new (main_context, FALSE);
049be7
-
049be7
-  /* queue the actual trigger in the loop */
049be7
-  idle_source = g_idle_source_new ();
049be7
-  g_source_set_callback (idle_source, (GSourceFunc) trigger_uevent_idle_cb, &data, NULL);
049be7
-  g_source_attach (idle_source, main_context);
049be7
-  g_source_unref (idle_source);
049be7
+  device_file = udisks_linux_block_object_get_device_file (object);
049be7
+  ret = udisks_daemon_util_trigger_uevent_sync (object->daemon, device_file, timeout_seconds);
049be7
+  g_free (device_file);
049be7
 
049be7
-  /* add timeout as a fallback */
049be7
-  timeout_source = g_timeout_source_new_seconds (timeout_seconds);
049be7
-  g_source_set_callback (timeout_source, (GSourceFunc) uevent_wait_timeout_cb, &data, NULL);
049be7
-  g_source_attach (timeout_source, main_context);
049be7
-  g_source_unref (timeout_source);
049be7
-
049be7
-  /* catch incoming uevents */
049be7
-  provider = udisks_daemon_get_linux_provider (object->daemon);
049be7
-  g_signal_connect (provider, "uevent-probed", G_CALLBACK (uevent_probed_cb), &data);
049be7
-
049be7
-  data.success = FALSE;
049be7
-  g_main_loop_run (data.main_loop);
049be7
-
049be7
-  g_signal_handlers_disconnect_by_func (provider, uevent_probed_cb, &data);
049be7
-  g_main_context_pop_thread_default (main_context);
049be7
-
049be7
-  g_main_loop_unref (data.main_loop);
049be7
-  g_main_context_unref (main_context);
049be7
-
049be7
-  g_free (data.uevent_path);
049be7
-  g_object_unref (device);
049be7
-
049be7
-  return data.success;
049be7
+  return ret;
049be7
 }
049be7
 
049be7
 /* ---------------------------------------------------------------------------------------------------- */
049be7
-- 
049be7
2.26.2
049be7