[gvfs/wip/oholy/pending-mounts] daemon: Prevent spawning new daemons if mount operation pending



commit 103910f934173e0ec84d608dc96caaccea47d8b4
Author: Ondrej Holy <oholy redhat com>
Date:   Thu Oct 11 17:47:59 2018 +0200

    daemon: Prevent spawning new daemons if mount operation pending
    
    A new daemon is always spawned if MountLocation method (or LookupMount for
    automounted) is called and the respective mount isn't registered yet. This
    is not usually an issue, because the redundant daemons are consequently
    removed. However, this is a problem if mount operations hang for some reason.
    This may happen e.g. with trash backend due to stale NFS mounts. Consequently,
    new and new daemons are spawned which may lead to system failures due to lack
    of system resources. See the following downstream bug report:
    https://bugzilla.redhat.com/show_bug.cgi?id=1632960
    
    Let's fix that behavior simply by preventing spawning of new daemons if
    respective mount operations are already pending.

 daemon/mount.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)
---
diff --git a/daemon/mount.c b/daemon/mount.c
index e242666d..df6bd357 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -73,6 +73,7 @@ typedef void (*MountCallback) (VfsMountable *mountable,
 
 static GList *mountables = NULL;
 static GList *mounts = NULL;
+static GList *pending = NULL;
 
 static gboolean fuse_available;
 
@@ -268,10 +269,58 @@ mount_data_free (MountData *data)
   g_free (data);
 }
 
+static int
+pending_compare (MountData *a, MountData *b)
+{
+  return g_mount_spec_equal (a->mount_spec, b->mount_spec) ? 0 : 1;
+}
+
+static void
+pending_remove (MountData *data, GError *error)
+{
+  GList *l, *next;
+  MountData *pending_data;
+
+  pending = g_list_remove (pending, data);
+
+  l = pending;
+  while (l != NULL)
+    {
+      next = l->next;
+      pending_data = l->data;
+
+      if (g_mount_spec_equal (pending_data->mount_spec, data->mount_spec))
+        {
+          pending_data->callback (pending_data->mountable, error, pending_data->user_data);
+          mount_data_free (pending_data);
+
+          pending = g_list_delete_link (pending, l);
+        }
+
+      l = next;
+    }
+}
+
+static gboolean
+pending_append (MountData *data)
+{
+  gboolean is_pending = FALSE;
+
+  if (g_list_find_custom (pending, data, (GCompareFunc) pending_compare) != NULL)
+    is_pending = TRUE;
+
+  pending = g_list_append (pending, data);
+
+  return is_pending;
+}
+
 static void
 mount_finish (MountData *data, GError *error)
 {
   data->callback (data->mountable, error, data->user_data);
+
+  pending_remove (data, error);
+
   mount_data_free (data);
 }
 
@@ -502,6 +551,9 @@ mountable_mount (VfsMountable *mountable,
   data->callback = callback;
   data->user_data = user_data;
 
+  if (pending_append (data))
+    return;
+
   if (mountable->dbus_name == NULL)
     spawn_mount (data);
   else


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]