git/compat/fsmonitor
Paul Tarjan ce48de8b2c fsmonitor: implement filesystem change listener for Linux
Implement the built-in fsmonitor daemon for Linux using the inotify
API, bringing it to feature parity with the existing Windows and macOS
implementations.

The implementation uses inotify rather than fanotify because fanotify
requires either CAP_SYS_ADMIN or CAP_PERFMON capabilities, making it
unsuitable for an unprivileged user-space daemon.  While inotify has
the limitation of requiring a separate watch on every directory (unlike
macOS's FSEvents, which can monitor an entire directory tree with a
single watch), it operates without elevated privileges and provides
the per-file event granularity needed for fsmonitor.

The listener uses inotify_init1(O_NONBLOCK) with a poll loop that
checks for events with a 50-millisecond timeout, keeping the inotify
queue well-drained to minimize the risk of overflows.  Bidirectional
hashmaps map between watch descriptors and directory paths for efficient
event resolution.  Directory renames are tracked using inotify's cookie
mechanism to correlate IN_MOVED_FROM and IN_MOVED_TO event pairs; a
periodic check detects stale renames where the matching IN_MOVED_TO
never arrived, forcing a resync.

New directory creation triggers recursive watch registration to ensure
all subdirectories are monitored.  The IN_MASK_CREATE flag is used
where available to prevent modifying existing watches, with a fallback
for older kernels.  When IN_MASK_CREATE is available and
inotify_add_watch returns EEXIST, it means another thread or recursive
scan has already registered the watch, so it is safe to ignore.

Remote filesystem detection uses statfs() to identify network-mounted
filesystems (NFS, CIFS, SMB, FUSE, etc.) via their magic numbers.
Mount point information is read from /proc/mounts and matched against
the statfs f_fsid to get accurate, human-readable filesystem type names
for logging.  When the .git directory is on a remote filesystem, the
IPC socket falls back to $HOME or a user-configured directory via the
fsmonitor.socketDir setting.

Based-on-patch-by: Eric DeCosta <edecosta@mathworks.com>
Based-on-patch-by: Marziyeh Esipreh <marziyeh.esipreh@gmail.com>
Signed-off-by: Paul Tarjan <github@paulisageek.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2026-04-15 08:44:33 -07:00
..
fsm-darwin-gcc.h fsmonitor: eliminate call to deprecated FSEventStream function 2022-12-15 09:08:27 +09:00
fsm-health-darwin.c fsmonitor: mark unused parameters in stub functions 2023-09-18 15:56:15 -07:00
fsm-health-linux.c fsmonitor: implement filesystem change listener for Linux 2026-04-15 08:44:33 -07:00
fsm-health-win32.c fsmonitor--daemon.h: remove unnecessary includes 2023-12-26 12:04:32 -08:00
fsm-health.h fsmonitor--daemon: stub in health thread 2022-05-26 15:59:27 -07:00
fsm-ipc-unix.c fsmonitor: rename fsm-ipc-darwin.c to fsm-ipc-unix.c 2026-04-15 08:44:33 -07:00
fsm-ipc-win32.c fsmonitor: prefer repo_git_path() to git_pathdup() 2023-09-18 15:56:14 -07:00
fsm-listen-darwin.c global: trivial conversions to fix `-Wsign-compare` warnings 2024-12-06 20:20:04 +09:00
fsm-listen-linux.c fsmonitor: implement filesystem change listener for Linux 2026-04-15 08:44:33 -07:00
fsm-listen-win32.c Merge branch 'ak/typofixes' 2024-10-25 14:02:04 -04:00
fsm-listen.h fsmonitor--daemon: rename listener thread related variables 2022-05-26 15:59:26 -07:00
fsm-path-utils-darwin.c fsmonitor-ll.h: split this header out of fsmonitor.h 2023-06-21 13:39:54 -07:00
fsm-path-utils-linux.c fsmonitor: implement filesystem change listener for Linux 2026-04-15 08:44:33 -07:00
fsm-path-utils-win32.c fsmonitor: mark unused parameters in stub functions 2023-09-18 15:56:15 -07:00
fsm-settings-unix.c fsmonitor: rename fsm-settings-darwin.c to fsm-settings-unix.c 2026-04-15 08:44:33 -07:00
fsm-settings-win32.c fsmonitor/win32: mark unused parameter in fsm_os__incompatible() 2023-09-18 15:56:15 -07:00