Improve trash backend performance
Resolves: RHEL-127445
This commit is contained in:
parent
c64ab34ccb
commit
b57f602cb4
43
backend-Prevent-usage-of-NULL.patch
Normal file
43
backend-Prevent-usage-of-NULL.patch
Normal file
@ -0,0 +1,43 @@
|
||||
From d1ab5870e828df259897598298c2ca66b587426a Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Wed, 29 Aug 2018 15:36:57 +0200
|
||||
Subject: [PATCH] backend: Prevent usage of NULL
|
||||
|
||||
g_dbus_connection_get_peer_credentials may fail in some cases, see
|
||||
the documentation, and thus we have to check the return value before
|
||||
use in order to prevent warnings like the following:
|
||||
|
||||
g_credentials_get_unix_pid: assertion 'G_IS_CREDENTIALS (credentials)' failed
|
||||
|
||||
Print simply -1 if pid can't be obtained this way.
|
||||
---
|
||||
daemon/gvfsbackend.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
|
||||
index 673070fa..4fd3455c 100644
|
||||
--- a/daemon/gvfsbackend.c
|
||||
+++ b/daemon/gvfsbackend.c
|
||||
@@ -609,14 +609,17 @@ g_vfs_backend_invocation_first_handler (GVfsDBusMount *object,
|
||||
{
|
||||
GDBusConnection *connection;
|
||||
GCredentials *credentials;
|
||||
+ pid_t pid = -1;
|
||||
|
||||
connection = g_dbus_method_invocation_get_connection (invocation);
|
||||
credentials = g_dbus_connection_get_peer_credentials (connection);
|
||||
+ if (credentials)
|
||||
+ pid = g_credentials_get_unix_pid (credentials, NULL);
|
||||
|
||||
- g_debug ("backend_dbus_handler %s:%s (pid=%u)\n",
|
||||
+ g_debug ("backend_dbus_handler %s:%s (pid=%ld)\n",
|
||||
g_dbus_method_invocation_get_interface_name (invocation),
|
||||
g_dbus_method_invocation_get_method_name (invocation),
|
||||
- g_credentials_get_unix_pid (credentials, NULL));
|
||||
+ (long)pid);
|
||||
|
||||
if (backend->priv->block_requests)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
47
daemon-Add-process-name-to-debug-handler-log.patch
Normal file
47
daemon-Add-process-name-to-debug-handler-log.patch
Normal file
@ -0,0 +1,47 @@
|
||||
From 9e38c56f99372b2474a780ac0c7c7d9b38e490cf Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Mon, 11 May 2026 17:48:26 +0200
|
||||
Subject: [PATCH] daemon: Add process name to debug handler log
|
||||
|
||||
Made-with: Cursor (Claude)
|
||||
---
|
||||
daemon/gvfsbackend.c | 17 +++++++++++++----
|
||||
1 file changed, 13 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c
|
||||
index fa1389ea..7dfd5300 100644
|
||||
--- a/daemon/gvfsbackend.c
|
||||
+++ b/daemon/gvfsbackend.c
|
||||
@@ -636,16 +636,25 @@ g_vfs_backend_invocation_first_handler (GVfsDBusMount *object,
|
||||
GDBusConnection *connection;
|
||||
GCredentials *credentials;
|
||||
pid_t pid = -1;
|
||||
+ g_autofree gchar *comm = NULL;
|
||||
|
||||
connection = g_dbus_method_invocation_get_connection (invocation);
|
||||
credentials = g_dbus_connection_get_peer_credentials (connection);
|
||||
if (credentials)
|
||||
pid = g_credentials_get_unix_pid (credentials, NULL);
|
||||
|
||||
- g_debug ("backend_dbus_handler %s:%s (pid=%ld)\n",
|
||||
- g_dbus_method_invocation_get_interface_name (invocation),
|
||||
- g_dbus_method_invocation_get_method_name (invocation),
|
||||
- (long)pid);
|
||||
+ if (pid > 0)
|
||||
+ {
|
||||
+ g_autofree gchar *comm_path = g_strdup_printf ("/proc/%ld/comm", (long)pid);
|
||||
+
|
||||
+ if (g_file_get_contents (comm_path, &comm, NULL, NULL))
|
||||
+ g_strstrip (comm);
|
||||
+ }
|
||||
+
|
||||
+ g_debug ("backend_dbus_handler %s:%s (pid=%ld comm=%s)\n",
|
||||
+ g_dbus_method_invocation_get_interface_name (invocation),
|
||||
+ g_dbus_method_invocation_get_method_name (invocation),
|
||||
+ (long)pid, comm ? comm : "");
|
||||
|
||||
if (backend->priv->block_requests)
|
||||
{
|
||||
--
|
||||
2.53.0
|
||||
|
||||
29
gvfs.spec
29
gvfs.spec
@ -25,7 +25,7 @@
|
||||
|
||||
Name: gvfs
|
||||
Version: 1.36.2
|
||||
Release: 20%{?dist}
|
||||
Release: 21%{?dist}
|
||||
Summary: Backends for the gio framework in GLib
|
||||
|
||||
License: GPLv3 and LGPLv2+ and BSD and MPLv2.0
|
||||
@ -99,6 +99,29 @@ Patch28: udisks2-monitor-performance-273.patch
|
||||
Patch29: udisks2-monitor-performance-290.patch
|
||||
Patch30: udisks2-monitor-performance-297.patch
|
||||
|
||||
# Improve trash backend performance
|
||||
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/287
|
||||
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/175
|
||||
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/169
|
||||
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/11
|
||||
Patch31: backend-Prevent-usage-of-NULL.patch
|
||||
Patch32: trash-Add-is_root-function.patch
|
||||
Patch33: trash-Remove-unused-ui_hook-property.patch
|
||||
Patch34: trash-Remove-unused-is_homedir-property.patch
|
||||
Patch35: trash-Do-not-create-monitors-for-non-root-items.patch
|
||||
Patch36: trash-Run-blocking-methods-on-a-thread-pool.patch
|
||||
Patch37: trash-Add-worker-thread.patch
|
||||
Patch38: trash-Chain-up-finalize.patch
|
||||
Patch39: trash-Rate-limit-mount-updates.patch
|
||||
Patch40: trash-Add-debug-prints-for-mounts-handling.patch
|
||||
Patch41: trash-Use-GHashTable-for-mount-tracking.patch
|
||||
Patch42: trash-Use-GHashTable-for-trash-directory-items.patch
|
||||
Patch43: trash-Rate-limit-size-change-notifications.patch
|
||||
Patch44: trash-Use-weak-refs-for-monitor-lifecycle.patch
|
||||
Patch45: trash-Defer-mount-monitoring-to-active-watchers-only.patch
|
||||
Patch46: daemon-Add-process-name-to-debug-handler-log.patch
|
||||
Patch47: trash-Skip-mount-table-reparsing-when-unchanged.patch
|
||||
|
||||
BuildRequires: pkgconfig
|
||||
BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version}
|
||||
BuildRequires: pkgconfig(dbus-glib-1)
|
||||
@ -489,6 +512,10 @@ killall -USR1 gvfsd >&/dev/null || :
|
||||
%{_datadir}/installed-tests
|
||||
|
||||
%changelog
|
||||
* Tue Jun 02 2026 Ondrej Holy <oholy@redhat.com> - 1.36.2-21
|
||||
- Improve trash backend performance
|
||||
Resolves: RHEL-127445
|
||||
|
||||
* Fri Feb 06 2026 Milan Crha <mcrha@redhat.com> - 1.36.2-20
|
||||
- udisks2: Correct add to hash table for items which can clash in the monitor (RHEL-76484)
|
||||
|
||||
|
||||
60
trash-Add-debug-prints-for-mounts-handling.patch
Normal file
60
trash-Add-debug-prints-for-mounts-handling.patch
Normal file
@ -0,0 +1,60 @@
|
||||
From 78cc4e391d4f9e6e17af83e980f9d819b7fd208e Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 15:32:58 +0200
|
||||
Subject: [PATCH] trash: Add debug prints for mounts handling
|
||||
|
||||
Backport of commit e0018263.
|
||||
|
||||
Adapted for older GLib API: `g_unix_mount_entry_get_device_path`/`get_mount_path`/`get_fs_type` replaced with `g_unix_mount_get_device_path`/`g_unix_mount_get_mount_path`/`g_unix_mount_get_fs_type`.
|
||||
---
|
||||
daemon/trashlib/trashwatcher.c | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
|
||||
index fe2ee44..c195234 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -245,12 +245,22 @@ trash_watcher_remount_do (TrashWatcher *watcher)
|
||||
if (result < 0)
|
||||
{
|
||||
/* new entry. add it. */
|
||||
+ g_debug ("trash_watcher_remount_do: insert %s %s %s\n",
|
||||
+ g_unix_mount_get_device_path (new->data),
|
||||
+ g_unix_mount_get_mount_path (new->data),
|
||||
+ g_unix_mount_get_fs_type (new->data));
|
||||
+
|
||||
trash_mount_insert (watcher, &old, new->data);
|
||||
new = new->next;
|
||||
}
|
||||
else if (result > 0)
|
||||
{
|
||||
/* old entry. remove it. */
|
||||
+ g_debug ("trash_watcher_remount_do: remove %s %s %s\n",
|
||||
+ g_unix_mount_get_device_path ((*old)->mount_entry),
|
||||
+ g_unix_mount_get_mount_path ((*old)->mount_entry),
|
||||
+ g_unix_mount_get_fs_type ((*old)->mount_entry));
|
||||
+
|
||||
trash_mount_remove (old);
|
||||
}
|
||||
else
|
||||
@@ -271,6 +281,8 @@ trash_watcher_remount_timeout (gpointer user_data)
|
||||
{
|
||||
TrashWatcher *watcher = user_data;
|
||||
|
||||
+ g_debug ("trash_watcher_remount_timeout\n");
|
||||
+
|
||||
watcher->update_id = 0;
|
||||
|
||||
trash_watcher_remount_do (watcher);
|
||||
@@ -281,6 +293,8 @@ trash_watcher_remount_timeout (gpointer user_data)
|
||||
static void
|
||||
trash_watcher_remount (TrashWatcher *watcher)
|
||||
{
|
||||
+ g_debug ("trash_watcher_remount\n");
|
||||
+
|
||||
if (watcher->update_id != 0)
|
||||
return;
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
94
trash-Add-is_root-function.patch
Normal file
94
trash-Add-is_root-function.patch
Normal file
@ -0,0 +1,94 @@
|
||||
From 86805f19dbcb55a4ad6fa2a00670d00b927c9d47 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Thu, 19 Jan 2023 12:57:30 +0100
|
||||
Subject: [PATCH] trash: Add is_root function
|
||||
|
||||
Let's make the code more readable using the is_root function instead
|
||||
of char comparison.
|
||||
---
|
||||
daemon/gvfsbackendtrash.c | 20 +++++++++++++-------
|
||||
1 file changed, 13 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
|
||||
index 9702b860..d7ec4f77 100644
|
||||
--- a/daemon/gvfsbackendtrash.c
|
||||
+++ b/daemon/gvfsbackendtrash.c
|
||||
@@ -44,6 +44,12 @@ struct OPAQUE_TYPE__GVfsBackendTrash
|
||||
|
||||
G_DEFINE_TYPE (GVfsBackendTrash, g_vfs_backend_trash, G_VFS_TYPE_BACKEND);
|
||||
|
||||
+static gboolean
|
||||
+is_root (const char *filename)
|
||||
+{
|
||||
+ return (filename[0] == '/' && filename[1] == '\0');
|
||||
+}
|
||||
+
|
||||
static GVfsMonitor *
|
||||
trash_backend_get_file_monitor (GVfsBackendTrash *backend,
|
||||
gboolean create)
|
||||
@@ -229,7 +235,7 @@ trash_backend_open_for_read (GVfsBackend *vfs_backend,
|
||||
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
|
||||
GError *error = NULL;
|
||||
|
||||
- if (filename[1] == '\0')
|
||||
+ if (is_root (filename))
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
|
||||
_("Can’t open directory"));
|
||||
|
||||
@@ -397,7 +403,7 @@ trash_backend_delete (GVfsBackend *vfs_backend,
|
||||
GError *error = NULL;
|
||||
g_debug ("before job: %d\n", G_OBJECT(job)->ref_count);
|
||||
|
||||
- if (filename[1] == '\0')
|
||||
+ if (is_root (filename))
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
|
||||
_("The trash folder may not be deleted"));
|
||||
else
|
||||
@@ -456,7 +462,7 @@ trash_backend_pull (GVfsBackend *vfs_backend,
|
||||
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
|
||||
GError *error = NULL;
|
||||
|
||||
- if (source[1] == '\0')
|
||||
+ if (is_root (source))
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
|
||||
_("The trash folder may not be deleted"));
|
||||
else
|
||||
@@ -683,7 +689,7 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
|
||||
|
||||
trash_watcher_rescan (backend->watcher);
|
||||
|
||||
- if (filename[1])
|
||||
+ if (!is_root (filename))
|
||||
trash_backend_enumerate_non_root (backend, job, filename,
|
||||
attribute_matcher, flags);
|
||||
else
|
||||
@@ -729,7 +735,7 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
|
||||
if (!backend->file_monitor && !backend->dir_monitor)
|
||||
trash_watcher_rescan (backend->watcher);
|
||||
|
||||
- if (filename[1])
|
||||
+ if (!is_root (filename))
|
||||
{
|
||||
GError *error = NULL;
|
||||
gboolean is_toplevel;
|
||||
@@ -832,7 +838,7 @@ trash_backend_create_dir_monitor (GVfsBackend *vfs_backend,
|
||||
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
|
||||
GVfsMonitor *monitor;
|
||||
|
||||
- if (filename[1])
|
||||
+ if (!is_root (filename))
|
||||
monitor = g_vfs_monitor_new (vfs_backend);
|
||||
else
|
||||
monitor = trash_backend_get_dir_monitor (backend, TRUE);
|
||||
@@ -853,7 +859,7 @@ trash_backend_create_file_monitor (GVfsBackend *vfs_backend,
|
||||
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
|
||||
GVfsMonitor *monitor;
|
||||
|
||||
- if (filename[1])
|
||||
+ if (!is_root (filename))
|
||||
monitor = g_vfs_monitor_new (vfs_backend);
|
||||
else
|
||||
monitor = trash_backend_get_file_monitor (backend, TRUE);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
295
trash-Add-worker-thread.patch
Normal file
295
trash-Add-worker-thread.patch
Normal file
@ -0,0 +1,295 @@
|
||||
From 890b2a747bbcd9ed220fb217aba41b9ef0188ba1 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Wed, 7 Jun 2023 15:49:41 +0200
|
||||
Subject: [PATCH] trash: Add worker thread
|
||||
|
||||
The previous commit makes the backend a bit more resilience of against
|
||||
stale NFS mounts, but still a lot of I/O operations (e.g.
|
||||
`trash_watcher_rescan`) run on the main thread and can easily block the
|
||||
whole backend. This is especially problem for the `create_dir_monitor` and
|
||||
`create_file_monitor` methods that doesn't have asynchronous variants.
|
||||
This may cause hangs for nautilus, or file chooser dialog, but also for
|
||||
the whole gnome-shell session (resp. desktop-icons extension). Let's add
|
||||
a worker thread to ensure that the `create_dir_monitor` and
|
||||
`create_file_monitor` methods response immediately.
|
||||
|
||||
Related: https://bugzilla.redhat.com/show_bug.cgi?id=2152538
|
||||
---
|
||||
daemon/gvfsbackendtrash.c | 156 ++++++++++++++++++++++++++++++++------
|
||||
1 file changed, 131 insertions(+), 25 deletions(-)
|
||||
|
||||
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
|
||||
index b4d3d089..0966242a 100644
|
||||
--- a/daemon/gvfsbackendtrash.c
|
||||
+++ b/daemon/gvfsbackendtrash.c
|
||||
@@ -36,6 +36,10 @@ struct OPAQUE_TYPE__GVfsBackendTrash
|
||||
GVfsMonitor *file_monitor;
|
||||
GVfsMonitor *dir_monitor;
|
||||
|
||||
+ GMainContext *worker_context;
|
||||
+ GMainLoop *worker_loop;
|
||||
+ GThread *worker_thread;
|
||||
+
|
||||
TrashWatcher *watcher;
|
||||
TrashRoot *root;
|
||||
|
||||
@@ -44,6 +48,94 @@ struct OPAQUE_TYPE__GVfsBackendTrash
|
||||
|
||||
G_DEFINE_TYPE (GVfsBackendTrash, g_vfs_backend_trash, G_VFS_TYPE_BACKEND);
|
||||
|
||||
+typedef struct
|
||||
+{
|
||||
+ GSourceFunc source_func;
|
||||
+ gpointer user_data;
|
||||
+ GMutex mutex;
|
||||
+ GCond cond;
|
||||
+ gboolean completed;
|
||||
+} ContextInvokeData;
|
||||
+
|
||||
+static gboolean
|
||||
+source_func_wrapper (gpointer user_data)
|
||||
+{
|
||||
+ ContextInvokeData *data = user_data;
|
||||
+
|
||||
+ g_mutex_lock (&data->mutex);
|
||||
+
|
||||
+ while (data->source_func (data->user_data));
|
||||
+ data->completed = TRUE;
|
||||
+
|
||||
+ g_cond_signal (&data->cond);
|
||||
+ g_mutex_unlock (&data->mutex);
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+trash_backend_worker_thread_queue_and_wait (GVfsBackendTrash *backend,
|
||||
+ GSourceFunc source_func)
|
||||
+{
|
||||
+ ContextInvokeData data;
|
||||
+
|
||||
+ data.source_func = source_func;
|
||||
+ data.user_data = backend;
|
||||
+
|
||||
+ g_mutex_init (&data.mutex);
|
||||
+ g_cond_init (&data.cond);
|
||||
+ data.completed = FALSE;
|
||||
+
|
||||
+ g_mutex_lock (&data.mutex);
|
||||
+
|
||||
+ g_main_context_invoke (backend->worker_context,
|
||||
+ source_func_wrapper,
|
||||
+ &data);
|
||||
+
|
||||
+ while (!data.completed)
|
||||
+ {
|
||||
+ g_cond_wait (&data.cond, &data.mutex);
|
||||
+ }
|
||||
+
|
||||
+ g_mutex_unlock (&data.mutex);
|
||||
+
|
||||
+ g_mutex_clear (&data.mutex);
|
||||
+ g_cond_clear (&data.cond);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+trash_backend_worker_thread_queue (GVfsBackendTrash *backend,
|
||||
+ GSourceFunc source_func)
|
||||
+{
|
||||
+ g_main_context_invoke (backend->worker_context, source_func, backend);
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+watch_func (gpointer user_data)
|
||||
+{
|
||||
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
|
||||
+
|
||||
+ trash_watcher_watch (backend->watcher);
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+rescan_func (gpointer user_data)
|
||||
+{
|
||||
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
|
||||
+
|
||||
+ trash_watcher_rescan (backend->watcher);
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
+static gboolean
|
||||
+ready_func (gpointer user_data)
|
||||
+{
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
is_root (const char *filename)
|
||||
{
|
||||
@@ -63,7 +155,7 @@ trash_backend_get_file_monitor (GVfsBackendTrash *backend,
|
||||
* no possibility here for creating more than one new monitor.
|
||||
*/
|
||||
if (backend->dir_monitor == NULL)
|
||||
- trash_watcher_watch (backend->watcher);
|
||||
+ trash_backend_worker_thread_queue (backend, watch_func);
|
||||
|
||||
backend->file_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
|
||||
}
|
||||
@@ -84,7 +176,7 @@ trash_backend_get_dir_monitor (GVfsBackendTrash *backend,
|
||||
* no possibility here for creating more than one new monitor.
|
||||
*/
|
||||
if (backend->file_monitor == NULL)
|
||||
- trash_watcher_watch (backend->watcher);
|
||||
+ trash_backend_worker_thread_queue (backend, watch_func);
|
||||
|
||||
backend->dir_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
|
||||
}
|
||||
@@ -164,7 +256,6 @@ trash_backend_item_count_changed (gpointer user_data)
|
||||
}
|
||||
}
|
||||
|
||||
-
|
||||
static GFile *
|
||||
trash_backend_get_file (GVfsBackendTrash *backend,
|
||||
const char *filename,
|
||||
@@ -177,6 +268,8 @@ trash_backend_get_file (GVfsBackendTrash *backend,
|
||||
TrashItem *item;
|
||||
GFile *file;
|
||||
|
||||
+ trash_backend_worker_thread_queue_and_wait (backend, rescan_func);
|
||||
+
|
||||
file = NULL;
|
||||
filename++;
|
||||
|
||||
@@ -243,9 +336,6 @@ trash_backend_open_for_read (GVfsBackend *vfs_backend,
|
||||
{
|
||||
GFile *real;
|
||||
|
||||
- if (!backend->file_monitor && !backend->dir_monitor)
|
||||
- trash_watcher_rescan (backend->watcher);
|
||||
-
|
||||
real = trash_backend_get_file (backend, filename, NULL, NULL, &error);
|
||||
|
||||
if (real)
|
||||
@@ -404,9 +494,6 @@ trash_backend_delete (GVfsBackend *vfs_backend,
|
||||
TrashItem *item;
|
||||
GFile *real;
|
||||
|
||||
- if (!backend->file_monitor && !backend->dir_monitor)
|
||||
- trash_watcher_rescan (backend->watcher);
|
||||
-
|
||||
real = trash_backend_get_file (backend, filename,
|
||||
&item, &is_toplevel, &error);
|
||||
|
||||
@@ -461,9 +548,6 @@ trash_backend_pull (GVfsBackend *vfs_backend,
|
||||
TrashItem *item;
|
||||
GFile *real;
|
||||
|
||||
- if (!backend->file_monitor && !backend->dir_monitor)
|
||||
- trash_watcher_rescan (backend->watcher);
|
||||
-
|
||||
real = trash_backend_get_file (backend, source, &item,
|
||||
&is_toplevel, &error);
|
||||
|
||||
@@ -585,6 +669,8 @@ trash_backend_enumerate_root (GVfsBackendTrash *backend,
|
||||
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
|
||||
+ trash_backend_worker_thread_queue_and_wait (backend, rescan_func);
|
||||
+
|
||||
items = trash_root_get_items (backend->root);
|
||||
|
||||
for (node = items; node; node = node->next)
|
||||
@@ -675,8 +761,6 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
|
||||
|
||||
g_assert (filename[0] == '/');
|
||||
|
||||
- trash_watcher_rescan (backend->watcher);
|
||||
-
|
||||
if (!is_root (filename))
|
||||
trash_backend_enumerate_non_root (backend, job, filename,
|
||||
attribute_matcher, flags);
|
||||
@@ -684,6 +768,31 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
|
||||
trash_backend_enumerate_root (backend, job, attribute_matcher, flags);
|
||||
}
|
||||
|
||||
+static gpointer
|
||||
+thread_func (gpointer user_data)
|
||||
+{
|
||||
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
|
||||
+
|
||||
+ g_main_context_push_thread_default (backend->worker_context);
|
||||
+ backend->worker_loop = g_main_loop_new (backend->worker_context, FALSE);
|
||||
+
|
||||
+ backend->root = trash_root_new (trash_backend_item_created,
|
||||
+ trash_backend_item_deleted,
|
||||
+ trash_backend_item_count_changed,
|
||||
+ backend);
|
||||
+ backend->watcher = trash_watcher_new (backend->root);
|
||||
+
|
||||
+ g_main_loop_run (backend->worker_loop);
|
||||
+
|
||||
+ trash_watcher_free (backend->watcher);
|
||||
+ trash_root_free (backend->root);
|
||||
+
|
||||
+ g_main_context_pop_thread_default (backend->worker_context);
|
||||
+ g_main_loop_unref (backend->worker_loop);
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
static void
|
||||
trash_backend_mount (GVfsBackend *vfs_backend,
|
||||
GVfsJobMount *job,
|
||||
@@ -695,11 +804,12 @@ trash_backend_mount (GVfsBackend *vfs_backend,
|
||||
|
||||
backend->file_monitor = NULL;
|
||||
backend->dir_monitor = NULL;
|
||||
- backend->root = trash_root_new (trash_backend_item_created,
|
||||
- trash_backend_item_deleted,
|
||||
- trash_backend_item_count_changed,
|
||||
- backend);
|
||||
- backend->watcher = trash_watcher_new (backend->root);
|
||||
+
|
||||
+ backend->worker_context = g_main_context_new ();
|
||||
+ backend->worker_thread = g_thread_new ("Trash Worker Thread",
|
||||
+ thread_func,
|
||||
+ backend);
|
||||
+ trash_backend_worker_thread_queue_and_wait (backend, ready_func);
|
||||
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
}
|
||||
@@ -716,9 +826,6 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
|
||||
|
||||
g_assert (filename[0] == '/');
|
||||
|
||||
- if (!backend->file_monitor && !backend->dir_monitor)
|
||||
- trash_watcher_rescan (backend->watcher);
|
||||
-
|
||||
if (!is_root (filename))
|
||||
{
|
||||
GError *error = NULL;
|
||||
@@ -762,6 +869,8 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
|
||||
GIcon *icon;
|
||||
int n_items;
|
||||
|
||||
+ trash_backend_worker_thread_queue_and_wait (backend, rescan_func);
|
||||
+
|
||||
n_items = trash_root_get_n_items (backend->root);
|
||||
|
||||
g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
|
||||
@@ -878,9 +987,6 @@ trash_backend_finalize (GObject *object)
|
||||
if (backend->dir_monitor)
|
||||
g_object_unref (backend->dir_monitor);
|
||||
backend->dir_monitor = NULL;
|
||||
-
|
||||
- trash_watcher_free (backend->watcher);
|
||||
- trash_root_free (backend->root);
|
||||
}
|
||||
|
||||
static void
|
||||
--
|
||||
2.53.0
|
||||
|
||||
30
trash-Chain-up-finalize.patch
Normal file
30
trash-Chain-up-finalize.patch
Normal file
@ -0,0 +1,30 @@
|
||||
From f1cdb812f8fa6f06239183923f920025a05e0712 Mon Sep 17 00:00:00 2001
|
||||
From: Maximiliano Sandoval <msandova@gnome.org>
|
||||
Date: Fri, 10 Apr 2026 23:52:16 +0200
|
||||
Subject: [PATCH] trash: Chain up finalize
|
||||
|
||||
Currently, `trash_backend_finalize()` only releases backend-specific
|
||||
monitors. Without chaining up, parent `GObject` finalization is
|
||||
skipped, which can leave parent-side teardown incomplete. Let's call
|
||||
`g_vfs_backend_trash_parent_class->finalize()` at the end of
|
||||
`trash_backned_finalize()`.
|
||||
---
|
||||
daemon/gvfsbackendtrash.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
|
||||
index 0966242a..1dcb44f0 100644
|
||||
--- a/daemon/gvfsbackendtrash.c
|
||||
+++ b/daemon/gvfsbackendtrash.c
|
||||
@@ -987,6 +987,8 @@ trash_backend_finalize (GObject *object)
|
||||
if (backend->dir_monitor)
|
||||
g_object_unref (backend->dir_monitor);
|
||||
backend->dir_monitor = NULL;
|
||||
+
|
||||
+ G_OBJECT_CLASS (g_vfs_backend_trash_parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static void
|
||||
--
|
||||
2.53.0
|
||||
|
||||
84
trash-Defer-mount-monitoring-to-active-watchers-only.patch
Normal file
84
trash-Defer-mount-monitoring-to-active-watchers-only.patch
Normal file
@ -0,0 +1,84 @@
|
||||
From 5e34cc212b32e58fd7b6721d92548e983fecd991 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 15:54:33 +0200
|
||||
Subject: [PATCH] trash: Defer mount monitoring to active watchers only
|
||||
|
||||
Backport of commit b53d45db.
|
||||
|
||||
Adjusted context for target version.
|
||||
---
|
||||
daemon/trashlib/trashwatcher.c | 26 +++++++++++++++++++++-----
|
||||
1 file changed, 21 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
|
||||
index bd658e1..3a1bc9f 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -139,6 +139,7 @@ struct OPAQUE_TYPE__TrashWatcher
|
||||
TrashRoot *root;
|
||||
|
||||
GUnixMountMonitor *mount_monitor;
|
||||
+ gulong mounts_changed_id;
|
||||
GHashTable *mounts; /* mount_path -> TrashMount */
|
||||
guint update_id;
|
||||
|
||||
@@ -339,8 +340,7 @@ trash_watcher_new (TrashRoot *root)
|
||||
watcher->watching = FALSE;
|
||||
watcher->update_id = 0;
|
||||
watcher->mount_monitor = g_unix_mount_monitor_get ();
|
||||
- g_signal_connect_swapped (watcher->mount_monitor, "mounts_changed",
|
||||
- G_CALLBACK (trash_watcher_remount), watcher);
|
||||
+ watcher->mounts_changed_id = 0;
|
||||
|
||||
user_datadir = g_file_new_for_path (g_get_user_data_dir ());
|
||||
homedir_trashdir = g_file_get_child (user_datadir, "Trash/files");
|
||||
@@ -378,9 +378,17 @@ trash_watcher_watch (TrashWatcher *watcher)
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
|
||||
+ g_debug ("trash_watcher_watch\n");
|
||||
+
|
||||
if (watcher->watching)
|
||||
return;
|
||||
|
||||
+ watcher->mounts_changed_id =
|
||||
+ g_signal_connect_swapped (watcher->mount_monitor, "mounts_changed",
|
||||
+ G_CALLBACK (trash_watcher_remount), watcher);
|
||||
+
|
||||
+ trash_watcher_remount_do (watcher);
|
||||
+
|
||||
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
|
||||
trash_dir_watch (watcher->homedir_trashdir);
|
||||
|
||||
@@ -404,9 +412,17 @@ trash_watcher_unwatch (TrashWatcher *watcher)
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
|
||||
+ g_debug ("trash_watcher_unwatch\n");
|
||||
+
|
||||
if (!watcher->watching)
|
||||
return;
|
||||
|
||||
+ g_signal_handler_disconnect (watcher->mount_monitor,
|
||||
+ watcher->mounts_changed_id);
|
||||
+ watcher->mounts_changed_id = 0;
|
||||
+
|
||||
+ g_clear_handle_id (&watcher->update_id, g_source_remove);
|
||||
+
|
||||
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
|
||||
trash_dir_unwatch (watcher->homedir_trashdir);
|
||||
|
||||
@@ -430,7 +446,9 @@ trash_watcher_rescan (TrashWatcher *watcher)
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
|
||||
- if (watcher->update_id != 0)
|
||||
+ if (!watcher->watching)
|
||||
+ trash_watcher_remount_do (watcher);
|
||||
+ else if (watcher->update_id != 0)
|
||||
{
|
||||
g_source_remove (watcher->update_id);
|
||||
trash_watcher_remount_timeout (watcher);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
57
trash-Do-not-create-monitors-for-non-root-items.patch
Normal file
57
trash-Do-not-create-monitors-for-non-root-items.patch
Normal file
@ -0,0 +1,57 @@
|
||||
From 85a789c800ef2773af6eb8884fef746d67d3cafe Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Fri, 20 Jan 2023 09:17:00 +0100
|
||||
Subject: [PATCH] trash: Do not create monitors for non-root items
|
||||
|
||||
The `create_dir_monitor` and `create_file_monitor` methods never fail
|
||||
currently. However, no events are emitted for non-root items. Let's
|
||||
return the `G_IO_ERROR_NOT_SUPPORTED` error for non-root items instead.
|
||||
---
|
||||
daemon/gvfsbackendtrash.c | 22 ++++++++++++++++------
|
||||
1 file changed, 16 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
|
||||
index d7ec4f77..76c9e006 100644
|
||||
--- a/daemon/gvfsbackendtrash.c
|
||||
+++ b/daemon/gvfsbackendtrash.c
|
||||
@@ -839,10 +839,15 @@ trash_backend_create_dir_monitor (GVfsBackend *vfs_backend,
|
||||
GVfsMonitor *monitor;
|
||||
|
||||
if (!is_root (filename))
|
||||
- monitor = g_vfs_monitor_new (vfs_backend);
|
||||
- else
|
||||
- monitor = trash_backend_get_dir_monitor (backend, TRUE);
|
||||
+ {
|
||||
+ g_vfs_job_failed (G_VFS_JOB (job),
|
||||
+ G_IO_ERROR,
|
||||
+ G_IO_ERROR_NOT_SUPPORTED,
|
||||
+ _("Operation not supported"));
|
||||
+ return TRUE;
|
||||
+ }
|
||||
|
||||
+ monitor = trash_backend_get_dir_monitor (backend, TRUE);
|
||||
g_vfs_job_create_monitor_set_monitor (job, monitor);
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
g_object_unref (monitor);
|
||||
@@ -860,10 +865,15 @@ trash_backend_create_file_monitor (GVfsBackend *vfs_backend,
|
||||
GVfsMonitor *monitor;
|
||||
|
||||
if (!is_root (filename))
|
||||
- monitor = g_vfs_monitor_new (vfs_backend);
|
||||
- else
|
||||
- monitor = trash_backend_get_file_monitor (backend, TRUE);
|
||||
+ {
|
||||
+ g_vfs_job_failed (G_VFS_JOB (job),
|
||||
+ G_IO_ERROR,
|
||||
+ G_IO_ERROR_NOT_SUPPORTED,
|
||||
+ _("Operation not supported"));
|
||||
+ return TRUE;
|
||||
+ }
|
||||
|
||||
+ monitor = trash_backend_get_file_monitor (backend, TRUE);
|
||||
g_vfs_job_create_monitor_set_monitor (job, monitor);
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
g_object_unref (monitor);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
119
trash-Rate-limit-mount-updates.patch
Normal file
119
trash-Rate-limit-mount-updates.patch
Normal file
@ -0,0 +1,119 @@
|
||||
From 181da9f0d10a9e75795db5bb138214a89382271f Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Fri, 21 Nov 2025 13:28:55 +0100
|
||||
Subject: [PATCH] trash: Rate limit mount updates
|
||||
|
||||
Currently, the trash daemon processes every `mounts_changed` signal.
|
||||
This leads to high CPU usage when many mount events occur in a short
|
||||
timeframe. Let's rate limit mount processing to avoid high CPU usage
|
||||
in this case. The timeout is randomly chosen within the interval
|
||||
50-500 ms to better balance the load when multiple daemons are
|
||||
running simultaneously.
|
||||
|
||||
Related: https://gitlab.gnome.org/GNOME/gvfs/-/issues/814
|
||||
---
|
||||
daemon/trashlib/trashwatcher.c | 39 ++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 37 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
|
||||
index 80a24d3d..664380c6 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -142,6 +142,7 @@ struct OPAQUE_TYPE__TrashWatcher
|
||||
|
||||
GUnixMountMonitor *mount_monitor;
|
||||
TrashMount *mounts;
|
||||
+ guint update_id;
|
||||
|
||||
TrashDir *homedir_trashdir;
|
||||
WatchType homedir_type;
|
||||
@@ -158,6 +159,8 @@ struct _TrashMount
|
||||
TrashMount *next;
|
||||
};
|
||||
|
||||
+#define UPDATE_TIMEOUT 100 /* ms */
|
||||
+
|
||||
static void
|
||||
trash_mount_insert (TrashWatcher *watcher,
|
||||
TrashMount ***mount_ptr_ptr,
|
||||
@@ -247,7 +250,7 @@ ignore_trash_mount (GUnixMountEntry *mount)
|
||||
}
|
||||
|
||||
static void
|
||||
-trash_watcher_remount (TrashWatcher *watcher)
|
||||
+trash_watcher_remount_do (TrashWatcher *watcher)
|
||||
{
|
||||
TrashMount **old;
|
||||
GList *mounts;
|
||||
@@ -298,6 +301,29 @@ trash_watcher_remount (TrashWatcher *watcher)
|
||||
g_list_free (mounts);
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+trash_watcher_remount_timeout (gpointer user_data)
|
||||
+{
|
||||
+ TrashWatcher *watcher = user_data;
|
||||
+
|
||||
+ watcher->update_id = 0;
|
||||
+
|
||||
+ trash_watcher_remount_do (watcher);
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+trash_watcher_remount (TrashWatcher *watcher)
|
||||
+{
|
||||
+ if (watcher->update_id != 0)
|
||||
+ return;
|
||||
+
|
||||
+ watcher->update_id = g_timeout_add (UPDATE_TIMEOUT * g_random_double_range (0.5, 5),
|
||||
+ trash_watcher_remount_timeout,
|
||||
+ watcher);
|
||||
+}
|
||||
+
|
||||
TrashWatcher *
|
||||
trash_watcher_new (TrashRoot *root)
|
||||
{
|
||||
@@ -310,6 +336,7 @@ trash_watcher_new (TrashRoot *root)
|
||||
watcher->root = root;
|
||||
watcher->mounts = NULL;
|
||||
watcher->watching = FALSE;
|
||||
+ watcher->update_id = 0;
|
||||
watcher->mount_monitor = g_unix_mount_monitor_get ();
|
||||
g_signal_connect_swapped (watcher->mount_monitor, "mounts_changed",
|
||||
G_CALLBACK (trash_watcher_remount), watcher);
|
||||
@@ -328,7 +355,7 @@ trash_watcher_new (TrashRoot *root)
|
||||
g_object_unref (homedir_trashdir);
|
||||
g_object_unref (user_datadir);
|
||||
|
||||
- trash_watcher_remount (watcher);
|
||||
+ trash_watcher_remount_do (watcher);
|
||||
|
||||
return watcher;
|
||||
}
|
||||
@@ -336,6 +363,8 @@ trash_watcher_new (TrashRoot *root)
|
||||
void
|
||||
trash_watcher_free (TrashWatcher *watcher)
|
||||
{
|
||||
+ g_clear_handle_id (&watcher->update_id, g_source_remove);
|
||||
+
|
||||
/* We just leak everything here, as this is not normally hit.
|
||||
This used to be a g_assert_not_reached(), and that got hit when
|
||||
mounting the trash backend failed due to the trash already being
|
||||
@@ -387,6 +416,12 @@ trash_watcher_rescan (TrashWatcher *watcher)
|
||||
{
|
||||
TrashMount *mount;
|
||||
|
||||
+ if (watcher->update_id != 0)
|
||||
+ {
|
||||
+ g_source_remove (watcher->update_id);
|
||||
+ trash_watcher_remount_timeout (watcher);
|
||||
+ }
|
||||
+
|
||||
if (!watcher->watching || watcher->homedir_type != TRASH_WATCHER_TRUSTED)
|
||||
trash_dir_rescan (watcher->homedir_trashdir);
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
88
trash-Rate-limit-size-change-notifications.patch
Normal file
88
trash-Rate-limit-size-change-notifications.patch
Normal file
@ -0,0 +1,88 @@
|
||||
From 68a056dd3764c795c5d9d5844e2cc3f20f9eaf1d Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 3 Feb 2026 16:47:50 +0100
|
||||
Subject: [PATCH] trash: Rate limit size change notifications
|
||||
|
||||
Currently, the `attribute-changed` signal is emitted after every file
|
||||
change. This can lead to higher CPU usage if too many changes occur
|
||||
in a short time frame. To avoid this, let's limit the frequency of the
|
||||
signal to a maximum of 100 ms.
|
||||
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>
|
||||
|
||||
Related: https://gitlab.gnome.org/GNOME/gvfs/-/issues/814
|
||||
---
|
||||
daemon/trashlib/trashitem.c | 26 +++++++++++++++++++++++---
|
||||
1 file changed, 23 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashitem.c b/daemon/trashlib/trashitem.c
|
||||
index a5b5b166..08dd8ad8 100644
|
||||
--- a/daemon/trashlib/trashitem.c
|
||||
+++ b/daemon/trashlib/trashitem.c
|
||||
@@ -30,8 +30,12 @@ struct OPAQUE_TYPE__TrashRoot
|
||||
|
||||
GHashTable *item_table;
|
||||
int old_size;
|
||||
+
|
||||
+ guint size_change_id;
|
||||
};
|
||||
|
||||
+#define SIZE_CHANGE_TIMEOUT 100 /* ms */
|
||||
+
|
||||
struct OPAQUE_TYPE__TrashItem
|
||||
{
|
||||
TrashRoot *root;
|
||||
@@ -283,6 +287,17 @@ trash_item_invoke_closure (NotifyClosure *closure)
|
||||
g_slice_free (NotifyClosure, closure);
|
||||
}
|
||||
|
||||
+static gboolean
|
||||
+trash_root_size_change_timeout (gpointer user_data)
|
||||
+{
|
||||
+ TrashRoot *root = user_data;
|
||||
+
|
||||
+ root->size_change_id = 0;
|
||||
+ root->size_change (root->user_data);
|
||||
+
|
||||
+ return G_SOURCE_REMOVE;
|
||||
+}
|
||||
+
|
||||
void
|
||||
trash_root_thaw (TrashRoot *root)
|
||||
{
|
||||
@@ -308,10 +323,13 @@ trash_root_thaw (TrashRoot *root)
|
||||
size_changed = root->old_size != size;
|
||||
root->old_size = size;
|
||||
|
||||
- g_rw_lock_writer_unlock (&root->lock);
|
||||
+ /* Rate limit size_change notifications */
|
||||
+ if (size_changed && root->size_change_id == 0)
|
||||
+ root->size_change_id = g_timeout_add (SIZE_CHANGE_TIMEOUT,
|
||||
+ trash_root_size_change_timeout,
|
||||
+ root);
|
||||
|
||||
- if (size_changed)
|
||||
- root->size_change (root->user_data);
|
||||
+ g_rw_lock_writer_unlock (&root->lock);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -341,6 +359,7 @@ trash_root_new (trash_item_notify create,
|
||||
root->item_table = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
NULL, trash_item_removed);
|
||||
root->old_size = 0;
|
||||
+ root->size_change_id = 0;
|
||||
|
||||
return root;
|
||||
}
|
||||
@@ -348,6 +367,7 @@ trash_root_new (trash_item_notify create,
|
||||
void
|
||||
trash_root_free (TrashRoot *root)
|
||||
{
|
||||
+ g_clear_handle_id (&root->size_change_id, g_source_remove);
|
||||
g_hash_table_destroy (root->item_table);
|
||||
|
||||
while (!g_queue_is_empty (root->notifications))
|
||||
--
|
||||
2.53.0
|
||||
|
||||
24
trash-Remove-unused-is_homedir-property.patch
Normal file
24
trash-Remove-unused-is_homedir-property.patch
Normal file
@ -0,0 +1,24 @@
|
||||
From f8504e445976830287dcb44a51514dc4c15fe528 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Wed, 7 Jun 2023 15:50:51 +0200
|
||||
Subject: [PATCH] trash: Remove unused is_homedir property
|
||||
|
||||
---
|
||||
daemon/trashlib/trashitem.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashitem.c b/daemon/trashlib/trashitem.c
|
||||
index 08912856..a5b5b166 100644
|
||||
--- a/daemon/trashlib/trashitem.c
|
||||
+++ b/daemon/trashlib/trashitem.c
|
||||
@@ -29,7 +29,6 @@ struct OPAQUE_TYPE__TrashRoot
|
||||
gpointer user_data;
|
||||
|
||||
GHashTable *item_table;
|
||||
- gboolean is_homedir;
|
||||
int old_size;
|
||||
};
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
68
trash-Remove-unused-ui_hook-property.patch
Normal file
68
trash-Remove-unused-ui_hook-property.patch
Normal file
@ -0,0 +1,68 @@
|
||||
From 07f55a1dae9af0852fed9d774a6ab7d5a924d5e1 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Fri, 20 Jan 2023 15:43:10 +0100
|
||||
Subject: [PATCH] trash: Remove unused ui_hook property
|
||||
|
||||
---
|
||||
daemon/trashlib/trashdir.c | 11 -----------
|
||||
daemon/trashlib/trashdir.h | 5 -----
|
||||
2 files changed, 16 deletions(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashdir.c b/daemon/trashlib/trashdir.c
|
||||
index 0d7d2b1b..707dff6c 100644
|
||||
--- a/daemon/trashlib/trashdir.c
|
||||
+++ b/daemon/trashlib/trashdir.c
|
||||
@@ -373,8 +373,6 @@ trash_dir_rescan (TrashDir *dir)
|
||||
trash_dir_empty (dir);
|
||||
}
|
||||
|
||||
-static trash_dir_ui_hook ui_hook;
|
||||
-
|
||||
TrashDir *
|
||||
trash_dir_new (TrashRoot *root,
|
||||
gboolean watching,
|
||||
@@ -411,20 +409,11 @@ trash_dir_new (TrashRoot *root,
|
||||
else
|
||||
dir->watch = NULL;
|
||||
|
||||
- if (ui_hook)
|
||||
- ui_hook (dir, dir->directory);
|
||||
-
|
||||
g_free (rel);
|
||||
|
||||
return dir;
|
||||
}
|
||||
|
||||
-void
|
||||
-trash_dir_set_ui_hook (trash_dir_ui_hook _ui_hook)
|
||||
-{
|
||||
- ui_hook = _ui_hook;
|
||||
-}
|
||||
-
|
||||
void
|
||||
trash_dir_free (TrashDir *dir)
|
||||
{
|
||||
diff --git a/daemon/trashlib/trashdir.h b/daemon/trashlib/trashdir.h
|
||||
index 5612f9ba..4c39d516 100644
|
||||
--- a/daemon/trashlib/trashdir.h
|
||||
+++ b/daemon/trashlib/trashdir.h
|
||||
@@ -15,9 +15,6 @@
|
||||
|
||||
typedef struct OPAQUE_TYPE__TrashDir TrashDir;
|
||||
|
||||
-typedef void (*trash_dir_ui_hook) (TrashDir *dir,
|
||||
- GFile *directory);
|
||||
-
|
||||
TrashDir *trash_dir_new (TrashRoot *root,
|
||||
gboolean watching,
|
||||
gboolean is_homedir,
|
||||
@@ -31,6 +28,4 @@ void trash_dir_watch (TrashDir *dir);
|
||||
void trash_dir_unwatch (TrashDir *dir);
|
||||
void trash_dir_rescan (TrashDir *dir);
|
||||
|
||||
-void trash_dir_set_ui_hook (trash_dir_ui_hook ui_hook);
|
||||
-
|
||||
#endif /* _trashdir_h_ */
|
||||
--
|
||||
2.53.0
|
||||
|
||||
241
trash-Run-blocking-methods-on-a-thread-pool.patch
Normal file
241
trash-Run-blocking-methods-on-a-thread-pool.patch
Normal file
@ -0,0 +1,241 @@
|
||||
From 3889e4dec938a8023b8120545d4b53083b209dab Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Thu, 19 Jan 2023 12:12:52 +0100
|
||||
Subject: [PATCH] trash: Run blocking methods on a thread pool
|
||||
|
||||
All jobs use `_try` methods currently. This is wrong as most of them can
|
||||
block. This works quite ok except the case of stale NFS mounts that can
|
||||
block the main loop forever. Let's run the jobs on a thread pool instead.
|
||||
This reverts commit 01fe5a61 except for the `create_dir_monitor` and
|
||||
`create_file_monitor` methods in order to avoid issues like
|
||||
https://bugzilla.gnome.org/show_bug.cgi?id=723305.
|
||||
---
|
||||
daemon/gvfsbackendtrash.c | 68 ++++++++++++++-------------------------
|
||||
1 file changed, 25 insertions(+), 43 deletions(-)
|
||||
|
||||
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
|
||||
index 76c9e006..b4d3d089 100644
|
||||
--- a/daemon/gvfsbackendtrash.c
|
||||
+++ b/daemon/gvfsbackendtrash.c
|
||||
@@ -227,7 +227,7 @@ trash_backend_get_file (GVfsBackendTrash *backend,
|
||||
}
|
||||
|
||||
/* ======================= method implementations ======================= */
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_open_for_read (GVfsBackend *vfs_backend,
|
||||
GVfsJobOpenForRead *job,
|
||||
const char *filename)
|
||||
@@ -261,18 +261,16 @@ trash_backend_open_for_read (GVfsBackend *vfs_backend,
|
||||
g_vfs_job_open_for_read_set_can_seek (job, TRUE);
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||
g_error_free (error);
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_read (GVfsBackend *backend,
|
||||
GVfsJobRead *job,
|
||||
GVfsBackendHandle handle,
|
||||
@@ -290,16 +288,14 @@ trash_backend_read (GVfsBackend *backend,
|
||||
g_vfs_job_read_set_size (job, bytes);
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
|
||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||
g_error_free (error);
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_seek_on_read (GVfsBackend *backend,
|
||||
GVfsJobSeekRead *job,
|
||||
GVfsBackendHandle handle,
|
||||
@@ -313,13 +309,11 @@ trash_backend_seek_on_read (GVfsBackend *backend,
|
||||
g_vfs_job_seek_read_set_offset (job, g_seekable_tell (handle));
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
|
||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||
g_error_free (error);
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -349,7 +343,7 @@ trash_backend_query_info_on_read (GVfsBackend *backend,
|
||||
}
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_close_read (GVfsBackend *backend,
|
||||
GVfsJobCloseRead *job,
|
||||
GVfsBackendHandle handle)
|
||||
@@ -361,15 +355,13 @@ trash_backend_close_read (GVfsBackend *backend,
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
g_object_unref (handle);
|
||||
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
|
||||
g_object_unref (handle);
|
||||
|
||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||
g_error_free (error);
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -394,7 +386,7 @@ trash_backend_schedule_thaw (GVfsBackendTrash *backend)
|
||||
backend);
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_delete (GVfsBackend *vfs_backend,
|
||||
GVfsJobDelete *job,
|
||||
const char *filename)
|
||||
@@ -435,7 +427,7 @@ trash_backend_delete (GVfsBackend *vfs_backend,
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
trash_item_unref (item);
|
||||
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -445,11 +437,9 @@ trash_backend_delete (GVfsBackend *vfs_backend,
|
||||
|
||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||
g_error_free (error);
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_pull (GVfsBackend *vfs_backend,
|
||||
GVfsJobPull *job,
|
||||
const gchar *source,
|
||||
@@ -505,7 +495,7 @@ trash_backend_pull (GVfsBackend *vfs_backend,
|
||||
trash_item_unref (item);
|
||||
g_object_unref (real);
|
||||
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,8 +507,6 @@ trash_backend_pull (GVfsBackend *vfs_backend,
|
||||
|
||||
g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
|
||||
g_error_free (error);
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -676,7 +664,7 @@ trash_backend_enumerate_non_root (GVfsBackendTrash *backend,
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_enumerate (GVfsBackend *vfs_backend,
|
||||
GVfsJobEnumerate *job,
|
||||
const char *filename,
|
||||
@@ -694,11 +682,9 @@ trash_backend_enumerate (GVfsBackend *vfs_backend,
|
||||
attribute_matcher, flags);
|
||||
else
|
||||
trash_backend_enumerate_root (backend, job, attribute_matcher, flags);
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_mount (GVfsBackend *vfs_backend,
|
||||
GVfsJobMount *job,
|
||||
GMountSpec *mount_spec,
|
||||
@@ -716,11 +702,9 @@ trash_backend_mount (GVfsBackend *vfs_backend,
|
||||
backend->watcher = trash_watcher_new (backend->root);
|
||||
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
-static gboolean
|
||||
+static void
|
||||
trash_backend_query_info (GVfsBackend *vfs_backend,
|
||||
GVfsJobQueryInfo *job,
|
||||
const char *filename,
|
||||
@@ -764,7 +748,7 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
|
||||
trash_item_unref (item);
|
||||
g_object_unref (real_info);
|
||||
|
||||
- return TRUE;
|
||||
+ return;
|
||||
}
|
||||
|
||||
trash_item_unref (item);
|
||||
@@ -798,8 +782,6 @@ trash_backend_query_info (GVfsBackend *vfs_backend,
|
||||
|
||||
g_vfs_job_succeeded (G_VFS_JOB (job));
|
||||
}
|
||||
-
|
||||
- return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -926,17 +908,17 @@ g_vfs_backend_trash_class_init (GVfsBackendTrashClass *class)
|
||||
|
||||
gobject_class->finalize = trash_backend_finalize;
|
||||
|
||||
- backend_class->try_mount = trash_backend_mount;
|
||||
- backend_class->try_open_for_read = trash_backend_open_for_read;
|
||||
- backend_class->try_read = trash_backend_read;
|
||||
- backend_class->try_seek_on_read = trash_backend_seek_on_read;
|
||||
+ backend_class->mount = trash_backend_mount;
|
||||
+ backend_class->open_for_read = trash_backend_open_for_read;
|
||||
+ backend_class->read = trash_backend_read;
|
||||
+ backend_class->seek_on_read = trash_backend_seek_on_read;
|
||||
backend_class->query_info_on_read = trash_backend_query_info_on_read;
|
||||
- backend_class->try_close_read = trash_backend_close_read;
|
||||
- backend_class->try_query_info = trash_backend_query_info;
|
||||
+ backend_class->close_read = trash_backend_close_read;
|
||||
+ backend_class->query_info = trash_backend_query_info;
|
||||
backend_class->try_query_fs_info = trash_backend_query_fs_info;
|
||||
- backend_class->try_enumerate = trash_backend_enumerate;
|
||||
- backend_class->try_delete = trash_backend_delete;
|
||||
- backend_class->try_pull = trash_backend_pull;
|
||||
+ backend_class->enumerate = trash_backend_enumerate;
|
||||
+ backend_class->delete = trash_backend_delete;
|
||||
+ backend_class->pull = trash_backend_pull;
|
||||
backend_class->try_create_dir_monitor = trash_backend_create_dir_monitor;
|
||||
backend_class->try_create_file_monitor = trash_backend_create_file_monitor;
|
||||
}
|
||||
--
|
||||
2.53.0
|
||||
|
||||
47
trash-Skip-mount-table-reparsing-when-unchanged.patch
Normal file
47
trash-Skip-mount-table-reparsing-when-unchanged.patch
Normal file
@ -0,0 +1,47 @@
|
||||
From 1ae1e68794a01b524d91c3da0addeca4d060b795 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 15:54:37 +0200
|
||||
Subject: [PATCH] trash: Skip mount table reparsing when unchanged
|
||||
|
||||
Backport of commit e1821cdc.
|
||||
|
||||
Adapted for older GLib API: `g_unix_mount_entries_get`/`g_unix_mount_entries_changed_since` replaced with `g_unix_mounts_get`/`g_unix_mounts_changed_since`.
|
||||
---
|
||||
daemon/trashlib/trashwatcher.c | 7 ++++++-
|
||||
1 file changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
|
||||
index e44ab06..59303f0 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -142,6 +142,7 @@ struct OPAQUE_TYPE__TrashWatcher
|
||||
gulong mounts_changed_id;
|
||||
GHashTable *mounts; /* mount_path -> TrashMount */
|
||||
guint update_id;
|
||||
+ guint64 last_mount_time;
|
||||
|
||||
TrashDir *homedir_trashdir;
|
||||
WatchType homedir_type;
|
||||
@@ -246,7 +247,10 @@ trash_watcher_remount_do (TrashWatcher *watcher)
|
||||
gpointer key, value;
|
||||
const char *mount_path;
|
||||
|
||||
- mounts = g_unix_mounts_get (NULL);
|
||||
+ if (!g_unix_mounts_changed_since (watcher->last_mount_time))
|
||||
+ return;
|
||||
+
|
||||
+ mounts = g_unix_mounts_get (&watcher->last_mount_time);
|
||||
mount_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
for (l = mounts; l != NULL; l = l->next)
|
||||
@@ -339,6 +343,7 @@ trash_watcher_new (TrashRoot *root)
|
||||
watcher->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
watcher->watching = FALSE;
|
||||
watcher->update_id = 0;
|
||||
+ watcher->last_mount_time = 0;
|
||||
watcher->mount_monitor = g_unix_mount_monitor_get ();
|
||||
watcher->mounts_changed_id = 0;
|
||||
|
||||
--
|
||||
2.53.0
|
||||
|
||||
280
trash-Use-GHashTable-for-mount-tracking.patch
Normal file
280
trash-Use-GHashTable-for-mount-tracking.patch
Normal file
@ -0,0 +1,280 @@
|
||||
From 0f166b6f4f3e38144c779b3e6b55d777c6637b0e Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Wed, 3 Jun 2026 08:37:56 +0200
|
||||
Subject: [PATCH] trash: Use GHashTable for mount tracking
|
||||
|
||||
Backport of commit 64f8853f.
|
||||
|
||||
Adapted for older GLib API: `g_unix_mount_entry_*` replaced with `g_unix_mount_*`, `g_unix_mount_entries_get` replaced with `g_unix_mounts_get`.
|
||||
---
|
||||
daemon/trashlib/trashwatcher.c | 156 +++++++++++++++++----------------
|
||||
1 file changed, 80 insertions(+), 76 deletions(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
|
||||
index d8d6ef8..426f97f 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -139,7 +139,7 @@ struct OPAQUE_TYPE__TrashWatcher
|
||||
TrashRoot *root;
|
||||
|
||||
GUnixMountMonitor *mount_monitor;
|
||||
- TrashMount *mounts;
|
||||
+ GHashTable *mounts; /* mount_path -> TrashMount */
|
||||
guint update_id;
|
||||
|
||||
TrashDir *homedir_trashdir;
|
||||
@@ -153,16 +153,13 @@ struct _TrashMount
|
||||
GUnixMountEntry *mount_entry;
|
||||
TrashDir *dirs[2];
|
||||
WatchType type;
|
||||
-
|
||||
- TrashMount *next;
|
||||
};
|
||||
|
||||
#define UPDATE_TIMEOUT 100 /* ms */
|
||||
|
||||
static void
|
||||
-trash_mount_insert (TrashWatcher *watcher,
|
||||
- TrashMount ***mount_ptr_ptr,
|
||||
- GUnixMountEntry *mount_entry)
|
||||
+trash_mount_insert (TrashWatcher *watcher,
|
||||
+ GUnixMountEntry *mount_entry)
|
||||
{
|
||||
const char *mountpoint;
|
||||
gboolean watching;
|
||||
@@ -192,24 +189,15 @@ trash_mount_insert (TrashWatcher *watcher,
|
||||
mount->dirs[1] = trash_dir_new (watcher->root, watching, FALSE, mountpoint,
|
||||
".Trash-%d/files", (int) getuid ());
|
||||
|
||||
- mount->next = **mount_ptr_ptr;
|
||||
-
|
||||
- **mount_ptr_ptr = mount;
|
||||
- *mount_ptr_ptr = &mount->next;
|
||||
+ g_hash_table_insert (watcher->mounts, g_strdup (mountpoint), mount);
|
||||
}
|
||||
|
||||
static void
|
||||
-trash_mount_remove (TrashMount **mount_ptr)
|
||||
+trash_mount_free (TrashMount *mount)
|
||||
{
|
||||
- TrashMount *mount = *mount_ptr;
|
||||
-
|
||||
- /* first, the dirs */
|
||||
trash_dir_free (mount->dirs[0]);
|
||||
trash_dir_free (mount->dirs[1]);
|
||||
|
||||
- /* detach from list */
|
||||
- *mount_ptr = mount->next;
|
||||
-
|
||||
g_unix_mount_free (mount->mount_entry);
|
||||
g_slice_free (TrashMount, mount);
|
||||
}
|
||||
@@ -249,63 +237,64 @@ ignore_trash_mount (GUnixMountEntry *mount)
|
||||
static void
|
||||
trash_watcher_remount_do (TrashWatcher *watcher)
|
||||
{
|
||||
- TrashMount **old;
|
||||
+ GHashTable *mount_paths;
|
||||
+ GHashTableIter iter;
|
||||
GList *mounts;
|
||||
- GList *new;
|
||||
+ GList *l;
|
||||
+ gpointer key, value;
|
||||
+ const char *mount_path;
|
||||
|
||||
mounts = g_unix_mounts_get (NULL);
|
||||
- mounts = g_list_sort (mounts, (GCompareFunc) g_unix_mount_compare);
|
||||
+ mount_paths = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
- old = &watcher->mounts;
|
||||
- new = mounts;
|
||||
-
|
||||
- /* synchronise the two lists */
|
||||
- while (*old || new)
|
||||
+ for (l = mounts; l != NULL; l = l->next)
|
||||
{
|
||||
- int result;
|
||||
+ g_autoptr(GUnixMountEntry) mount_entry = l->data;
|
||||
|
||||
- if (new && ignore_trash_mount (new->data))
|
||||
+ if (ignore_trash_mount (mount_entry))
|
||||
{
|
||||
- g_unix_mount_free (new->data);
|
||||
- new = new->next;
|
||||
+ g_debug ("trash_watcher_remount_do: ignore %s %s %s\n",
|
||||
+ g_unix_mount_get_device_path (mount_entry),
|
||||
+ g_unix_mount_get_mount_path (mount_entry),
|
||||
+ g_unix_mount_get_fs_type (mount_entry));
|
||||
continue;
|
||||
}
|
||||
|
||||
- if ((result = (new == NULL) - (*old == NULL)) == 0)
|
||||
- result = g_unix_mount_compare (new->data, (*old)->mount_entry);
|
||||
-
|
||||
- if (result < 0)
|
||||
+ mount_path = g_unix_mount_get_mount_path (mount_entry);
|
||||
+ if (!g_hash_table_contains (watcher->mounts, mount_path))
|
||||
{
|
||||
- /* new entry. add it. */
|
||||
g_debug ("trash_watcher_remount_do: insert %s %s %s\n",
|
||||
- g_unix_mount_get_device_path (new->data),
|
||||
- g_unix_mount_get_mount_path (new->data),
|
||||
- g_unix_mount_get_fs_type (new->data));
|
||||
+ g_unix_mount_get_device_path (mount_entry),
|
||||
+ g_unix_mount_get_mount_path (mount_entry),
|
||||
+ g_unix_mount_get_fs_type (mount_entry));
|
||||
|
||||
- trash_mount_insert (watcher, &old, new->data);
|
||||
- new = new->next;
|
||||
+ trash_mount_insert (watcher, g_steal_pointer (&mount_entry));
|
||||
}
|
||||
- else if (result > 0)
|
||||
- {
|
||||
- /* old entry. remove it. */
|
||||
- g_debug ("trash_watcher_remount_do: remove %s %s %s\n",
|
||||
- g_unix_mount_get_device_path ((*old)->mount_entry),
|
||||
- g_unix_mount_get_mount_path ((*old)->mount_entry),
|
||||
- g_unix_mount_get_fs_type ((*old)->mount_entry));
|
||||
|
||||
- trash_mount_remove (old);
|
||||
- }
|
||||
- else
|
||||
+ g_hash_table_add (mount_paths, g_strdup (mount_path));
|
||||
+ }
|
||||
+
|
||||
+ g_list_free (mounts);
|
||||
+
|
||||
+ g_hash_table_iter_init (&iter, watcher->mounts);
|
||||
+ while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
+ {
|
||||
+ TrashMount *mount = value;
|
||||
+ mount_path = key;
|
||||
+
|
||||
+ if (!g_hash_table_contains (mount_paths, mount_path))
|
||||
{
|
||||
- /* match. no change. */
|
||||
- g_unix_mount_free (new->data);
|
||||
+ g_debug ("trash_watcher_remount_do: remove %s %s %s\n",
|
||||
+ g_unix_mount_get_device_path (mount->mount_entry),
|
||||
+ g_unix_mount_get_mount_path (mount->mount_entry),
|
||||
+ g_unix_mount_get_fs_type (mount->mount_entry));
|
||||
|
||||
- old = &(*old)->next;
|
||||
- new = new->next;
|
||||
+ trash_mount_free (mount);
|
||||
+ g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
}
|
||||
|
||||
- g_list_free (mounts);
|
||||
+ g_hash_table_destroy (mount_paths);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -345,7 +334,7 @@ trash_watcher_new (TrashRoot *root)
|
||||
|
||||
watcher = g_slice_new (TrashWatcher);
|
||||
watcher->root = root;
|
||||
- watcher->mounts = NULL;
|
||||
+ watcher->mounts = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
watcher->watching = FALSE;
|
||||
watcher->update_id = 0;
|
||||
watcher->mount_monitor = g_unix_mount_monitor_get ();
|
||||
@@ -385,19 +374,24 @@ trash_watcher_free (TrashWatcher *watcher)
|
||||
void
|
||||
trash_watcher_watch (TrashWatcher *watcher)
|
||||
{
|
||||
- TrashMount *mount;
|
||||
+ GHashTableIter iter;
|
||||
+ gpointer value;
|
||||
|
||||
g_assert (!watcher->watching);
|
||||
|
||||
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
|
||||
trash_dir_watch (watcher->homedir_trashdir);
|
||||
|
||||
- for (mount = watcher->mounts; mount; mount = mount->next)
|
||||
- if (mount->type != TRASH_WATCHER_NO_WATCH)
|
||||
- {
|
||||
- trash_dir_watch (mount->dirs[0]);
|
||||
- trash_dir_watch (mount->dirs[1]);
|
||||
- }
|
||||
+ g_hash_table_iter_init (&iter, watcher->mounts);
|
||||
+ while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
+ {
|
||||
+ TrashMount *mount = value;
|
||||
+ if (mount->type != TRASH_WATCHER_NO_WATCH)
|
||||
+ {
|
||||
+ trash_dir_watch (mount->dirs[0]);
|
||||
+ trash_dir_watch (mount->dirs[1]);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
watcher->watching = TRUE;
|
||||
}
|
||||
@@ -405,19 +399,24 @@ trash_watcher_watch (TrashWatcher *watcher)
|
||||
void
|
||||
trash_watcher_unwatch (TrashWatcher *watcher)
|
||||
{
|
||||
- TrashMount *mount;
|
||||
+ GHashTableIter iter;
|
||||
+ gpointer value;
|
||||
|
||||
g_assert (watcher->watching);
|
||||
|
||||
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
|
||||
trash_dir_unwatch (watcher->homedir_trashdir);
|
||||
|
||||
- for (mount = watcher->mounts; mount; mount = mount->next)
|
||||
- if (mount->type != TRASH_WATCHER_NO_WATCH)
|
||||
- {
|
||||
- trash_dir_unwatch (mount->dirs[0]);
|
||||
- trash_dir_unwatch (mount->dirs[1]);
|
||||
- }
|
||||
+ g_hash_table_iter_init (&iter, watcher->mounts);
|
||||
+ while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
+ {
|
||||
+ TrashMount *mount = value;
|
||||
+ if (mount->type != TRASH_WATCHER_NO_WATCH)
|
||||
+ {
|
||||
+ trash_dir_unwatch (mount->dirs[0]);
|
||||
+ trash_dir_unwatch (mount->dirs[1]);
|
||||
+ }
|
||||
+ }
|
||||
|
||||
watcher->watching = FALSE;
|
||||
}
|
||||
@@ -425,7 +424,8 @@ trash_watcher_unwatch (TrashWatcher *watcher)
|
||||
void
|
||||
trash_watcher_rescan (TrashWatcher *watcher)
|
||||
{
|
||||
- TrashMount *mount;
|
||||
+ GHashTableIter iter;
|
||||
+ gpointer value;
|
||||
|
||||
if (watcher->update_id != 0)
|
||||
{
|
||||
@@ -436,10 +436,14 @@ trash_watcher_rescan (TrashWatcher *watcher)
|
||||
if (!watcher->watching || watcher->homedir_type != TRASH_WATCHER_TRUSTED)
|
||||
trash_dir_rescan (watcher->homedir_trashdir);
|
||||
|
||||
- for (mount = watcher->mounts; mount; mount = mount->next)
|
||||
- if (!watcher->watching || mount->type != TRASH_WATCHER_TRUSTED)
|
||||
- {
|
||||
- trash_dir_rescan (mount->dirs[0]);
|
||||
- trash_dir_rescan (mount->dirs[1]);
|
||||
- }
|
||||
+ g_hash_table_iter_init (&iter, watcher->mounts);
|
||||
+ while (g_hash_table_iter_next (&iter, NULL, &value))
|
||||
+ {
|
||||
+ TrashMount *mount = value;
|
||||
+ if (!watcher->watching || mount->type != TRASH_WATCHER_TRUSTED)
|
||||
+ {
|
||||
+ trash_dir_rescan (mount->dirs[0]);
|
||||
+ trash_dir_rescan (mount->dirs[1]);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
--
|
||||
2.54.0
|
||||
|
||||
221
trash-Use-GHashTable-for-trash-directory-items.patch
Normal file
221
trash-Use-GHashTable-for-trash-directory-items.patch
Normal file
@ -0,0 +1,221 @@
|
||||
From 97d9831042ca1c5c13fdb6cd9bfb2e2fe77f94f8 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Wed, 3 Jun 2026 08:45:00 +0200
|
||||
Subject: [PATCH] trash: Use GHashTable for trash directory items
|
||||
|
||||
Backport of commit 665ff6b8.
|
||||
|
||||
Adjusted context for target version.
|
||||
---
|
||||
daemon/trashlib/trashdir.c | 122 +++++++++++++++----------------------
|
||||
1 file changed, 48 insertions(+), 74 deletions(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashdir.c b/daemon/trashlib/trashdir.c
|
||||
index 23aa0d7..610f2c3 100644
|
||||
--- a/daemon/trashlib/trashdir.c
|
||||
+++ b/daemon/trashlib/trashdir.c
|
||||
@@ -16,7 +16,7 @@
|
||||
struct OPAQUE_TYPE__TrashDir
|
||||
{
|
||||
TrashRoot *root;
|
||||
- GSList *items;
|
||||
+ GHashTable *items; /* basename -> GFile */
|
||||
|
||||
GFile *directory;
|
||||
GFile *topdir;
|
||||
@@ -27,28 +27,6 @@ struct OPAQUE_TYPE__TrashDir
|
||||
GFileMonitor *monitor;
|
||||
};
|
||||
|
||||
-static gint
|
||||
-compare_basename (gconstpointer a,
|
||||
- gconstpointer b)
|
||||
-{
|
||||
- GFile *file_a, *file_b;
|
||||
- char *name_a, *name_b;
|
||||
- gint result;
|
||||
-
|
||||
- file_a = (GFile *) a;
|
||||
- file_b = (GFile *) b;
|
||||
-
|
||||
- name_a = g_file_get_basename (file_a);
|
||||
- name_b = g_file_get_basename (file_b);
|
||||
-
|
||||
- result = strcmp (name_a, name_b);
|
||||
-
|
||||
- g_free (name_a);
|
||||
- g_free (name_b);
|
||||
-
|
||||
- return result;
|
||||
-}
|
||||
-
|
||||
static void
|
||||
trash_dir_query_mtime (TrashDir *dir, GTimeVal *mtime)
|
||||
{
|
||||
@@ -70,47 +48,36 @@ trash_dir_query_mtime (TrashDir *dir, GTimeVal *mtime)
|
||||
}
|
||||
|
||||
static void
|
||||
-trash_dir_set_files (TrashDir *dir,
|
||||
- GSList *items)
|
||||
+trash_dir_set_files (TrashDir *dir,
|
||||
+ GHashTable *items)
|
||||
{
|
||||
- GSList **old, *new;
|
||||
-
|
||||
- items = g_slist_sort (items, (GCompareFunc) compare_basename);
|
||||
- old = &dir->items;
|
||||
- new = items;
|
||||
+ GHashTableIter iter;
|
||||
+ gpointer key, value;
|
||||
|
||||
- while (new || *old)
|
||||
+ g_hash_table_iter_init (&iter, dir->items);
|
||||
+ while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
{
|
||||
- int result;
|
||||
-
|
||||
- if ((result = (new == NULL) - (*old == NULL)) == 0)
|
||||
- result = compare_basename (new->data, (*old)->data);
|
||||
-
|
||||
- if (result < 0)
|
||||
- {
|
||||
- /* new entry. add it. */
|
||||
- *old = g_slist_prepend (*old, new->data); /* take reference */
|
||||
- old = &(*old)->next;
|
||||
- trash_root_add_item (dir->root, new->data, dir->topdir, dir->is_homedir);
|
||||
- new = new->next;
|
||||
- }
|
||||
- else if (result > 0)
|
||||
+ if (!g_hash_table_contains (items, key))
|
||||
{
|
||||
/* old entry. remove it. */
|
||||
- trash_root_remove_item (dir->root, (*old)->data, dir->is_homedir);
|
||||
- g_object_unref ((*old)->data);
|
||||
- *old = g_slist_delete_link (*old, *old);
|
||||
+ trash_root_remove_item (dir->root, value, dir->is_homedir);
|
||||
+ g_hash_table_iter_remove (&iter);
|
||||
}
|
||||
- else
|
||||
+ }
|
||||
+
|
||||
+ g_hash_table_iter_init (&iter, items);
|
||||
+ while (g_hash_table_iter_next (&iter, &key, &value))
|
||||
+ {
|
||||
+ if (!g_hash_table_contains (dir->items, key))
|
||||
{
|
||||
- /* match. no change. */
|
||||
- old = &(*old)->next;
|
||||
- g_object_unref (new->data);
|
||||
- new = new->next;
|
||||
+ /* new entry. add it. */
|
||||
+ g_hash_table_iter_steal (&iter);
|
||||
+ g_hash_table_insert (dir->items, key, value);
|
||||
+ trash_root_add_item (dir->root, value, dir->topdir, dir->is_homedir);
|
||||
}
|
||||
}
|
||||
|
||||
- g_slist_free (items);
|
||||
+ g_hash_table_unref (items);
|
||||
|
||||
trash_root_thaw (dir->root);
|
||||
}
|
||||
@@ -118,16 +85,23 @@ trash_dir_set_files (TrashDir *dir,
|
||||
static void
|
||||
trash_dir_empty (TrashDir *dir)
|
||||
{
|
||||
- trash_dir_set_files (dir, NULL);
|
||||
+ GHashTable *empty;
|
||||
+
|
||||
+ empty = g_hash_table_new (g_str_hash, g_str_equal);
|
||||
+ trash_dir_set_files (dir, empty);
|
||||
}
|
||||
|
||||
static void
|
||||
trash_dir_enumerate (TrashDir *dir)
|
||||
{
|
||||
GFileEnumerator *enumerator;
|
||||
- GSList *files = NULL;
|
||||
+ GHashTable *files = NULL;
|
||||
|
||||
trash_dir_query_mtime (dir, &dir->mtime);
|
||||
+
|
||||
+ files = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
+ g_free, g_object_unref);
|
||||
+
|
||||
enumerator = g_file_enumerate_children (dir->directory,
|
||||
G_FILE_ATTRIBUTE_STANDARD_NAME,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
@@ -140,10 +113,11 @@ trash_dir_enumerate (TrashDir *dir)
|
||||
while ((info = g_file_enumerator_next_file (enumerator, NULL, NULL)))
|
||||
{
|
||||
GFile *file;
|
||||
+ const gchar *name;
|
||||
|
||||
- file = g_file_get_child (dir->directory,
|
||||
- g_file_info_get_name (info));
|
||||
- files = g_slist_prepend (files, file);
|
||||
+ name = g_file_info_get_name (info);
|
||||
+ file = g_file_get_child (dir->directory, name);
|
||||
+ g_hash_table_insert (files, g_strdup (name), file);
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
@@ -165,24 +139,20 @@ trash_dir_changed (GFileMonitor *monitor,
|
||||
|
||||
if (event_type == G_FILE_MONITOR_EVENT_CREATED)
|
||||
{
|
||||
- dir->items = g_slist_insert_sorted (dir->items,
|
||||
- g_object_ref (file),
|
||||
- (GCompareFunc) compare_basename);
|
||||
- trash_root_add_item (dir->root, file, dir->topdir, dir->is_homedir);
|
||||
+ g_autofree gchar *name = g_file_get_basename (file);
|
||||
+
|
||||
+ if (!g_hash_table_contains (dir->items, name))
|
||||
+ {
|
||||
+ g_hash_table_insert (dir->items, g_steal_pointer (&name), g_object_ref (file));
|
||||
+ trash_root_add_item (dir->root, file, dir->topdir, dir->is_homedir);
|
||||
+ }
|
||||
}
|
||||
|
||||
else if (event_type == G_FILE_MONITOR_EVENT_DELETED)
|
||||
{
|
||||
- GSList *node;
|
||||
+ g_autofree char *name = g_file_get_basename (file);
|
||||
|
||||
- node = g_slist_find_custom (dir->items,
|
||||
- file,
|
||||
- (GCompareFunc) compare_basename);
|
||||
- if (node)
|
||||
- {
|
||||
- g_object_unref (node->data);
|
||||
- dir->items = g_slist_delete_link (dir->items, node);
|
||||
- }
|
||||
+ g_hash_table_remove (dir->items, name);
|
||||
trash_root_remove_item (dir->root, file, dir->is_homedir);
|
||||
}
|
||||
|
||||
@@ -386,7 +356,8 @@ trash_dir_new (TrashRoot *root,
|
||||
dir = g_slice_new (TrashDir);
|
||||
|
||||
dir->root = root;
|
||||
- dir->items = NULL;
|
||||
+ dir->items = g_hash_table_new_full (g_str_hash, g_str_equal,
|
||||
+ g_free, g_object_unref);
|
||||
dir->topdir = g_file_new_for_path (mount_point);
|
||||
dir->directory = g_file_get_child (dir->topdir, rel);
|
||||
dir->monitor = NULL;
|
||||
@@ -416,7 +387,9 @@ trash_dir_free (TrashDir *dir)
|
||||
if (dir->monitor)
|
||||
g_object_unref (dir->monitor);
|
||||
|
||||
- trash_dir_set_files (dir, NULL);
|
||||
+ trash_dir_empty (dir);
|
||||
+
|
||||
+ g_hash_table_unref (dir->items);
|
||||
|
||||
g_object_unref (dir->directory);
|
||||
g_object_unref (dir->topdir);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
223
trash-Use-weak-refs-for-monitor-lifecycle.patch
Normal file
223
trash-Use-weak-refs-for-monitor-lifecycle.patch
Normal file
@ -0,0 +1,223 @@
|
||||
From b15490d80dc8044dd546c8f5fba171bacb92c49c Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 15:54:17 +0200
|
||||
Subject: [PATCH] trash: Use weak refs for monitor lifecycle
|
||||
|
||||
Backport of commit 1080ca11.
|
||||
|
||||
Adjusted context for target version.
|
||||
---
|
||||
daemon/gvfsbackendtrash.c | 119 ++++++++++++++++++++++-----------
|
||||
daemon/trashlib/trashwatcher.c | 6 +-
|
||||
2 files changed, 84 insertions(+), 41 deletions(-)
|
||||
|
||||
diff --git a/daemon/gvfsbackendtrash.c b/daemon/gvfsbackendtrash.c
|
||||
index 1dcb44f..6d0af56 100644
|
||||
--- a/daemon/gvfsbackendtrash.c
|
||||
+++ b/daemon/gvfsbackendtrash.c
|
||||
@@ -33,8 +33,8 @@ struct OPAQUE_TYPE__GVfsBackendTrash
|
||||
{
|
||||
GVfsBackend parent_instance;
|
||||
|
||||
- GVfsMonitor *file_monitor;
|
||||
- GVfsMonitor *dir_monitor;
|
||||
+ GWeakRef file_monitor;
|
||||
+ GWeakRef dir_monitor;
|
||||
|
||||
GMainContext *worker_context;
|
||||
GMainLoop *worker_loop;
|
||||
@@ -111,15 +111,32 @@ trash_backend_worker_thread_queue (GVfsBackendTrash *backend,
|
||||
}
|
||||
|
||||
static gboolean
|
||||
-watch_func (gpointer user_data)
|
||||
+sync_watch_state_func (gpointer user_data)
|
||||
{
|
||||
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (user_data);
|
||||
+ GVfsMonitor *file_monitor;
|
||||
+ GVfsMonitor *dir_monitor;
|
||||
|
||||
- trash_watcher_watch (backend->watcher);
|
||||
+ file_monitor = g_weak_ref_get (&backend->file_monitor);
|
||||
+ dir_monitor = g_weak_ref_get (&backend->dir_monitor);
|
||||
+
|
||||
+ if (file_monitor != NULL || dir_monitor != NULL)
|
||||
+ trash_watcher_watch (backend->watcher);
|
||||
+ else
|
||||
+ trash_watcher_unwatch (backend->watcher);
|
||||
+
|
||||
+ g_clear_object (&file_monitor);
|
||||
+ g_clear_object (&dir_monitor);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
+static void
|
||||
+trash_backend_queue_watch_state_sync (GVfsBackendTrash *backend)
|
||||
+{
|
||||
+ trash_backend_worker_thread_queue (backend, sync_watch_state_func);
|
||||
+}
|
||||
+
|
||||
static gboolean
|
||||
rescan_func (gpointer user_data)
|
||||
{
|
||||
@@ -142,46 +159,62 @@ is_root (const char *filename)
|
||||
return (filename[0] == '/' && filename[1] == '\0');
|
||||
}
|
||||
|
||||
+static void
|
||||
+trash_backend_file_monitor_destroyed (gpointer data,
|
||||
+ GObject *where_the_object_was)
|
||||
+{
|
||||
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (data);
|
||||
+
|
||||
+ trash_backend_queue_watch_state_sync (backend);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+trash_backend_dir_monitor_destroyed (gpointer data,
|
||||
+ GObject *where_the_object_was)
|
||||
+{
|
||||
+ GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (data);
|
||||
+
|
||||
+ trash_backend_queue_watch_state_sync (backend);
|
||||
+}
|
||||
+
|
||||
static GVfsMonitor *
|
||||
trash_backend_get_file_monitor (GVfsBackendTrash *backend,
|
||||
gboolean create)
|
||||
{
|
||||
- if (backend->file_monitor == NULL && create == FALSE)
|
||||
- return NULL;
|
||||
+ GVfsMonitor *monitor;
|
||||
|
||||
- else if (backend->file_monitor == NULL)
|
||||
- {
|
||||
- /* 'create' is only ever set in the main thread, so we will have
|
||||
- * no possibility here for creating more than one new monitor.
|
||||
- */
|
||||
- if (backend->dir_monitor == NULL)
|
||||
- trash_backend_worker_thread_queue (backend, watch_func);
|
||||
+ monitor = g_weak_ref_get (&backend->file_monitor);
|
||||
+ if (monitor != NULL || create == FALSE)
|
||||
+ return monitor;
|
||||
|
||||
- backend->file_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
|
||||
- }
|
||||
+ monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
|
||||
+ g_weak_ref_set (&backend->file_monitor, monitor);
|
||||
+ g_object_weak_ref (G_OBJECT (monitor),
|
||||
+ trash_backend_file_monitor_destroyed, backend);
|
||||
+
|
||||
+ trash_backend_queue_watch_state_sync (backend);
|
||||
|
||||
- return g_object_ref (backend->file_monitor);
|
||||
+ return monitor;
|
||||
}
|
||||
|
||||
static GVfsMonitor *
|
||||
trash_backend_get_dir_monitor (GVfsBackendTrash *backend,
|
||||
gboolean create)
|
||||
{
|
||||
- if (backend->dir_monitor == NULL && create == FALSE)
|
||||
- return NULL;
|
||||
+ GVfsMonitor *monitor;
|
||||
|
||||
- else if (backend->dir_monitor == NULL)
|
||||
- {
|
||||
- /* 'create' is only ever set in the main thread, so we will have
|
||||
- * no possibility here for creating more than one new monitor.
|
||||
- */
|
||||
- if (backend->file_monitor == NULL)
|
||||
- trash_backend_worker_thread_queue (backend, watch_func);
|
||||
+ monitor = g_weak_ref_get (&backend->dir_monitor);
|
||||
+ if (monitor != NULL || create == FALSE)
|
||||
+ return monitor;
|
||||
|
||||
- backend->dir_monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
|
||||
- }
|
||||
+ monitor = g_vfs_monitor_new (G_VFS_BACKEND (backend));
|
||||
+ g_weak_ref_set (&backend->dir_monitor, monitor);
|
||||
+ g_object_weak_ref (G_OBJECT (monitor),
|
||||
+ trash_backend_dir_monitor_destroyed, backend);
|
||||
+
|
||||
+ trash_backend_queue_watch_state_sync (backend);
|
||||
|
||||
- return g_object_ref (backend->dir_monitor);
|
||||
+ return monitor;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -802,8 +835,8 @@ trash_backend_mount (GVfsBackend *vfs_backend,
|
||||
{
|
||||
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (vfs_backend);
|
||||
|
||||
- backend->file_monitor = NULL;
|
||||
- backend->dir_monitor = NULL;
|
||||
+ g_weak_ref_init (&backend->file_monitor, NULL);
|
||||
+ g_weak_ref_init (&backend->dir_monitor, NULL);
|
||||
|
||||
backend->worker_context = g_main_context_new ();
|
||||
backend->worker_thread = g_thread_new ("Trash Worker Thread",
|
||||
@@ -976,17 +1009,25 @@ static void
|
||||
trash_backend_finalize (GObject *object)
|
||||
{
|
||||
GVfsBackendTrash *backend = G_VFS_BACKEND_TRASH (object);
|
||||
+ GVfsMonitor *monitor;
|
||||
|
||||
- /* get rid of these first to stop a flood of event notifications
|
||||
- * from being emitted while we're tearing down the TrashWatcher
|
||||
- */
|
||||
- if (backend->file_monitor)
|
||||
- g_object_unref (backend->file_monitor);
|
||||
- backend->file_monitor = NULL;
|
||||
+ monitor = g_weak_ref_get (&backend->file_monitor);
|
||||
+ if (monitor != NULL)
|
||||
+ {
|
||||
+ g_object_weak_unref (G_OBJECT (monitor),
|
||||
+ trash_backend_file_monitor_destroyed, backend);
|
||||
+ g_object_unref (monitor);
|
||||
+ }
|
||||
+ g_weak_ref_clear (&backend->file_monitor);
|
||||
|
||||
- if (backend->dir_monitor)
|
||||
- g_object_unref (backend->dir_monitor);
|
||||
- backend->dir_monitor = NULL;
|
||||
+ monitor = g_weak_ref_get (&backend->dir_monitor);
|
||||
+ if (monitor != NULL)
|
||||
+ {
|
||||
+ g_object_weak_unref (G_OBJECT (monitor),
|
||||
+ trash_backend_dir_monitor_destroyed, backend);
|
||||
+ g_object_unref (monitor);
|
||||
+ }
|
||||
+ g_weak_ref_clear (&backend->dir_monitor);
|
||||
|
||||
G_OBJECT_CLASS (g_vfs_backend_trash_parent_class)->finalize (object);
|
||||
}
|
||||
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
|
||||
index 1888bed..bd658e1 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -378,7 +378,8 @@ trash_watcher_watch (TrashWatcher *watcher)
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
|
||||
- g_assert (!watcher->watching);
|
||||
+ if (watcher->watching)
|
||||
+ return;
|
||||
|
||||
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
|
||||
trash_dir_watch (watcher->homedir_trashdir);
|
||||
@@ -403,7 +404,8 @@ trash_watcher_unwatch (TrashWatcher *watcher)
|
||||
GHashTableIter iter;
|
||||
gpointer value;
|
||||
|
||||
- g_assert (watcher->watching);
|
||||
+ if (!watcher->watching)
|
||||
+ return;
|
||||
|
||||
if (watcher->homedir_type != TRASH_WATCHER_NO_WATCH)
|
||||
trash_dir_unwatch (watcher->homedir_trashdir);
|
||||
--
|
||||
2.53.0
|
||||
|
||||
Loading…
Reference in New Issue
Block a user