Improve trash backend performance
Resolves: RHEL-138575
This commit is contained in:
parent
862bb9e6e0
commit
f53f2a2fed
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
|
||||
|
||||
19
gvfs.spec
19
gvfs.spec
@ -22,7 +22,7 @@
|
||||
|
||||
Name: gvfs
|
||||
Version: 1.54.4
|
||||
Release: 4%{?dist}
|
||||
Release: 5%{?dist}
|
||||
Summary: Backends for the gio framework in GLib
|
||||
|
||||
License: LGPL-2.0-or-later AND GPL-3.0-only AND MPL-2.0 AND BSD-3-Clause-Sun
|
||||
@ -49,6 +49,19 @@ Patch: udisks2-monitor-performance-273.patch
|
||||
Patch: udisks2-monitor-performance-290.patch
|
||||
Patch: udisks2-monitor-performance-297.patch
|
||||
|
||||
# Improve trash backend performance
|
||||
# https://gitlab.gnome.org/GNOME/gvfs/-/merge_requests/287
|
||||
Patch: trash-Rate-limit-mount-updates.patch
|
||||
Patch: trash-Add-debug-prints-for-mounts-handling.patch
|
||||
Patch: trash-Use-GHashTable-for-mount-tracking.patch
|
||||
Patch: trash-Use-GHashTable-for-trash-directory-items.patch
|
||||
Patch: trash-Rate-limit-size-change-notifications.patch
|
||||
Patch: trash-Chain-up-finalize.patch
|
||||
Patch: trash-Use-weak-refs-for-monitor-lifecycle.patch
|
||||
Patch: trash-Defer-mount-monitoring-to-active-watchers-only.patch
|
||||
Patch: daemon-Add-process-name-to-debug-handler-log.patch
|
||||
Patch: trash-Skip-mount-table-reparsing-when-unchanged.patch
|
||||
|
||||
BuildRequires: meson
|
||||
BuildRequires: gcc
|
||||
BuildRequires: pkgconfig(glib-2.0) >= %{glib2_version}
|
||||
@ -450,6 +463,10 @@ killall -USR1 gvfsd >&/dev/null || :
|
||||
|
||||
|
||||
%changelog
|
||||
* Tue Jun 02 2026 Ondrej Holy <oholy@redhat.com> - 1.54.4-5
|
||||
- Improve trash backend performance
|
||||
Resolves: RHEL-138575
|
||||
|
||||
* Fri Feb 06 2026 Milan Crha <mcrha@redhat.com> - 1.54.4-4
|
||||
- udisks2: Correct add to hash table for items which can clash in the monitor (RHEL-143935)
|
||||
|
||||
|
||||
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 18e795eda715947b42a940b277a51b8e36b64062 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 16:01:09 +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 506d03c..21809f2 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -279,12 +279,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
|
||||
@@ -305,6 +315,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);
|
||||
@@ -315,6 +327,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
|
||||
|
||||
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 c6d70b441f9c6f50a844808e6ebfa0651b0a7f8f Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 16:01:50 +0200
|
||||
Subject: [PATCH] trash: Defer mount monitoring to active watchers only
|
||||
|
||||
Backport of commit b53d45db.
|
||||
|
||||
Adjusted context for target version.
|
||||
---
|
||||
daemon/trashlib/trashwatcher.c | 24 +++++++++++++++++++++---
|
||||
1 file changed, 21 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/daemon/trashlib/trashwatcher.c b/daemon/trashlib/trashwatcher.c
|
||||
index 3c1aea1..60410df 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -141,6 +141,7 @@ struct OPAQUE_TYPE__TrashWatcher
|
||||
TrashRoot *root;
|
||||
|
||||
GUnixMountMonitor *mount_monitor;
|
||||
+ gulong mounts_changed_id;
|
||||
GHashTable *mounts; /* mount_path -> TrashMount */
|
||||
guint update_id;
|
||||
|
||||
@@ -345,8 +346,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");
|
||||
@@ -384,9 +384,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);
|
||||
|
||||
@@ -410,9 +418,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);
|
||||
|
||||
@@ -436,7 +452,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
|
||||
|
||||
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
|
||||
|
||||
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 163dc91fe3c1b6fac6d8aed947b66d8c32ccc010 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 16:01:50 +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 60410df..93e1fae 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -144,6 +144,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;
|
||||
@@ -247,7 +248,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)
|
||||
@@ -345,6 +349,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 0d3023a9e7303c7786f6510643fb7cad62e36568 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 16:01:50 +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 21809f2..72b67e4 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -141,7 +141,7 @@ struct OPAQUE_TYPE__TrashWatcher
|
||||
TrashRoot *root;
|
||||
|
||||
GUnixMountMonitor *mount_monitor;
|
||||
- TrashMount *mounts;
|
||||
+ GHashTable *mounts; /* mount_path -> TrashMount */
|
||||
guint update_id;
|
||||
|
||||
TrashDir *homedir_trashdir;
|
||||
@@ -155,16 +155,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;
|
||||
@@ -194,24 +191,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);
|
||||
}
|
||||
@@ -251,63 +239,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
|
||||
@@ -347,7 +341,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 ();
|
||||
@@ -387,19 +381,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;
|
||||
}
|
||||
@@ -407,19 +406,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;
|
||||
}
|
||||
@@ -427,7 +431,8 @@ trash_watcher_unwatch (TrashWatcher *watcher)
|
||||
void
|
||||
trash_watcher_rescan (TrashWatcher *watcher)
|
||||
{
|
||||
- TrashMount *mount;
|
||||
+ GHashTableIter iter;
|
||||
+ gpointer value;
|
||||
|
||||
if (watcher->update_id != 0)
|
||||
{
|
||||
@@ -438,10 +443,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.53.0
|
||||
|
||||
222
trash-Use-GHashTable-for-trash-directory-items.patch
Normal file
222
trash-Use-GHashTable-for-trash-directory-items.patch
Normal file
@ -0,0 +1,222 @@
|
||||
From 6cc1d7aa763dfbd6103429313b5af025ebb68e50 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 16:01:50 +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 707dff6..6b5f21c 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 GDateTime *
|
||||
trash_dir_query_mtime (TrashDir *dir)
|
||||
{
|
||||
@@ -68,47 +46,36 @@ trash_dir_query_mtime (TrashDir *dir)
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -116,17 +83,24 @@ 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;
|
||||
|
||||
g_clear_pointer (&dir->mtime, g_date_time_unref);
|
||||
dir->mtime = trash_dir_query_mtime (dir);
|
||||
+
|
||||
+ 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,
|
||||
@@ -139,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);
|
||||
}
|
||||
@@ -164,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);
|
||||
}
|
||||
|
||||
@@ -392,7 +363,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;
|
||||
@@ -423,7 +395,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 0807d43c845796bf7260480c0349ca523932f953 Mon Sep 17 00:00:00 2001
|
||||
From: Ondrej Holy <oholy@redhat.com>
|
||||
Date: Tue, 2 Jun 2026 16:01:50 +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 72b67e4..3c1aea1 100644
|
||||
--- a/daemon/trashlib/trashwatcher.c
|
||||
+++ b/daemon/trashlib/trashwatcher.c
|
||||
@@ -384,7 +384,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);
|
||||
@@ -409,7 +410,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