summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOndrej Holy <oholy@redhat.com>2018-03-15 11:26:29 +0100
committerOndrej Holy <oholy@redhat.com>2018-03-15 15:02:04 +0100
commit7c27d2b78f27455ee33012e6cbf49af9a98a20e6 (patch)
tree27ef676eda9410cbf2a3739535c4af1ba76c7474
parent22e16dcd0cfd07e36439a946b4520a5825fb744e (diff)
downloadgvfs-7c27d2b78f27455ee33012e6cbf49af9a98a20e6.tar.gz
backend: Fix crashes when "Volume is busy" prompt is shown
Backend crashes in on_show_processes_reply callback if g_vfs_backend_unmount_with_operation async call has been completed over on_update_processes_timeout in the meantime and releases GTask data (i.e. "Volume is busy" prompt is being shown and blocking operations have been finished). This patch simplify the handling. With this patch, the async call is completed only from one place, on_show_processes_reply. If there are no more processes, g_mount_source_abort is called from on_update_processes_timeout only and the reply is handled by on_show_processes_reply consequently. This prevents the crashes. Just a note that client side ensures that on_show_processes_reply is called only once. https://bugzilla.gnome.org/show_bug.cgi?id=794113
-rw-r--r--daemon/gvfsbackend.c53
1 files changed, 18 insertions, 35 deletions
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
index b9096033..a622f6e3 100644
--- a/daemon/gvfsbackend.c
+++ b/daemon/gvfsbackend.c
@@ -832,32 +832,35 @@ typedef struct
{
GMountSource *mount_source;
- gboolean ret;
- gboolean aborted;
- gint choice;
-
const gchar *message;
const gchar *choices[3];
- gboolean completed;
+ gboolean no_more_processes;
guint timeout_id;
} UnmountWithOpData;
static void
-complete_unmount_with_op (GTask *task, gboolean no_more_processes)
+on_show_processes_reply (GMountSource *mount_source,
+ GAsyncResult *res,
+ gpointer user_data)
{
+ GTask *task = G_TASK (user_data);
UnmountWithOpData *data = g_task_get_task_data (task);
+ gboolean ret, aborted;
+ gint choice;
- g_source_remove (data->timeout_id);
+ if (data->timeout_id != 0)
+ g_source_remove (data->timeout_id);
- if (!no_more_processes && !data->ret)
+ ret = g_mount_source_show_processes_finish (mount_source, res, &aborted, &choice);
+ if (!data->no_more_processes && !ret)
{
/* If the "show-processes" signal wasn't handled */
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_BUSY,
_("File system is busy"));
}
- else if (!no_more_processes && (data->aborted || data->choice == 1))
+ else if (!data->no_more_processes && (aborted || choice == 1))
{
g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED_HANDLED,
"GMountOperation aborted");
@@ -867,30 +870,9 @@ complete_unmount_with_op (GTask *task, gboolean no_more_processes)
g_task_return_boolean (task, TRUE);
}
- data->completed = TRUE;
g_object_unref (task);
}
-static void
-on_show_processes_reply (GMountSource *mount_source,
- GAsyncResult *res,
- gpointer user_data)
-{
- GTask *task = G_TASK (user_data);
- UnmountWithOpData *data = g_task_get_task_data (task);
-
- /* Do nothing if we've handled this already */
- if (data->completed)
- return;
-
- data->ret = g_mount_source_show_processes_finish (mount_source,
- res,
- &data->aborted,
- &data->choice);
-
- complete_unmount_with_op (task, FALSE);
-}
-
static gboolean
on_update_processes_timeout (gpointer user_data)
{
@@ -902,9 +884,11 @@ on_update_processes_timeout (gpointer user_data)
if (!g_vfs_daemon_has_blocking_processes (daemon))
{
- /* no more processes, abort mount op */
g_mount_source_abort (data->mount_source);
- complete_unmount_with_op (task, TRUE);
+ data->timeout_id = 0;
+ data->no_more_processes = TRUE;
+
+ return G_SOURCE_REMOVE;
}
else
{
@@ -916,10 +900,9 @@ on_update_processes_timeout (gpointer user_data)
(GAsyncReadyCallback) on_show_processes_reply,
task);
g_array_unref (processes);
- }
- /* keep timeout around */
- return TRUE;
+ return G_SOURCE_CONTINUE;
+ }
}
static void