summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Fergeau <cfergeau@redhat.com>2015-07-01 18:29:56 +0200
committerChristophe Fergeau <cfergeau@redhat.com>2015-07-03 13:57:18 +0200
commit63e3d144784eefe112de6b4e821664ebef94b0ab (patch)
treedf46de28ee6876621295d53de7ffaf57bd6d3d8d
parentd856d49b370380d56c44b500fb392ff8f10dc229 (diff)
downloadgvfs-63e3d144784eefe112de6b4e821664ebef94b0ab.tar.gz
afc: Cleanup force-unmount idle on finalize
When GvfsBackendAfc is finalized, if we have a pending idle for a force unmount, we need to remove it as by the time it runs, the GvfsBackendAfc it's acting on will no longer be valid. This fixes https://bugzilla.gnome.org/show_bug.cgi?id=751537 which can be reproduced by plugging an iDevice, unmounting it in Nautilus, and quickly unplugging it right after clicking on the eject icon.
-rw-r--r--daemon/gvfsbackendafc.c32
1 files changed, 30 insertions, 2 deletions
diff --git a/daemon/gvfsbackendafc.c b/daemon/gvfsbackendafc.c
index 22bab161..1c041a86 100644
--- a/daemon/gvfsbackendafc.c
+++ b/daemon/gvfsbackendafc.c
@@ -87,6 +87,8 @@ struct _GVfsBackendAfc {
idevice_t dev;
afc_client_t afc_cli; /* for ACCESS_MODE_AFC */
+ guint force_umount_id;
+
/* for ACCESS_MODE_HOUSE_ARREST */
GHashTable *apps; /* hash table of AppInfo */
instproxy_client_t inst;
@@ -353,6 +355,9 @@ force_umount_idle (gpointer user_data)
g_vfs_backend_force_unmount (G_VFS_BACKEND(afc_backend));
+ afc_backend->force_umount_id = 0;
+ g_object_unref (afc_backend);
+
return G_SOURCE_REMOVE;
}
@@ -372,9 +377,20 @@ _idevice_event_cb (const idevice_event_t *event, void *user_data)
g_print ("Shutting down AFC backend for device uuid %s\n", afc_backend->uuid);
- /* idevice_event_unsubscribe() will terminate the thread _idevice_event_cb
+ /* This might happen if the user manages to unplug/replug/unplug the same device
+ * before the idle runs
+ */
+ if (afc_backend->force_umount_id != 0)
+ {
+ g_print ("AFC device with uuid %s is already being removed",
+ afc_backend->uuid);
+ return;
+ }
+
+ /* idevice_event_unsubscribe () will terminate the thread _idevice_event_cb
* is running in, so we need to call back into our main loop */
- g_idle_add(force_umount_idle, afc_backend);
+ afc_backend->force_umount_id = g_idle_add (force_umount_idle,
+ g_object_ref (afc_backend));
}
static gboolean
@@ -759,6 +775,8 @@ g_vfs_backend_afc_unmount (GVfsBackend *backend,
{
GVfsBackendAfc *self;
+ idevice_event_unsubscribe ();
+
/* FIXME: check on G_MOUNT_UNMOUNT_FORCE flag */
self = G_VFS_BACKEND_AFC (backend);
g_vfs_backend_afc_close_connection (self);
@@ -2722,6 +2740,16 @@ g_vfs_backend_afc_finalize (GObject *obj)
self = G_VFS_BACKEND_AFC(obj);
g_vfs_backend_afc_close_connection (self);
+ idevice_event_unsubscribe ();
+ /* After running idevice_event_unsubscribe() we won't get any new event
+ * notifications, but we are also guaranteed that currently running event
+ * callbacks will have completed, so no other thread is going to requeue
+ * an idle after we removed it */
+ if (self->force_umount_id != 0) {
+ g_source_remove(self->force_umount_id);
+ self->force_umount_id = 0;
+ }
+
if (G_OBJECT_CLASS(g_vfs_backend_afc_parent_class)->finalize)
(*G_OBJECT_CLASS(g_vfs_backend_afc_parent_class)->finalize) (obj);
}