gvfs/trash-Use-GHashTable-for-mount-tracking.patch
Ondrej Holy f53f2a2fed Improve trash backend performance
Resolves: RHEL-138575
2026-06-03 12:29:54 +02:00

281 lines
8.7 KiB
Diff

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