fsmonitor-settings: remote repos on macOS are incompatible

Teach Git to detect remote working directories on macOS and mark them as incompatible with FSMonitor. With this, `git fsmonitor--daemon run` will error out with a message like it does for bare repos. Client commands, like `git status`, will not attempt to start the daemon. Signed-off-by: Jeff Hostetler <jeffhost@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff Hostetler committed May 26, 2022 at 21:47 UTC 1e7be10de0d493f471bf102a7eed32da8247c825
3 files changed +80
compat/fsmonitor/fsm-settings-darwin.c
+66
@@ -2,8 +2,74 @@
2 #include "config.h"
3 #include "repository.h"
4 #include "fsmonitor-settings.h"
5 +#include "fsmonitor.h"
6 +#include <sys/param.h>
7 +#include <sys/mount.h>
8 +
9 +/*
10 + * Remote working directories are problematic for FSMonitor.
11 + *
12 + * The underlying file system on the server machine and/or the remote
13 + * mount type (NFS, SAMBA, etc.) dictates whether notification events
14 + * are available at all to remote client machines.
15 + *
16 + * Kernel differences between the server and client machines also
17 + * dictate the how (buffering, frequency, de-dup) the events are
18 + * delivered to client machine processes.
19 + *
20 + * A client machine (such as a laptop) may choose to suspend/resume
21 + * and it is unclear (without lots of testing) whether the watcher can
22 + * resync after a resume. We might be able to treat this as a normal
23 + * "events were dropped by the kernel" event and do our normal "flush
24 + * and resync" --or-- we might need to close the existing (zombie?)
25 + * notification fd and create a new one.
26 + *
27 + * In theory, the above issues need to be addressed whether we are
28 + * using the Hook or IPC API.
29 + *
30 + * For the builtin FSMonitor, we create the Unix domain socket for the
31 + * IPC in the .git directory. If the working directory is remote,
32 + * then the socket will be created on the remote file system. This
33 + * can fail if the remote file system does not support UDS file types
34 + * (e.g. smbfs to a Windows server) or if the remote kernel does not
35 + * allow a non-local process to bind() the socket. (These problems
36 + * could be fixed by moving the UDS out of the .git directory and to a
37 + * well-known local directory on the client machine, but care should
38 + * be taken to ensure that $HOME is actually local and not a managed
39 + * file share.)
40 + *
41 + * So (for now at least), mark remote working directories as
42 + * incompatible.
43 + */
44 +static enum fsmonitor_reason check_remote(struct repository *r)
45 +{
46 + struct statfs fs;
47 +
48 + if (statfs(r->worktree, &fs) == -1) {
49 + int saved_errno = errno;
50 + trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s",
51 + r->worktree, strerror(saved_errno));
52 + errno = saved_errno;
53 + return FSMONITOR_REASON_ERROR;
54 + }
55 +
56 + trace_printf_key(&trace_fsmonitor,
57 + "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'",
58 + r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename);
59 +
60 + if (!(fs.f_flags & MNT_LOCAL))
61 + return FSMONITOR_REASON_REMOTE;
62 +
63 + return FSMONITOR_REASON_OK;
64 +}
65
66 enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
67 {
68 + enum fsmonitor_reason reason;
69 +
70 + reason = check_remote(r);
71 + if (reason != FSMONITOR_REASON_OK)
72 + return reason;
73 +
74 return FSMONITOR_REASON_OK;
75 }
fsmonitor-settings.c
+12
@@ -208,6 +208,18 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r,
208 xgetcwd());
209 goto done;
210
211 + case FSMONITOR_REASON_ERROR:
212 + strbuf_addf(&msg,
213 + _("repository '%s' is incompatible with fsmonitor due to errors"),
214 + r->worktree);
215 + goto done;
216 +
217 + case FSMONITOR_REASON_REMOTE:
218 + strbuf_addf(&msg,
219 + _("remote repository '%s' is incompatible with fsmonitor"),
220 + r->worktree);
221 + goto done;
222 +
223 case FSMONITOR_REASON_VFS4GIT:
224 strbuf_addf(&msg,
225 _("virtual repository '%s' is incompatible with fsmonitor"),
fsmonitor-settings.h
+2
@@ -17,6 +17,8 @@ enum fsmonitor_reason {
17 FSMONITOR_REASON_UNTESTED = 0,
18 FSMONITOR_REASON_OK, /* no incompatibility or when disabled */
19 FSMONITOR_REASON_BARE,
20 + FSMONITOR_REASON_ERROR, /* FS error probing for compatibility */
21 + FSMONITOR_REASON_REMOTE,
22 FSMONITOR_REASON_VFS4GIT, /* VFS for Git virtualization */
23 };
24