Blob Blame History Raw
From 396216f71abf6907efd1383ca0d1a597918cd83d Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 11 Oct 2018 17:47:59 +0200
Subject: [PATCH] daemon: Prevent spawning new daemons if outgoing operation
 exists

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
terminated. 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 outgoing mount operations exist.

https://gitlab.gnome.org/GNOME/gvfs/merge_requests/19
---
 daemon/mount.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/daemon/mount.c b/daemon/mount.c
index e242666d..33cae597 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 *ongoing = NULL;
 
 static gboolean fuse_available;
 
@@ -253,6 +254,7 @@ typedef struct {
   char *obj_path;
   gboolean spawned;
   GVfsDBusSpawner *spawner;
+  GList *pending; /* MountData */
 } MountData;
 
 static void spawn_mount (MountData *data);
@@ -264,6 +266,7 @@ mount_data_free (MountData *data)
   g_mount_spec_unref (data->mount_spec);
   g_free (data->obj_path);
   g_clear_object (&data->spawner);
+  g_list_free_full (data->pending, (GDestroyNotify) mount_data_free);
 
   g_free (data);
 }
@@ -271,7 +274,17 @@ mount_data_free (MountData *data)
 static void
 mount_finish (MountData *data, GError *error)
 {
+  GList *l;
+
+  ongoing = g_list_remove (ongoing, data);
+
   data->callback (data->mountable, error, data->user_data);
+  for (l = data->pending; l != NULL; l = l->next)
+    {
+      MountData *pending_data = l->data;
+      pending_data->callback (pending_data->mountable, error, pending_data->user_data);
+    }
+
   mount_data_free (data);
 }
 
@@ -493,6 +506,7 @@ mountable_mount (VfsMountable *mountable,
 		 gpointer user_data)
 {
   MountData *data;
+  GList *l;
 
   data = g_new0 (MountData, 1);
   data->automount = automount;
@@ -502,6 +516,18 @@ mountable_mount (VfsMountable *mountable,
   data->callback = callback;
   data->user_data = user_data;
 
+  for (l = ongoing; l != NULL; l = l->next)
+    {
+      MountData *ongoing_data = l->data;
+      if (g_mount_spec_equal (ongoing_data->mount_spec, mount_spec))
+        {
+          ongoing_data->pending = g_list_append (ongoing_data->pending, data);
+          return;
+        }
+    }
+
+  ongoing = g_list_append (ongoing, data);
+
   if (mountable->dbus_name == NULL)
     spawn_mount (data);
   else
-- 
2.20.1