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