diff options
author | Christophe Fergeau <cfergeau@redhat.com> | 2015-07-01 18:29:56 +0200 |
---|---|---|
committer | Christophe Fergeau <cfergeau@redhat.com> | 2015-07-03 13:59:48 +0200 |
commit | 5740ee6860342c37b4967d529271d0851400567f (patch) | |
tree | 26e05fa0fd19401c120b9d413cc2493ac301c7b1 | |
parent | 6bfecb830c98f7398a748c311fc97e986f97c668 (diff) | |
download | gvfs-5740ee6860342c37b4967d529271d0851400567f.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.c | 32 |
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); } |