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