|
2 | 2 | #include "config.h"
|
3 | 3 | #include "repository.h"
|
4 | 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 is_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_ZERO; |
| 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_ZERO; |
| 64 | +} |
5 | 65 |
|
6 | 66 | enum fsmonitor_reason fsm_os__incompatible(struct repository *r)
|
7 | 67 | {
|
| 68 | + enum fsmonitor_reason reason; |
| 69 | + |
| 70 | + reason = is_remote(r); |
| 71 | + if (reason) |
| 72 | + return reason; |
| 73 | + |
8 | 74 | return FSMONITOR_REASON_ZERO;
|
9 | 75 | }
|
0 commit comments