ebf376
From 396216f71abf6907efd1383ca0d1a597918cd83d Mon Sep 17 00:00:00 2001
ebf376
From: Ondrej Holy <oholy@redhat.com>
ebf376
Date: Thu, 11 Oct 2018 17:47:59 +0200
ebf376
Subject: [PATCH] daemon: Prevent spawning new daemons if outgoing operation
ebf376
 exists
ebf376
ebf376
A new daemon is always spawned if MountLocation method (or LookupMount for
ebf376
automounted) is called and the respective mount isn't registered yet. This
ebf376
is not usually an issue, because the redundant daemons are consequently
ebf376
terminated. However, this is a problem if mount operations hang for some reason.
ebf376
This may happen e.g. with trash backend due to stale NFS mounts. Consequently,
ebf376
new and new daemons are spawned which may lead to system failures due to lack
ebf376
of system resources. See the following downstream bug report:
ebf376
https://bugzilla.redhat.com/show_bug.cgi?id=1632960
ebf376
ebf376
Let's fix that behavior simply by preventing spawning of new daemons if
ebf376
respective outgoing mount operations exist.
ebf376
ebf376
https://gitlab.gnome.org/GNOME/gvfs/merge_requests/19
ebf376
---
ebf376
 daemon/mount.c | 26 ++++++++++++++++++++++++++
ebf376
 1 file changed, 26 insertions(+)
ebf376
ebf376
diff --git a/daemon/mount.c b/daemon/mount.c
ebf376
index e242666d..33cae597 100644
ebf376
--- a/daemon/mount.c
ebf376
+++ b/daemon/mount.c
ebf376
@@ -73,6 +73,7 @@ typedef void (*MountCallback) (VfsMountable *mountable,
ebf376
 
ebf376
 static GList *mountables = NULL;
ebf376
 static GList *mounts = NULL;
ebf376
+static GList *ongoing = NULL;
ebf376
 
ebf376
 static gboolean fuse_available;
ebf376
 
ebf376
@@ -253,6 +254,7 @@ typedef struct {
ebf376
   char *obj_path;
ebf376
   gboolean spawned;
ebf376
   GVfsDBusSpawner *spawner;
ebf376
+  GList *pending; /* MountData */
ebf376
 } MountData;
ebf376
 
ebf376
 static void spawn_mount (MountData *data);
ebf376
@@ -264,6 +266,7 @@ mount_data_free (MountData *data)
ebf376
   g_mount_spec_unref (data->mount_spec);
ebf376
   g_free (data->obj_path);
ebf376
   g_clear_object (&data->spawner);
ebf376
+  g_list_free_full (data->pending, (GDestroyNotify) mount_data_free);
ebf376
 
ebf376
   g_free (data);
ebf376
 }
ebf376
@@ -271,7 +274,17 @@ mount_data_free (MountData *data)
ebf376
 static void
ebf376
 mount_finish (MountData *data, GError *error)
ebf376
 {
ebf376
+  GList *l;
ebf376
+
ebf376
+  ongoing = g_list_remove (ongoing, data);
ebf376
+
ebf376
   data->callback (data->mountable, error, data->user_data);
ebf376
+  for (l = data->pending; l != NULL; l = l->next)
ebf376
+    {
ebf376
+      MountData *pending_data = l->data;
ebf376
+      pending_data->callback (pending_data->mountable, error, pending_data->user_data);
ebf376
+    }
ebf376
+
ebf376
   mount_data_free (data);
ebf376
 }
ebf376
 
ebf376
@@ -493,6 +506,7 @@ mountable_mount (VfsMountable *mountable,
ebf376
 		 gpointer user_data)
ebf376
 {
ebf376
   MountData *data;
ebf376
+  GList *l;
ebf376
 
ebf376
   data = g_new0 (MountData, 1);
ebf376
   data->automount = automount;
ebf376
@@ -502,6 +516,18 @@ mountable_mount (VfsMountable *mountable,
ebf376
   data->callback = callback;
ebf376
   data->user_data = user_data;
ebf376
 
ebf376
+  for (l = ongoing; l != NULL; l = l->next)
ebf376
+    {
ebf376
+      MountData *ongoing_data = l->data;
ebf376
+      if (g_mount_spec_equal (ongoing_data->mount_spec, mount_spec))
ebf376
+        {
ebf376
+          ongoing_data->pending = g_list_append (ongoing_data->pending, data);
ebf376
+          return;
ebf376
+        }
ebf376
+    }
ebf376
+
ebf376
+  ongoing = g_list_append (ongoing, data);
ebf376
+
ebf376
   if (mountable->dbus_name == NULL)
ebf376
     spawn_mount (data);
ebf376
   else
ebf376
-- 
ebf376
2.20.1
ebf376