[gvfs/gnome-3-20] afc: Limit the number of HouseArrest services we start



commit e5f242f191262e958c73b9a4df4b952bfbfb77f1
Author: Bastien Nocera <hadess hadess net>
Date:   Wed Mar 23 19:34:57 2016 +0100

    afc: Limit the number of HouseArrest services we start
    
    To avoid being unable to navigate within applications because we ran out
    of HouseArrest services, keep track of file operations within each
    application, and disconnect from unused ones when trying to access an
    unconnected one.
    
    The tracking only covers file operations, and not enumerations, and the
    garbage collection algorithm is quite naive, but could easily be
    extended.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=676188

 daemon/gvfsbackendafc.c |  152 ++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 131 insertions(+), 21 deletions(-)
---
diff --git a/daemon/gvfsbackendafc.c b/daemon/gvfsbackendafc.c
index 45ce968..b2285d4 100644
--- a/daemon/gvfsbackendafc.c
+++ b/daemon/gvfsbackendafc.c
@@ -51,6 +51,7 @@ typedef enum {
 typedef struct {
   guint64 fd;
   afc_client_t afc_cli;
+  char *app;
 } FileHandle;
 
 typedef struct {
@@ -58,6 +59,7 @@ typedef struct {
   char *id;
   char *icon_path;
   house_arrest_client_t house_arrest;
+  guint num_users;
   afc_client_t afc_cli;
 } AppInfo;
 
@@ -856,6 +858,100 @@ out:
   return !retry;
 }
 
+static FileHandle *
+g_vfs_backend_file_handle_new (GVfsBackendAfc *self,
+                               const char     *app)
+{
+  AppInfo *info;
+  FileHandle *handle;
+
+  handle = g_new0 (FileHandle, 1);
+
+  if (app == NULL)
+    return handle;
+
+  g_mutex_lock (&self->apps_lock);
+  info = g_hash_table_lookup (self->apps, app);
+  info->num_users++;
+  g_mutex_unlock (&self->apps_lock);
+
+  handle->app = g_strdup (app);
+
+  return handle;
+}
+
+static void
+g_vfs_backend_file_handle_free (GVfsBackendAfc *self,
+                                FileHandle     *fh)
+{
+  AppInfo *info;
+
+  if (fh == NULL)
+    return;
+
+  if (fh->app == NULL)
+    goto out;
+
+  g_mutex_lock (&self->apps_lock);
+  info = g_hash_table_lookup (self->apps, fh->app);
+  g_assert (info->num_users != 0);
+  info->num_users--;
+  g_mutex_unlock (&self->apps_lock);
+
+out:
+  if (self->connected)
+    afc_file_close (fh->afc_cli, fh->fd);
+  g_free (fh->app);
+  g_free (fh);
+}
+
+/* If we succeeded in removing access to at least one
+ * HouseArrest service, return TRUE */
+static gboolean
+g_vfs_backend_gc_house_arrest (GVfsBackendAfc *self,
+                               const char     *app)
+{
+  GList *apps, *l;
+  gboolean ret = FALSE;
+
+  g_mutex_lock (&self->apps_lock);
+
+  apps = g_hash_table_get_values (self->apps);
+  /* XXX: We might want to sort the apps so the
+   * oldest used gets cleaned up first */
+
+  for (l = apps; l != NULL; l = l->next)
+    {
+      AppInfo *info = l->data;
+
+      /* Don't close the same app we're trying to
+       * connect to the service, but return as it's
+       * already setup */
+      if (g_strcmp0 (info->id, app) == 0)
+        {
+          g_debug ("A HouseArrest service for '%s' is already setup\n", app);
+          ret = TRUE;
+          break;
+        }
+
+      if (info->afc_cli == NULL ||
+          info->num_users > 0)
+        continue;
+
+      g_clear_pointer (&info->afc_cli, afc_client_free);
+      g_clear_pointer (&info->house_arrest, house_arrest_client_free);
+
+      g_debug ("Managed to free HouseArrest service from '%s', for '%s'\n",
+               info->id, app);
+      ret = TRUE;
+      break;
+    }
+
+  g_mutex_unlock (&self->apps_lock);
+
+  return ret;
+}
+
 /* If force_afc_mount is TRUE, then we'll try to mount
  * the app if there's one in the path, otherwise, we'll hold on */
 static char *
@@ -898,7 +994,12 @@ g_vfs_backend_parse_house_arrest_path (GVfsBackendAfc *self,
   if (app != NULL &&
       setup_afc)
     {
-      g_vfs_backend_setup_afc_for_app (self, app);
+      if (!g_vfs_backend_setup_afc_for_app (self, app))
+        {
+          g_debug ("Ran out of HouseArrest clients for app '%s', trying again\n", app);
+          g_vfs_backend_gc_house_arrest (self, app);
+          g_vfs_backend_setup_afc_for_app (self, app);
+        }
     }
 
   return app;
@@ -915,13 +1016,13 @@ g_vfs_backend_afc_open_for_read (GVfsBackend *backend,
   char *new_path;
   afc_client_t afc_cli;
   FileHandle *handle;
+  char *app = NULL;
 
   self = G_VFS_BACKEND_AFC(backend);
   g_return_if_fail (self->connected);
 
   if (self->mode == ACCESS_MODE_HOUSE_ARREST)
     {
-      char *app;
       AppInfo *info;
       gboolean is_doc_root;
 
@@ -935,7 +1036,6 @@ g_vfs_backend_afc_open_for_read (GVfsBackend *backend,
         goto not_found_bail;
 
       afc_cli = info->afc_cli;
-      g_free (app);
     }
   else
     {
@@ -947,6 +1047,7 @@ g_vfs_backend_afc_open_for_read (GVfsBackend *backend,
     {
 is_dir_bail:
       g_free (new_path);
+      g_free (app);
       g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
                         G_IO_ERROR_IS_DIRECTORY,
                         _("Can't open directory"));
@@ -957,6 +1058,7 @@ is_dir_bail:
     {
 not_found_bail:
       g_free (new_path);
+      g_free (app);
       g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
                         G_IO_ERROR_NOT_FOUND,
                         _("File doesn't exist"));
@@ -967,13 +1069,16 @@ not_found_bail:
                                                          new_path ? new_path : path, AFC_FOPEN_RDONLY, &fd),
                                           G_VFS_JOB(job))))
     {
+      g_free (app);
       return;
     }
 
-  handle = g_new0 (FileHandle, 1);
+  handle = g_vfs_backend_file_handle_new (self, app);
   handle->fd = fd;
   handle->afc_cli = afc_cli;
 
+  g_free (app);
+
   g_vfs_job_open_for_read_set_handle (job, handle);
   g_vfs_job_open_for_read_set_can_seek (job, TRUE);
   g_vfs_job_succeeded (G_VFS_JOB(job));
@@ -990,7 +1095,7 @@ g_vfs_backend_afc_create (GVfsBackend *backend,
 {
   uint64_t fd = 0;
   GVfsBackendAfc *self;
-  char *new_path, *app;
+  char *new_path, *app = NULL;
   afc_client_t afc_cli;
   FileHandle *fh;
 
@@ -1012,11 +1117,11 @@ g_vfs_backend_afc_create (GVfsBackend *backend,
       info = g_hash_table_lookup (self->apps, app);
       if (info == NULL)
         {
+          g_free (app);
           g_vfs_backend_afc_check (AFC_E_OBJECT_NOT_FOUND, G_VFS_JOB(job));
           return;
         }
       afc_cli = info->afc_cli;
-      g_free (app);
     }
   else
     {
@@ -1029,15 +1134,18 @@ g_vfs_backend_afc_create (GVfsBackend *backend,
                                           G_VFS_JOB(job))))
     {
       g_free (new_path);
+      g_free (app);
       return;
     }
 
   g_free (new_path);
 
-  fh = g_new0 (FileHandle, 1);
+  fh = g_vfs_backend_file_handle_new (self, app);
   fh->fd = fd;
   fh->afc_cli = afc_cli;
 
+  g_free (app);
+
   g_vfs_job_open_for_write_set_handle (job, fh);
   g_vfs_job_open_for_write_set_can_seek (job, TRUE);
   g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
@@ -1056,7 +1164,7 @@ g_vfs_backend_afc_append_to (GVfsBackend *backend,
   uint64_t fd = 0;
   uint64_t off = 0;
   GVfsBackendAfc *self;
-  char *new_path, *app;
+  char *new_path, *app = NULL;
   afc_client_t afc_cli;
   FileHandle *fh;
 
@@ -1078,11 +1186,11 @@ g_vfs_backend_afc_append_to (GVfsBackend *backend,
       info = g_hash_table_lookup (self->apps, app);
       if (info == NULL)
         {
+          g_free (app);
           g_vfs_backend_afc_check (AFC_E_OBJECT_NOT_FOUND, G_VFS_JOB(job));
           return;
         }
       afc_cli = info->afc_cli;
-      g_free (app);
     }
   else
     {
@@ -1095,6 +1203,7 @@ g_vfs_backend_afc_append_to (GVfsBackend *backend,
                                           G_VFS_JOB(job))))
     {
       g_free (new_path);
+      g_free (app);
       return;
     }
 
@@ -1105,6 +1214,7 @@ g_vfs_backend_afc_append_to (GVfsBackend *backend,
                                           G_VFS_JOB(job))))
     {
       afc_file_close (afc_cli, fd);
+      g_free (app);
       return;
     }
 
@@ -1113,13 +1223,16 @@ g_vfs_backend_afc_append_to (GVfsBackend *backend,
                                           G_VFS_JOB(job))))
     {
       afc_file_close (afc_cli, fd);
+      g_free (app);
       return;
     }
 
