From 94a189ee9b086c2f0105cfd80c6a61588f7ffe87 Mon Sep 17 00:00:00 2001 From: Ray Strode Date: Mon, 2 May 2022 15:05:50 -0400 Subject: [PATCH] libtracker-miner: Properly detect fanotify failures commit 28142bdb5e3b96e0e7328322f3a880d97a6cdca0 makes trackers file monitoring code fall back to GLib file monitors, if fanotify doesn't work. Unfortunately, fanotify_mark failures aren't propagated up, so the fall back code doesn't get triggered in some cases. This commit adds the plumbing to make the fall back code get propagated. --- src/libtracker-miner/tracker-monitor-fanotify.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/libtracker-miner/tracker-monitor-fanotify.c b/src/libtracker-miner/tracker-monitor-fanotify.c index 7da262e89..9c6755d4a 100644 --- a/src/libtracker-miner/tracker-monitor-fanotify.c +++ b/src/libtracker-miner/tracker-monitor-fanotify.c @@ -80,60 +80,61 @@ typedef struct { } HandleData; typedef struct { TrackerMonitorFanotify *monitor; GFile *file; GBytes *handle_bytes; /* This must be last in the struct */ HandleData handle; } MonitoredFile; enum { ITEM_CREATED, ITEM_UPDATED, ITEM_ATTRIBUTE_UPDATED, ITEM_DELETED, ITEM_MOVED, LAST_SIGNAL }; enum { PROP_0, PROP_ENABLED, PROP_LIMIT, PROP_COUNT, PROP_IGNORED, }; static GInitableIface *initable_parent_iface = NULL; static void tracker_monitor_fanotify_initable_iface_init (GInitableIface *iface); +static void monitored_file_free (MonitoredFile *data); G_DEFINE_TYPE_WITH_CODE (TrackerMonitorFanotify, tracker_monitor_fanotify, TRACKER_TYPE_MONITOR_GLIB, G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, tracker_monitor_fanotify_initable_iface_init)) static inline const char * event_type_to_string (EventType evtype) { switch (evtype) { case EVENT_CREATE: return "CREATE"; case EVENT_UPDATE: return "UPDATE"; case EVENT_ATTRIBUTES_UPDATE: return "ATTRIBUTES_UPDATE"; case EVENT_DELETE: return "DELETE"; case EVENT_MOVE: return "MOVE"; default: g_assert_not_reached (); } } static void emit_event (TrackerMonitorFanotify *monitor, EventType evtype, GFile *file, GFile *other_file, @@ -532,153 +533,161 @@ tracker_monitor_fanotify_set_property (GObject *object, G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } static void tracker_monitor_fanotify_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { TrackerMonitorFanotify *monitor = TRACKER_MONITOR_FANOTIFY (object); switch (prop_id) { case PROP_ENABLED: g_value_set_boolean (value, monitor->enabled); break; case PROP_LIMIT: g_value_set_uint (value, monitor->limit); break; case PROP_COUNT: g_value_set_uint (value, tracker_monitor_get_count (TRACKER_MONITOR (object))); break; case PROP_IGNORED: g_value_set_uint (value, monitor->ignored); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); } } -static void +static gboolean add_mark (TrackerMonitorFanotify *monitor, GFile *file) { gchar *path; path = g_file_get_path (file); if (fanotify_mark (monitor->fanotify_fd, (FAN_MARK_ADD | FAN_MARK_ONLYDIR), FANOTIFY_EVENTS, AT_FDCWD, path) < 0) { g_warning ("Could not add mark for path '%s': %m", path); + return FALSE; } g_free (path); + return TRUE; } static void remove_mark (TrackerMonitorFanotify *monitor, GFile *file) { gchar *path; path = g_file_get_path (file); if (fanotify_mark (monitor->fanotify_fd, FAN_MARK_REMOVE, FANOTIFY_EVENTS, AT_FDCWD, path) < 0) { if (errno != ENOENT) g_warning ("Could not remove mark for path '%s': %m", path); } g_free (path); } static MonitoredFile * monitored_file_new (TrackerMonitorFanotify *monitor, GFile *file) { MonitoredFile *data; gchar *path; struct statfs buf; int mntid; + gboolean mark_added = FALSE; path = g_file_get_path (file); if (statfs (path, &buf) < 0) { if (errno != ENOENT) g_warning ("Could not get filesystem ID for %s: %m", path); g_free (path); return NULL; } retry: /* We need to try different sizes for the file_handle data */ data = g_slice_alloc0 (sizeof (MonitoredFile) + monitor->file_handle_payload); data->handle.handle.handle_bytes = monitor->file_handle_payload; if (name_to_handle_at (AT_FDCWD, path, (void *) &data->handle.handle, &mntid, 0) < 0) { if (errno == EOVERFLOW) { ssize_t payload; /* The payload is not big enough to hold a file_handle, * in this case we get the ideal handle data size, so * fetch that and retry. */ payload = data->handle.handle.handle_bytes; g_slice_free1 (sizeof (MonitoredFile) + monitor->file_handle_payload, data); monitor->file_handle_payload = payload; goto retry; } else if (errno != ENOENT) { g_warning ("Could not get file handle for '%s': %m", path); } g_free (path); return NULL; } data->file = g_object_ref (file); data->monitor = monitor; memcpy (&data->handle.fsid, &buf.f_fsid, sizeof(fsid_t)); - add_mark (monitor, file); + mark_added = add_mark (monitor, file); g_free (path); data->handle_bytes = create_bytes_for_handle (&data->handle); + if (!mark_added) { + monitored_file_free (data); + data = NULL; + } + return data; } static void monitored_file_free (MonitoredFile *data) { if (!data) return; g_bytes_unref (data->handle_bytes); remove_mark (data->monitor, data->file); g_object_unref (data->file); g_slice_free1 (sizeof (MonitoredFile) + data->handle.handle.handle_bytes, data); } static gboolean tracker_monitor_fanotify_add (TrackerMonitor *object, GFile *file) { TrackerMonitorFanotify *monitor = TRACKER_MONITOR_FANOTIFY (object); MonitoredFile *data; if (g_hash_table_contains (monitor->monitored_dirs, file)) return TRUE; if (g_hash_table_size (monitor->monitored_dirs) > monitor->limit) { monitor->ignored++; return FALSE; } -- 2.35.1