-  fh = g_new0 (FileHandle, 1);
+  fh = g_vfs_backend_file_handle_new (self, app);
   fh->fd = fd;
   fh->afc_cli = afc_cli;
 
+  g_free (app);
+
   g_vfs_job_open_for_write_set_handle (job, fh);
   g_vfs_job_open_for_write_set_can_seek (job, TRUE);
   g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
@@ -1139,7 +1252,7 @@ g_vfs_backend_afc_replace (GVfsBackend *backend,
 {
   uint64_t fd = 0;
   GVfsBackendAfc *self;
-  char *new_path, *app;
+  char *new_path, *app = NULL;
   afc_client_t afc_cli;
   FileHandle *fh;
 
@@ -1171,11 +1284,11 @@ g_vfs_backend_afc_replace (GVfsBackend *backend,
       info = g_hash_table_lookup (self->apps, app);
       if (info == NULL)
         {
+          g_free (app);
           g_vfs_backend_afc_check (AFC_E_OBJECT_NOT_FOUND, G_VFS_JOB(job));
           return;
         }
       afc_cli = info->afc_cli;
-      g_free (app);
     }
   else
     {
@@ -1188,15 +1301,18 @@ g_vfs_backend_afc_replace (GVfsBackend *backend,
                                           G_VFS_JOB(job))))
     {
       g_free (new_path);
+      g_free (app);
       return;
     }
 
   g_free (new_path);
 
-  fh = g_new0 (FileHandle, 1);
+  fh = g_vfs_backend_file_handle_new (self, app);
   fh->fd = fd;
   fh->afc_cli = afc_cli;
 
+  g_free (app);
+
   g_vfs_job_open_for_write_set_handle (job, fh);
   g_vfs_job_open_for_write_set_can_seek (job, TRUE);
   g_vfs_job_open_for_write_set_can_truncate (job, TRUE);
@@ -1218,10 +1334,7 @@ g_vfs_backend_afc_close_read (GVfsBackend *backend,
 
   self = G_VFS_BACKEND_AFC(backend);
 
-  if (self->connected)
-    afc_file_close (fh->afc_cli, fh->fd);
-
-  g_free (fh);
+  g_vfs_backend_file_handle_free (self, fh);
 
   g_vfs_job_succeeded (G_VFS_JOB(job));
 }
@@ -1238,10 +1351,7 @@ g_vfs_backend_afc_close_write (GVfsBackend *backend,
 
   self = G_VFS_BACKEND_AFC(backend);
 
-  if (self->connected)
-    afc_file_close(fh->afc_cli, fh->fd);
-
-  g_free (fh);
+  g_vfs_backend_file_handle_free (self, fh);
 
   g_vfs_job_succeeded (G_VFS_JOB(job));
 }


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