From patchwork Sun Oct 9 14:37:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3C1E0C4332F for ; Sun, 9 Oct 2022 14:38:01 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230213AbiJIOiA (ORCPT ); Sun, 9 Oct 2022 10:38:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46772 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230115AbiJIOhp (ORCPT ); Sun, 9 Oct 2022 10:37:45 -0400 Received: from mail-wm1-x336.google.com (mail-wm1-x336.google.com [IPv6:2a00:1450:4864:20::336]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2DD3E2716B for ; Sun, 9 Oct 2022 07:37:43 -0700 (PDT) Received: by mail-wm1-x336.google.com with SMTP id n16-20020a05600c4f9000b003c17bf8ddecso3820737wmq.0 for ; Sun, 09 Oct 2022 07:37:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=wIFY2Z/vJBuNXsR7F5iTNtyFHpmyCnaMLS0bQSwMfus=; b=USww/YSU0Nt0RWKPChu0jNGB0w6gAP6UzvPO/g9IZ+Bl6SPSludohIHeAwCX6Pjjbu 7dOw4CyEn6W5OwMSs9xBf1fMmpgEzyfYuSXmL+RHAzjAGSItIoH78X2xf2lcdNFkKzp3 7vbmd5AbI2jyx/0/7BPGIoCRjG93MqlxTMzOvuDEhnqYOGfkJ6FgEoJQNe3V24JTGbwe 7th8/jtlUfC89SFmdy6Na9emcKMHPyyVxip/G9IRxRaHOtLQhgbvBO6EKLOEdjKSnzeE f8Dq0ynPBPfMJgqCY/Cus4lPR1lPimfN60whmwEZZHqVMhOonzBV9rumfDHXIHKSW9Sy v6Bw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=wIFY2Z/vJBuNXsR7F5iTNtyFHpmyCnaMLS0bQSwMfus=; b=Cua1D+PcnV7km9ivwlvnck8vGSxeV3/zxASGNkLmSpG1drunxKSkR/0JBKnSYAM5J9 j/lr9WOkQKVJ8r7Hxf8mS4om3u6nsgXXG7a9xbHKBU50IMlF88aqjwitEyZ8xfs8HmY/ k94W1NR9uvq2flE9yPIJ9MyCoh0meitNltYlFLzfbekfZ/pgxYep10+ATmMmwOEOO1SX dYB6N4D4YbDETF/cskGXeSd8LMM5TX4BfcmIr0Ivsqp21Bpt/rD8g3tg30qwgpBJ2zE1 IRyd1un8QxctjH8WbqEBls726nU9ScpNVRA6D8dD1hrwo5DfEXIpK7XzxjthOOaqD80f nAKA== X-Gm-Message-State: ACrzQf1SfPdAoRgxYP06iWQ83n4FtUZCXrwX4Fy775C1u0kfjFpfjCZX 9x5KXGp+1CU3yH8YcekHRZ1sAPlylFY= X-Google-Smtp-Source: AMsMyM6F7bDtH/hnRYANAHWGtixrqlrpY/4Y/WKpSPIh+P+A6zrsxz9U9pJrA3fRUnhAaybkBIDDJw== X-Received: by 2002:a7b:c303:0:b0:3b4:6e89:e5d5 with SMTP id k3-20020a7bc303000000b003b46e89e5d5mr9760832wmj.111.1665326260795; Sun, 09 Oct 2022 07:37:40 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id s3-20020adfdb03000000b0022e309d35f8sm6739851wri.12.2022.10.09.07.37.40 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:40 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:27 +0000 Subject: [PATCH 01/12] fsmonitor: refactor filesystem checks to common interface Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Provide a common interface for getting basic filesystem information including filesystem type and whether the filesystem is remote. Refactor existing code for getting basic filesystem info and detecting remote file systems to the new interface. Refactor filesystem checks to leverage new interface. For macOS, error-out if the Unix Domain socket (UDS) file is on a remote filesystem. Signed-off-by: Eric DeCosta --- Makefile | 1 + compat/fsmonitor/fsm-path-utils-darwin.c | 43 ++++++ compat/fsmonitor/fsm-path-utils-win32.c | 128 +++++++++++++++++ compat/fsmonitor/fsm-settings-darwin.c | 69 +++------ compat/fsmonitor/fsm-settings-win32.c | 172 +---------------------- contrib/buildsystems/CMakeLists.txt | 2 + fsmonitor-path-utils.h | 26 ++++ fsmonitor-settings.c | 50 +++++++ 8 files changed, 272 insertions(+), 219 deletions(-) create mode 100644 compat/fsmonitor/fsm-path-utils-darwin.c create mode 100644 compat/fsmonitor/fsm-path-utils-win32.c create mode 100644 fsmonitor-path-utils.h diff --git a/Makefile b/Makefile index cac3452edb9..ffab427ea5b 100644 --- a/Makefile +++ b/Makefile @@ -2044,6 +2044,7 @@ endif ifdef FSMONITOR_OS_SETTINGS COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o + COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o endif ifeq ($(TCLTK_PATH),) diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c new file mode 100644 index 00000000000..d46d7f13538 --- /dev/null +++ b/compat/fsmonitor/fsm-path-utils-darwin.c @@ -0,0 +1,43 @@ +#include "fsmonitor.h" +#include "fsmonitor-path-utils.h" +#include +#include + +int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info) +{ + struct statfs fs; + if (statfs(path, &fs) == -1) { + int saved_errno = errno; + trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s", + path, strerror(saved_errno)); + errno = saved_errno; + return -1; + } + + trace_printf_key(&trace_fsmonitor, + "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'", + path, fs.f_type, fs.f_flags, fs.f_fstypename); + + if (!(fs.f_flags & MNT_LOCAL)) + fs_info->is_remote = 1; + else + fs_info->is_remote = 0; + + fs_info->typename = xstrdup(fs.f_fstypename); + + trace_printf_key(&trace_fsmonitor, + "'%s' is_remote: %d", + path, fs_info->is_remote); + return 0; +} + +int fsmonitor__is_fs_remote(const char *path) +{ + struct fs_info fs; + if (fsmonitor__get_fs_info(path, &fs)) + return -1; + + free(fs.typename); + + return fs.is_remote; +} diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c new file mode 100644 index 00000000000..a90b8f7925b --- /dev/null +++ b/compat/fsmonitor/fsm-path-utils-win32.c @@ -0,0 +1,128 @@ +#include "cache.h" +#include "fsmonitor.h" +#include "fsmonitor-path-utils.h" + +/* + * Check remote working directory protocol. + * + * Return -1 if client machine cannot get remote protocol information. + */ +static int check_remote_protocol(wchar_t *wpath) +{ + HANDLE h; + FILE_REMOTE_PROTOCOL_INFO proto_info; + + h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (h == INVALID_HANDLE_VALUE) { + error(_("[GLE %ld] unable to open for read '%ls'"), + GetLastError(), wpath); + return -1; + } + + if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo, + &proto_info, sizeof(proto_info))) { + error(_("[GLE %ld] unable to get protocol information for '%ls'"), + GetLastError(), wpath); + CloseHandle(h); + return -1; + } + + CloseHandle(h); + + trace_printf_key(&trace_fsmonitor, + "check_remote_protocol('%ls') remote protocol %#8.8lx", + wpath, proto_info.Protocol); + + return 0; +} + +/* + * Notes for testing: + * + * (a) Windows allows a network share to be mapped to a drive letter. + * (This is the normal method to access it.) + * + * $ NET USE Z: \\server\share + * $ git -C Z:/repo status + * + * (b) Windows allows a network share to be referenced WITHOUT mapping + * it to drive letter. + * + * $ NET USE \\server\share\dir + * $ git -C //server/share/repo status + * + * (c) Windows allows "SUBST" to create a fake drive mapping to an + * arbitrary path (which may be remote) + * + * $ SUBST Q: Z:\repo + * $ git -C Q:/ status + * + * (d) Windows allows a directory symlink to be created on a local + * file system that points to a remote repo. + * + * $ mklink /d ./link //server/share/repo + * $ git -C ./link status + */ +int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info) +{ + wchar_t wpath[MAX_PATH]; + wchar_t wfullpath[MAX_PATH]; + size_t wlen; + UINT driveType; + + /* + * Do everything in wide chars because the drive letter might be + * a multi-byte sequence. See win32_has_dos_drive_prefix(). + */ + if (xutftowcs_path(wpath, path) < 0) { + return -1; + } + + /* + * GetDriveTypeW() requires a final slash. We assume that the + * worktree pathname points to an actual directory. + */ + wlen = wcslen(wpath); + if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') { + wpath[wlen++] = L'\\'; + wpath[wlen] = 0; + } + + /* + * Normalize the path. If nothing else, this converts forward + * slashes to backslashes. This is essential to get GetDriveTypeW() + * correctly handle some UNC "\\server\share\..." paths. + */ + if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) { + return -1; + } + + driveType = GetDriveTypeW(wfullpath); + trace_printf_key(&trace_fsmonitor, + "DriveType '%s' L'%ls' (%u)", + path, wfullpath, driveType); + + if (driveType == DRIVE_REMOTE) { + fs_info->is_remote = 1; + if (check_remote_protocol(wfullpath) < 0) + return -1; + } else { + fs_info->is_remote = 0; + } + + trace_printf_key(&trace_fsmonitor, + "'%s' is_remote: %d", + path, fs_info->is_remote); + + return 0; +} + +int fsmonitor__is_fs_remote(const char *path) +{ + struct fs_info fs; + if (fsmonitor__get_fs_info(path, &fs)) + return -1; + return fs.is_remote; +} diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c index efc732c0f31..699f0b272e6 100644 --- a/compat/fsmonitor/fsm-settings-darwin.c +++ b/compat/fsmonitor/fsm-settings-darwin.c @@ -1,32 +1,10 @@ -#include "cache.h" #include "config.h" -#include "repository.h" -#include "fsmonitor-settings.h" #include "fsmonitor.h" -#include -#include +#include "fsmonitor-ipc.h" +#include "fsmonitor-settings.h" +#include "fsmonitor-path-utils.h" -/* - * [1] Remote working directories are problematic for FSMonitor. - * - * The underlying file system on the server machine and/or the remote - * mount type (NFS, SAMBA, etc.) dictates whether notification events - * are available at all to remote client machines. - * - * Kernel differences between the server and client machines also - * dictate the how (buffering, frequency, de-dup) the events are - * delivered to client machine processes. - * - * A client machine (such as a laptop) may choose to suspend/resume - * and it is unclear (without lots of testing) whether the watcher can - * resync after a resume. We might be able to treat this as a normal - * "events were dropped by the kernel" event and do our normal "flush - * and resync" --or-- we might need to close the existing (zombie?) - * notification fd and create a new one. - * - * In theory, the above issues need to be addressed whether we are - * using the Hook or IPC API. - * + /* * For the builtin FSMonitor, we create the Unix domain socket for the * IPC in the .git directory. If the working directory is remote, * then the socket will be created on the remote file system. This @@ -38,42 +16,35 @@ * be taken to ensure that $HOME is actually local and not a managed * file share.) * - * So (for now at least), mark remote working directories as - * incompatible. - * - * - * [2] FAT32 and NTFS working directories are problematic too. + * FAT32 and NTFS working directories are problematic too. * * The builtin FSMonitor uses a Unix domain socket in the .git * directory for IPC. These Windows drive formats do not support * Unix domain sockets, so mark them as incompatible for the daemon. * */ -static enum fsmonitor_reason check_volume(struct repository *r) +static enum fsmonitor_reason check_uds_volume(struct repository *r) { - struct statfs fs; + struct fs_info fs; + const char *ipc_path = fsmonitor_ipc__get_path(); + struct strbuf path = STRBUF_INIT; + strbuf_add(&path, ipc_path, strlen(ipc_path)); - if (statfs(r->worktree, &fs) == -1) { - int saved_errno = errno; - trace_printf_key(&trace_fsmonitor, "statfs('%s') failed: %s", - r->worktree, strerror(saved_errno)); - errno = saved_errno; + if (fsmonitor__get_fs_info(dirname(path.buf), &fs) == -1) { + strbuf_release(&path); return FSMONITOR_REASON_ERROR; } - trace_printf_key(&trace_fsmonitor, - "statfs('%s') [type 0x%08x][flags 0x%08x] '%s'", - r->worktree, fs.f_type, fs.f_flags, fs.f_fstypename); - - if (!(fs.f_flags & MNT_LOCAL)) - return FSMONITOR_REASON_REMOTE; + strbuf_release(&path); - if (!strcmp(fs.f_fstypename, "msdos")) /* aka FAT32 */ - return FSMONITOR_REASON_NOSOCKETS; - - if (!strcmp(fs.f_fstypename, "ntfs")) + if (fs.is_remote || + !strcmp(fs.typename, "msdos") || + !strcmp(fs.typename, "ntfs")) { + free(fs.typename); return FSMONITOR_REASON_NOSOCKETS; + } + free(fs.typename); return FSMONITOR_REASON_OK; } @@ -81,7 +52,7 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r) { enum fsmonitor_reason reason; - reason = check_volume(r); + reason = check_uds_volume(r); if (reason != FSMONITOR_REASON_OK) return reason; diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c index e5ec5b0a9f7..d88b06ae610 100644 --- a/compat/fsmonitor/fsm-settings-win32.c +++ b/compat/fsmonitor/fsm-settings-win32.c @@ -1,8 +1,9 @@ #include "cache.h" #include "config.h" #include "repository.h" -#include "fsmonitor-settings.h" #include "fsmonitor.h" +#include "fsmonitor-settings.h" +#include "fsmonitor-path-utils.h" /* * VFS for Git is incompatible with FSMonitor. @@ -24,171 +25,6 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r) return FSMONITOR_REASON_OK; } -/* - * Check if monitoring remote working directories is allowed. - * - * By default, monitoring remote working directories is - * disabled. Users may override this behavior in enviroments where - * they have proper support. - */ -static int check_config_allowremote(struct repository *r) -{ - int allow; - - if (!repo_config_get_bool(r, "fsmonitor.allowremote", &allow)) - return allow; - - return -1; /* fsmonitor.allowremote not set */ -} - -/* - * Check remote working directory protocol. - * - * Error if client machine cannot get remote protocol information. - */ -static int check_remote_protocol(wchar_t *wpath) -{ - HANDLE h; - FILE_REMOTE_PROTOCOL_INFO proto_info; - - h = CreateFileW(wpath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS, NULL); - - if (h == INVALID_HANDLE_VALUE) { - error(_("[GLE %ld] unable to open for read '%ls'"), - GetLastError(), wpath); - return -1; - } - - if (!GetFileInformationByHandleEx(h, FileRemoteProtocolInfo, - &proto_info, sizeof(proto_info))) { - error(_("[GLE %ld] unable to get protocol information for '%ls'"), - GetLastError(), wpath); - CloseHandle(h); - return -1; - } - - CloseHandle(h); - - trace_printf_key(&trace_fsmonitor, - "check_remote_protocol('%ls') remote protocol %#8.8lx", - wpath, proto_info.Protocol); - - return 0; -} - -/* - * Remote working directories are problematic for FSMonitor. - * - * The underlying file system on the server machine and/or the remote - * mount type dictates whether notification events are available at - * all to remote client machines. - * - * Kernel differences between the server and client machines also - * dictate the how (buffering, frequency, de-dup) the events are - * delivered to client machine processes. - * - * A client machine (such as a laptop) may choose to suspend/resume - * and it is unclear (without lots of testing) whether the watcher can - * resync after a resume. We might be able to treat this as a normal - * "events were dropped by the kernel" event and do our normal "flush - * and resync" --or-- we might need to close the existing (zombie?) - * notification fd and create a new one. - * - * In theory, the above issues need to be addressed whether we are - * using the Hook or IPC API. - * - * So (for now at least), mark remote working directories as - * incompatible. - * - * Notes for testing: - * - * (a) Windows allows a network share to be mapped to a drive letter. - * (This is the normal method to access it.) - * - * $ NET USE Z: \\server\share - * $ git -C Z:/repo status - * - * (b) Windows allows a network share to be referenced WITHOUT mapping - * it to drive letter. - * - * $ NET USE \\server\share\dir - * $ git -C //server/share/repo status - * - * (c) Windows allows "SUBST" to create a fake drive mapping to an - * arbitrary path (which may be remote) - * - * $ SUBST Q: Z:\repo - * $ git -C Q:/ status - * - * (d) Windows allows a directory symlink to be created on a local - * file system that points to a remote repo. - * - * $ mklink /d ./link //server/share/repo - * $ git -C ./link status - */ -static enum fsmonitor_reason check_remote(struct repository *r) -{ - int ret; - wchar_t wpath[MAX_PATH]; - wchar_t wfullpath[MAX_PATH]; - size_t wlen; - UINT driveType; - - /* - * Do everything in wide chars because the drive letter might be - * a multi-byte sequence. See win32_has_dos_drive_prefix(). - */ - if (xutftowcs_path(wpath, r->worktree) < 0) - return FSMONITOR_REASON_ERROR; - - /* - * GetDriveTypeW() requires a final slash. We assume that the - * worktree pathname points to an actual directory. - */ - wlen = wcslen(wpath); - if (wpath[wlen - 1] != L'\\' && wpath[wlen - 1] != L'/') { - wpath[wlen++] = L'\\'; - wpath[wlen] = 0; - } - - /* - * Normalize the path. If nothing else, this converts forward - * slashes to backslashes. This is essential to get GetDriveTypeW() - * correctly handle some UNC "\\server\share\..." paths. - */ - if (!GetFullPathNameW(wpath, MAX_PATH, wfullpath, NULL)) - return FSMONITOR_REASON_ERROR; - - driveType = GetDriveTypeW(wfullpath); - trace_printf_key(&trace_fsmonitor, - "DriveType '%s' L'%ls' (%u)", - r->worktree, wfullpath, driveType); - - if (driveType == DRIVE_REMOTE) { - trace_printf_key(&trace_fsmonitor, - "check_remote('%s') true", - r->worktree); - - ret = check_remote_protocol(wfullpath); - if (ret < 0) - return FSMONITOR_REASON_ERROR; - - switch (check_config_allowremote(r)) { - case 0: /* config overrides and disables */ - return FSMONITOR_REASON_REMOTE; - case 1: /* config overrides and enables */ - return FSMONITOR_REASON_OK; - default: - break; /* config has no opinion */ - } - - return FSMONITOR_REASON_REMOTE; - } - - return FSMONITOR_REASON_OK; -} - enum fsmonitor_reason fsm_os__incompatible(struct repository *r) { enum fsmonitor_reason reason; @@ -197,9 +33,5 @@ enum fsmonitor_reason fsm_os__incompatible(struct repository *r) if (reason != FSMONITOR_REASON_OK) return reason; - reason = check_remote(r); - if (reason != FSMONITOR_REASON_OK) - return reason; - return FSMONITOR_REASON_OK; } diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index ea2a531be87..5482a04b3ce 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC) add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c) add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS) list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c) @@ -315,6 +316,7 @@ if(SUPPORTS_SIMPLE_IPC) add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c) add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS) list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c) diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h new file mode 100644 index 00000000000..41edf5b934f --- /dev/null +++ b/fsmonitor-path-utils.h @@ -0,0 +1,26 @@ +#ifndef FSM_PATH_UTILS_H +#define FSM_PATH_UTILS_H + +struct fs_info { + int is_remote; + char *typename; +}; + +/* + * Get some basic filesystem informtion for the given path + * + * The caller owns the storage that is occupied by fs_info and + * is responsible for releasing it. + * + * Returns -1 on error, zero otherwise. + */ +int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info); + +/* + * Determines if the filesystem that path resides on is remote. + * + * Returns -1 on error, 0 if not remote, 1 if remote. + */ +int fsmonitor__is_fs_remote(const char *path); + +#endif diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c index 464424a1e92..d288cbad479 100644 --- a/fsmonitor-settings.c +++ b/fsmonitor-settings.c @@ -2,6 +2,7 @@ #include "config.h" #include "repository.h" #include "fsmonitor-settings.h" +#include "fsmonitor-path-utils.h" /* * We keep this structure defintion private and have getters @@ -13,6 +14,52 @@ struct fsmonitor_settings { char *hook_path; }; +/* + * Remote working directories are problematic for FSMonitor. + * + * The underlying file system on the server machine and/or the remote + * mount type dictates whether notification events are available at + * all to remote client machines. + * + * Kernel differences between the server and client machines also + * dictate the how (buffering, frequency, de-dup) the events are + * delivered to client machine processes. + * + * A client machine (such as a laptop) may choose to suspend/resume + * and it is unclear (without lots of testing) whether the watcher can + * resync after a resume. We might be able to treat this as a normal + * "events were dropped by the kernel" event and do our normal "flush + * and resync" --or-- we might need to close the existing (zombie?) + * notification fd and create a new one. + * + * In theory, the above issues need to be addressed whether we are + * using the Hook or IPC API. + * + * So (for now at least), mark remote working directories as + * incompatible unless 'fsmonitor.allowRemote' is true. + * + */ +#ifdef HAVE_FSMONITOR_OS_SETTINGS +static enum fsmonitor_reason check_remote(struct repository *r) +{ + int allow_remote = -1; /* -1 unset, 0 not allowed, 1 allowed */ + int is_remote = fsmonitor__is_fs_remote(r->worktree); + + switch (is_remote) { + case 0: + return FSMONITOR_REASON_OK; + case 1: + repo_config_get_bool(r, "fsmonitor.allowremote", &allow_remote); + if (allow_remote < 1) + return FSMONITOR_REASON_REMOTE; + else + return FSMONITOR_REASON_OK; + default: + return FSMONITOR_REASON_ERROR; + } +} +#endif + static enum fsmonitor_reason check_for_incompatible(struct repository *r) { if (!r->worktree) { @@ -27,6 +74,9 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r) { enum fsmonitor_reason reason; + reason = check_remote(r); + if (reason != FSMONITOR_REASON_OK) + return reason; reason = fsm_os__incompatible(r); if (reason != FSMONITOR_REASON_OK) return reason; From patchwork Sun Oct 9 14:37:28 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002022 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4C6DCC433F5 for ; Sun, 9 Oct 2022 14:37:52 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230201AbiJIOhu (ORCPT ); Sun, 9 Oct 2022 10:37:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46744 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229949AbiJIOho (ORCPT ); Sun, 9 Oct 2022 10:37:44 -0400 Received: from mail-wm1-x329.google.com (mail-wm1-x329.google.com [IPv6:2a00:1450:4864:20::329]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8692E275C8 for ; Sun, 9 Oct 2022 07:37:43 -0700 (PDT) Received: by mail-wm1-x329.google.com with SMTP id n16-20020a05600c4f9000b003c17bf8ddecso3820739wmq.0 for ; Sun, 09 Oct 2022 07:37:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=ZxZ+ekCnhsjFbvNwp8F7hayS+Nmqoxn8PLvM43nMJw4=; b=ZMUbfTJ9kfunrJmA8TYP86ROD+eGhehSFp5vwZoPNXWz+fjVbkuxCIikxSc8vilGd+ zrO2aQLuyZ90D29xuNjtcXLb2EkaFePXiOIqWQZbFjpogTRV8xRu9pm4RNcFAGaEWOjt lKVzUz2Z0Yr9+0pk3aPmlSTIwSze7qZsBMqpC8l3jdWpMMbTUbw/59gK0ANxwAjl93o7 LoqtJjIQr85W/lo4t2KJWCBOJNPZNz6ywWcuPxCapS1P5iL5EuJwmA8CpO3cg68peIIK CWgW61OP54gjK7VXOgjcFM1/vU0Bbi4Pld2aRPZoER05ZdPXocMwd1vYhM06Ec6f3XDA XiuQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=ZxZ+ekCnhsjFbvNwp8F7hayS+Nmqoxn8PLvM43nMJw4=; b=sMKFGt+6/fC/R5DBDQ4Ddqu8j4ZGtzheidZp4fNGJzozTaDvNiJBiBvWJGSaeG59DX ZFwblthR6Z/sDaFmngYxIUB/1bDz8RxIEdrkwdkerq+uDO+L4CjpEzyuyH3L4xN+qaCB PqA1wCz8SDjTN8jENCl1l/rJgFP/5zj8Wqa4vmPKJ8KcBz7u8EqSoEdIPNo3YJnXL0uJ TKo4P/QkRHEar9i2tEy4FH8NldH0Jv4LI7NbqJms5EiXWXWZbMTCnQmK2byD5GJABvRn X4ZFlcPJt+d2q5qe5uzeCbuiIXdhetY+tXYx1ot3ONL37eiUCBXYMiKEbdh2b7amuDEw Lanw== X-Gm-Message-State: ACrzQf1qH8J1b+yKuz+XM5RHIDT+oy8iOoYbtMw6/1ql4DR5YJjz/LTd QfRDzRE39gUVrmga2XzehGOg9YWXxRk= X-Google-Smtp-Source: AMsMyM74L7VZhA2kCIINu9Ndj3NTYxaikSUej4154kh5z8xzJD6pP69923z7jiciw2+an6YqOfOwgQ== X-Received: by 2002:a1c:ed0b:0:b0:3c1:d16e:a827 with SMTP id l11-20020a1ced0b000000b003c1d16ea827mr9584120wmh.127.1665326261640; Sun, 09 Oct 2022 07:37:41 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id g6-20020a5d4886000000b0022cc6b8df5esm6867589wrq.7.2022.10.09.07.37.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:41 -0700 (PDT) Message-Id: <7bf1cdfe3b259f7135f3a50dcdd653563d5e19f6.1665326258.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:28 +0000 Subject: [PATCH 02/12] fsmonitor: relocate socket file if .git directory is remote Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta If the .git directory is on a remote filesystem, create the socket file in 'fsmonitor.socketDir' if it is defined, else create it in $HOME. Signed-off-by: Eric DeCosta --- Makefile | 1 + builtin/fsmonitor--daemon.c | 3 +- compat/fsmonitor/fsm-ipc-darwin.c | 52 ++++++++++++++++++++++++++ compat/fsmonitor/fsm-ipc-win32.c | 9 +++++ compat/fsmonitor/fsm-settings-darwin.c | 2 +- contrib/buildsystems/CMakeLists.txt | 2 + fsmonitor-ipc.c | 18 ++++----- fsmonitor-ipc.h | 4 +- 8 files changed, 78 insertions(+), 13 deletions(-) create mode 100644 compat/fsmonitor/fsm-ipc-darwin.c create mode 100644 compat/fsmonitor/fsm-ipc-win32.c diff --git a/Makefile b/Makefile index ffab427ea5b..feb675a6959 100644 --- a/Makefile +++ b/Makefile @@ -2039,6 +2039,7 @@ ifdef FSMONITOR_DAEMON_BACKEND COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o + COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o endif ifdef FSMONITOR_OS_SETTINGS diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 2c109cf8b37..0123fc33ed2 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -1343,7 +1343,8 @@ static int fsmonitor_run_daemon(void) * directory.) */ strbuf_init(&state.path_ipc, 0); - strbuf_addstr(&state.path_ipc, absolute_path(fsmonitor_ipc__get_path())); + strbuf_addstr(&state.path_ipc, + absolute_path(fsmonitor_ipc__get_path(the_repository))); /* * Confirm that we can create platform-specific resources for the diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-darwin.c new file mode 100644 index 00000000000..ce843d63348 --- /dev/null +++ b/compat/fsmonitor/fsm-ipc-darwin.c @@ -0,0 +1,52 @@ +#include "cache.h" +#include "config.h" +#include "strbuf.h" +#include "fsmonitor.h" +#include "fsmonitor-ipc.h" +#include "fsmonitor-path-utils.h" + +static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc") + +const char *fsmonitor_ipc__get_path(struct repository *r) +{ + static const char *ipc_path = NULL; + SHA_CTX sha1ctx; + char *sock_dir = NULL; + struct strbuf ipc_file = STRBUF_INIT; + unsigned char hash[SHA_DIGEST_LENGTH]; + + if (!r) + BUG("No repository passed into fsmonitor_ipc__get_path"); + + if (ipc_path) + return ipc_path; + + + /* By default the socket file is created in the .git directory */ + if (fsmonitor__is_fs_remote(r->gitdir) < 1) { + ipc_path = fsmonitor_ipc__get_default_path(); + return ipc_path; + } + + SHA1_Init(&sha1ctx); + SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree)); + SHA1_Final(hash, &sha1ctx); + + repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir); + + /* Create the socket file in either socketDir or $HOME */ + if (sock_dir && *sock_dir) { + strbuf_addf(&ipc_file, "%s/.git-fsmonitor-%s", + sock_dir, hash_to_hex(hash)); + } else { + strbuf_addf(&ipc_file, "~/.git-fsmonitor-%s", hash_to_hex(hash)); + } + free(sock_dir); + + ipc_path = interpolate_path(ipc_file.buf, 1); + if (!ipc_path) + die(_("Invalid path: %s"), ipc_file.buf); + + strbuf_release(&ipc_file); + return ipc_path; +} diff --git a/compat/fsmonitor/fsm-ipc-win32.c b/compat/fsmonitor/fsm-ipc-win32.c new file mode 100644 index 00000000000..e08c505c148 --- /dev/null +++ b/compat/fsmonitor/fsm-ipc-win32.c @@ -0,0 +1,9 @@ +#include "config.h" +#include "fsmonitor-ipc.h" + +const char *fsmonitor_ipc__get_path(struct repository *r) { + static char *ret; + if (!ret) + ret = git_pathdup("fsmonitor--daemon.ipc"); + return ret; +} diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c index 699f0b272e6..7241c4c22c9 100644 --- a/compat/fsmonitor/fsm-settings-darwin.c +++ b/compat/fsmonitor/fsm-settings-darwin.c @@ -26,7 +26,7 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r) { struct fs_info fs; - const char *ipc_path = fsmonitor_ipc__get_path(); + const char *ipc_path = fsmonitor_ipc__get_path(r); struct strbuf path = STRBUF_INIT; strbuf_add(&path, ipc_path, strlen(ipc_path)); diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 5482a04b3ce..787738e6fa3 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -308,6 +308,7 @@ if(SUPPORTS_SIMPLE_IPC) add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-win32.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-win32.c) add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS) @@ -316,6 +317,7 @@ if(SUPPORTS_SIMPLE_IPC) add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c) add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS) diff --git a/fsmonitor-ipc.c b/fsmonitor-ipc.c index 789e7397baa..c0f42301c84 100644 --- a/fsmonitor-ipc.c +++ b/fsmonitor-ipc.c @@ -18,7 +18,7 @@ int fsmonitor_ipc__is_supported(void) return 0; } -const char *fsmonitor_ipc__get_path(void) +const char *fsmonitor_ipc__get_path(struct repository *r) { return NULL; } @@ -47,11 +47,9 @@ int fsmonitor_ipc__is_supported(void) return 1; } -GIT_PATH_FUNC(fsmonitor_ipc__get_path, "fsmonitor--daemon.ipc") - enum ipc_active_state fsmonitor_ipc__get_state(void) { - return ipc_get_active_state(fsmonitor_ipc__get_path()); + return ipc_get_active_state(fsmonitor_ipc__get_path(the_repository)); } static int spawn_daemon(void) @@ -81,8 +79,8 @@ int fsmonitor_ipc__send_query(const char *since_token, trace2_data_string("fsm_client", NULL, "query/command", tok); try_again: - state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options, - &connection); + state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository), + &options, &connection); switch (state) { case IPC_STATE__LISTENING: @@ -117,13 +115,13 @@ try_again: case IPC_STATE__INVALID_PATH: ret = error(_("fsmonitor_ipc__send_query: invalid path '%s'"), - fsmonitor_ipc__get_path()); + fsmonitor_ipc__get_path(the_repository)); goto done; case IPC_STATE__OTHER_ERROR: default: ret = error(_("fsmonitor_ipc__send_query: unspecified error on '%s'"), - fsmonitor_ipc__get_path()); + fsmonitor_ipc__get_path(the_repository)); goto done; } @@ -149,8 +147,8 @@ int fsmonitor_ipc__send_command(const char *command, options.wait_if_busy = 1; options.wait_if_not_found = 0; - state = ipc_client_try_connect(fsmonitor_ipc__get_path(), &options, - &connection); + state = ipc_client_try_connect(fsmonitor_ipc__get_path(the_repository), + &options, &connection); if (state != IPC_STATE__LISTENING) { die(_("fsmonitor--daemon is not running")); return -1; diff --git a/fsmonitor-ipc.h b/fsmonitor-ipc.h index b6a7067c3af..8b489da762b 100644 --- a/fsmonitor-ipc.h +++ b/fsmonitor-ipc.h @@ -3,6 +3,8 @@ #include "simple-ipc.h" +struct repository; + /* * Returns true if built-in file system monitor daemon is defined * for this platform. @@ -16,7 +18,7 @@ int fsmonitor_ipc__is_supported(void); * * Returns NULL if the daemon is not supported on this platform. */ -const char *fsmonitor_ipc__get_path(void); +const char *fsmonitor_ipc__get_path(struct repository *r); /* * Try to determine whether there is a `git-fsmonitor--daemon` process From patchwork Sun Oct 9 14:37:29 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002024 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A06BBC433F5 for ; Sun, 9 Oct 2022 14:37:57 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230200AbiJIOh4 (ORCPT ); Sun, 9 Oct 2022 10:37:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46754 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229974AbiJIOhp (ORCPT ); Sun, 9 Oct 2022 10:37:45 -0400 Received: from mail-wm1-x335.google.com (mail-wm1-x335.google.com [IPv6:2a00:1450:4864:20::335]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 354CB275CD for ; Sun, 9 Oct 2022 07:37:44 -0700 (PDT) Received: by mail-wm1-x335.google.com with SMTP id p26-20020a7bcc9a000000b003c384e59047so3070621wma.4 for ; Sun, 09 Oct 2022 07:37:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=Wcm8qpzJovNixZr4FfekgJCx0i3cU8b+4aQdred0fgg=; b=N5La4ECgEAxOCg0Zv3uKZ7ZvCUTn6B6O9EWA/TKFL0dOaMzFhVd4SuXwJT7UkkCybr Wtdu+en6FSCjiMYRO4Ivx/o1oSmWVINTTRL3BFbgFqhuPQgXXxugW0ylyRxxdPI06AYH hYA9EZR9yw48y9xCQSf7cDA5ALeMXoLqwbzZJUV7FoMNl8TP9BYWimCX9+TpqC29h70x bu9PXz1tHqcJXzQhRy/EqhdIU8+CCPtz2NYH5DgNuAUB5yJkIL4MjHK3lZOhSfSxfq33 nLwCGjEAuhYbRQFzdf14URpRf70zftL0Tjg0CoVW2JJSBxCbi2sqtZCE18bhs+SgS1Yz 0r1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Wcm8qpzJovNixZr4FfekgJCx0i3cU8b+4aQdred0fgg=; b=NsF3vaBk6ZVunvslU8n7XvBEsEPppuj1n0XxxCyGiF7KU44IQoLhRlVUsQdicw+Heh trdKSg3evpojxyJj6R8lzj2ELXCAMLa/PBUSU4JZlbDpCJav64lKNV4aXTvIdc5M3OWn Qgz3azpOQ4pfV9ha29qs4P5c6OSOTsuovdeN+NfWOyoVE5NWzwqKLb4ZyXniZMzgvndt KLwJmFUA0K4mKBiFkO5nfaFHGmtZ3ROR0sShqzbDktTpscBDZjyO4gFSGYnNbQFdlUkr qCaHPOO9dh3sVfLnpTUNHGU9SVrUN5nqTvgKOKZth2x5r/6CpI5HWpNb6SG4RACRtUeJ PBTQ== X-Gm-Message-State: ACrzQf2aPUrCnxF8hUp/MqEesLEKclgJsPrcwMAYHdKW62c5U0zKgSpU SIdGUtHkh/t7jtB2e644esk7d1+jbMI= X-Google-Smtp-Source: AMsMyM4PDjcsfmsU9HLCclj5h/aLzUxd7tWF14CqdGo5dw2XnIZm6HGoS/x3dOX5byJICnne2BsUIQ== X-Received: by 2002:a05:600c:d5:b0:3c0:fba1:d2b9 with SMTP id u21-20020a05600c00d500b003c0fba1d2b9mr9650228wmm.108.1665326262544; Sun, 09 Oct 2022 07:37:42 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id o18-20020a1c7512000000b003b492753826sm7631593wmc.43.2022.10.09.07.37.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:42 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:29 +0000 Subject: [PATCH 03/12] fsmonitor: avoid socket location check if using hook Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta If monitoring is done via fsmonitor hook rather than IPC there is no need to check if the location of the Unix Domain socket (UDS) file is on a remote filesystem. Signed-off-by: Eric DeCosta --- compat/fsmonitor/fsm-settings-darwin.c | 10 ++++++---- compat/fsmonitor/fsm-settings-win32.c | 2 +- fsmonitor-settings.c | 8 ++++---- fsmonitor-settings.h | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-darwin.c index 7241c4c22c9..6abbc7af3ab 100644 --- a/compat/fsmonitor/fsm-settings-darwin.c +++ b/compat/fsmonitor/fsm-settings-darwin.c @@ -48,13 +48,15 @@ static enum fsmonitor_reason check_uds_volume(struct repository *r) return FSMONITOR_REASON_OK; } -enum fsmonitor_reason fsm_os__incompatible(struct repository *r) +enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc) { enum fsmonitor_reason reason; - reason = check_uds_volume(r); - if (reason != FSMONITOR_REASON_OK) - return reason; + if (ipc) { + reason = check_uds_volume(r); + if (reason != FSMONITOR_REASON_OK) + return reason; + } return FSMONITOR_REASON_OK; } diff --git a/compat/fsmonitor/fsm-settings-win32.c b/compat/fsmonitor/fsm-settings-win32.c index d88b06ae610..a8af31b71de 100644 --- a/compat/fsmonitor/fsm-settings-win32.c +++ b/compat/fsmonitor/fsm-settings-win32.c @@ -25,7 +25,7 @@ static enum fsmonitor_reason check_vfs4git(struct repository *r) return FSMONITOR_REASON_OK; } -enum fsmonitor_reason fsm_os__incompatible(struct repository *r) +enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc) { enum fsmonitor_reason reason; diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c index d288cbad479..531a1b6f956 100644 --- a/fsmonitor-settings.c +++ b/fsmonitor-settings.c @@ -60,7 +60,7 @@ static enum fsmonitor_reason check_remote(struct repository *r) } #endif -static enum fsmonitor_reason check_for_incompatible(struct repository *r) +static enum fsmonitor_reason check_for_incompatible(struct repository *r, int ipc) { if (!r->worktree) { /* @@ -77,7 +77,7 @@ static enum fsmonitor_reason check_for_incompatible(struct repository *r) reason = check_remote(r); if (reason != FSMONITOR_REASON_OK) return reason; - reason = fsm_os__incompatible(r); + reason = fsm_os__incompatible(r, ipc); if (reason != FSMONITOR_REASON_OK) return reason; } @@ -162,7 +162,7 @@ const char *fsm_settings__get_hook_path(struct repository *r) void fsm_settings__set_ipc(struct repository *r) { - enum fsmonitor_reason reason = check_for_incompatible(r); + enum fsmonitor_reason reason = check_for_incompatible(r, 1); if (reason != FSMONITOR_REASON_OK) { fsm_settings__set_incompatible(r, reason); @@ -185,7 +185,7 @@ void fsm_settings__set_ipc(struct repository *r) void fsm_settings__set_hook(struct repository *r, const char *path) { - enum fsmonitor_reason reason = check_for_incompatible(r); + enum fsmonitor_reason reason = check_for_incompatible(r, 0); if (reason != FSMONITOR_REASON_OK) { fsm_settings__set_incompatible(r, reason); diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h index d9c2605197f..0721617b95a 100644 --- a/fsmonitor-settings.h +++ b/fsmonitor-settings.h @@ -48,7 +48,7 @@ struct fsmonitor_settings; * fsm_os__* routines should considered private to fsm_settings__ * routines. */ -enum fsmonitor_reason fsm_os__incompatible(struct repository *r); +enum fsmonitor_reason fsm_os__incompatible(struct repository *r, int ipc); #endif /* HAVE_FSMONITOR_OS_SETTINGS */ #endif /* FSMONITOR_SETTINGS_H */ From patchwork Sun Oct 9 14:37:30 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002023 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C18A9C4332F for ; Sun, 9 Oct 2022 14:37:54 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230127AbiJIOhx (ORCPT ); Sun, 9 Oct 2022 10:37:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230128AbiJIOhr (ORCPT ); Sun, 9 Oct 2022 10:37:47 -0400 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9018B27CD4 for ; Sun, 9 Oct 2022 07:37:45 -0700 (PDT) Received: by mail-wr1-x42a.google.com with SMTP id bk15so13614613wrb.13 for ; Sun, 09 Oct 2022 07:37:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=4VOiu2LYfOs/H3yOPejPrktShUt4NieEVRkHQ4lKtzs=; b=hOABBfQ9X+qgd0vHpG0v9R1zRZ+8/xpKuKGwEp4T2zluyXNPXpQRu9i8Anx/9OVXAc PRXFWbBIq5gJ3POboqbquxDXjoMvEEYJQCrePl88wzb/BGHb106p7SF8+K/iI2ZfFklp sGXfraTBzXC2RD9x+XYDMzbLkrQZEcLrSetEIw6o0cNswhwPAgLzVZl/R/2nrim5iX6E 5mErHeqOROn+cAh0o5UuxAqixqWxR+aQdcZaUo4vHXptg9oJYfggx99dd9Vuy4ce3S/3 r3S/K/yml3v8TKZaP8d/jUyiShk53ONDEH8Rjey7dOEwyS0UHI7+p7YDUYmwN6dkkB6e 4k2w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4VOiu2LYfOs/H3yOPejPrktShUt4NieEVRkHQ4lKtzs=; b=uazhmYKNaaz8+mnMud71z72KApfQoqEpK78MIGFLPNMEzGVJ8822mkOfcRdGZHOojm SbbQnQm+i0RfqZB2q25FmgtoPWuwrDLMnko2wnD2lKJzl4vJK+eQQJnmxE++MelZULUN q7LgGWVW3CTaZMYwzFaUfOsHRGsvzkl23QEC/be5zabb36otRi2qhCIAgPvpkdXJmOkc 71IKoGdWlhxeA+rUOBAhxu2js3GG9CQSscHgNGH0S+/Cw2p/Ey9Odt56JEzIwEEpC3YQ PoBc65DBIbi8s82h+B2FSDiSkhpddF07IITc7nGViLG92qnQAhd/GNlU3WRZjnylHobJ M5Yg== X-Gm-Message-State: ACrzQf0r5YFHHEn9xobak1lvJiIwv1lRHYqmoFx/ljgnumqyhsSygWAg 9C4w6xQGgq+phYF7gocjNF052AiNGec= X-Google-Smtp-Source: AMsMyM5T7Z1lvgwiScrGEzMPag2TLy1NWptbtxrzc983J9V9I2QRm2rloAP9R/8jClIWtoHl9l0cmg== X-Received: by 2002:a05:6000:144a:b0:22e:4d74:c1f7 with SMTP id v10-20020a056000144a00b0022e4d74c1f7mr9001037wrx.86.1665326263515; Sun, 09 Oct 2022 07:37:43 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id q5-20020a05600000c500b0022e2eaa2bdcsm6801557wrx.98.2022.10.09.07.37.42 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:43 -0700 (PDT) Message-Id: <863063aefeeecfd23bb50eb111fcfbf5879a8ee3.1665326258.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:30 +0000 Subject: [PATCH 04/12] fsmonitor: deal with synthetic firmlinks on macOS Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Starting with macOS 10.15 (Catalina), Apple introduced a new feature called 'firmlinks' in order to separate the boot volume into two volumes, one read-only and one writable but still present them to the user as a single volume. Along with this change, Apple removed the ability to create symlinks in the root directory and replaced them with 'synthetic firmlinks'. See 'man synthetic.conf' When FSEevents reports the path of changed files, if the path involves a synthetic firmlink, the path is reported from the point of the synthetic firmlink and not the real path. For example: Real path: /System/Volumes/Data/network/working/directory/foo.txt Synthetic firmlink: /network -> /System/Volumes/Data/network FSEvents path: /network/working/directory/foo.txt This causes the FSEvents path to not match against the worktree directory. There are several ways in which synthetic firmlinks can be created: they can be defined in /etc/synthetic.conf, the automounter can create them, and there may be other means. Simply reading /etc/synthetic.conf is insufficient. No matter what process creates synthetic firmlinks, they all get created in the root directory. Therefore, in order to deal with synthetic firmlinks, the root directory is scanned and the first possible synthetic firmink that, when resolved, is a prefix of the worktree is used to map FSEvents paths to worktree paths. Signed-off-by: Eric DeCosta --- builtin/fsmonitor--daemon.c | 8 +++ compat/fsmonitor/fsm-listen-darwin.c | 14 +++- compat/fsmonitor/fsm-path-utils-darwin.c | 92 ++++++++++++++++++++++++ compat/fsmonitor/fsm-path-utils-win32.c | 17 +++++ fsmonitor--daemon.h | 3 + fsmonitor-path-utils.h | 36 +++++++++- 6 files changed, 167 insertions(+), 3 deletions(-) diff --git a/builtin/fsmonitor--daemon.c b/builtin/fsmonitor--daemon.c index 0123fc33ed2..7a4cb78c7dd 100644 --- a/builtin/fsmonitor--daemon.c +++ b/builtin/fsmonitor--daemon.c @@ -3,6 +3,7 @@ #include "parse-options.h" #include "fsmonitor.h" #include "fsmonitor-ipc.h" +#include "fsmonitor-path-utils.h" #include "compat/fsmonitor/fsm-health.h" #include "compat/fsmonitor/fsm-listen.h" #include "fsmonitor--daemon.h" @@ -1282,6 +1283,11 @@ static int fsmonitor_run_daemon(void) strbuf_addstr(&state.path_worktree_watch, absolute_path(get_git_work_tree())); state.nr_paths_watching = 1; + strbuf_init(&state.alias.alias, 0); + strbuf_init(&state.alias.points_to, 0); + if ((err = fsmonitor__get_alias(state.path_worktree_watch.buf, &state.alias))) + goto done; + /* * We create and delete cookie files somewhere inside the .git * directory to help us keep sync with the file system. If @@ -1391,6 +1397,8 @@ done: strbuf_release(&state.path_gitdir_watch); strbuf_release(&state.path_cookie_prefix); strbuf_release(&state.path_ipc); + strbuf_release(&state.alias.alias); + strbuf_release(&state.alias.points_to); return err; } diff --git a/compat/fsmonitor/fsm-listen-darwin.c b/compat/fsmonitor/fsm-listen-darwin.c index 8e208e8289e..daeee4e465c 100644 --- a/compat/fsmonitor/fsm-listen-darwin.c +++ b/compat/fsmonitor/fsm-listen-darwin.c @@ -26,6 +26,7 @@ #include "fsmonitor.h" #include "fsm-listen.h" #include "fsmonitor--daemon.h" +#include "fsmonitor-path-utils.h" struct fsm_listen_data { @@ -198,8 +199,9 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef, struct string_list cookie_list = STRING_LIST_INIT_DUP; const char *path_k; const char *slash; - int k; + char *resolved = NULL; struct strbuf tmp = STRBUF_INIT; + int k; /* * Build a list of all filesystem changes into a private/local @@ -209,7 +211,12 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef, /* * On Mac, we receive an array of absolute paths. */ - path_k = paths[k]; + free(resolved); + resolved = fsmonitor__resolve_alias(paths[k], &state->alias); + if (resolved) + path_k = resolved; + else + path_k = paths[k]; /* * If you want to debug FSEvents, log them to GIT_TRACE_FSMONITOR. @@ -238,6 +245,7 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef, fsmonitor_force_resync(state); fsmonitor_batch__free_list(batch); string_list_clear(&cookie_list, 0); + batch = NULL; /* * We assume that any events that we received @@ -360,12 +368,14 @@ static void fsevent_callback(ConstFSEventStreamRef streamRef, } } + free(resolved); fsmonitor_publish(state, batch, &cookie_list); string_list_clear(&cookie_list, 0); strbuf_release(&tmp); return; force_shutdown: + free(resolved); fsmonitor_batch__free_list(batch); string_list_clear(&cookie_list, 0); diff --git a/compat/fsmonitor/fsm-path-utils-darwin.c b/compat/fsmonitor/fsm-path-utils-darwin.c index d46d7f13538..ce5a8febe09 100644 --- a/compat/fsmonitor/fsm-path-utils-darwin.c +++ b/compat/fsmonitor/fsm-path-utils-darwin.c @@ -1,5 +1,8 @@ #include "fsmonitor.h" #include "fsmonitor-path-utils.h" +#include +#include +#include #include #include @@ -41,3 +44,92 @@ int fsmonitor__is_fs_remote(const char *path) return fs.is_remote; } + +/* + * Scan the root directory for synthetic firmlinks that when resolved + * are a prefix of the path, stopping at the first one found. + * + * Some information about firmlinks and synthetic firmlinks: + * https://eclecticlight.co/2020/01/23/catalina-boot-volumes/ + * + * macOS no longer allows symlinks in the root directory; any link found + * there is therefore a synthetic firmlink. + * + * If this function gets called often, will want to cache all the firmlink + * information, but for now there is only one caller of this function. + * + * If there is more than one alias for the path, that is another + * matter altogether. + */ +int fsmonitor__get_alias(const char *path, struct alias_info *info) +{ + DIR *dir; + int retval = -1; + const char *const root = "/"; + struct stat st; + struct dirent *de; + struct strbuf alias; + struct strbuf points_to = STRBUF_INIT; + + dir = opendir(root); + if (!dir) + return error_errno(_("opendir('%s') failed"), root); + + strbuf_init(&alias, 256); + + while ((de = readdir(dir)) != NULL) { + strbuf_reset(&alias); + strbuf_addf(&alias, "%s%s", root, de->d_name); + + if (lstat(alias.buf, &st) < 0) { + error_errno(_("lstat('%s') failed"), alias.buf); + goto done; + } + + if (!S_ISLNK(st.st_mode)) + continue; + + if (strbuf_readlink(&points_to, alias.buf, st.st_size) < 0) { + error_errno(_("strbuf_readlink('%s') failed"), alias.buf); + goto done; + } + + if (!strncmp(points_to.buf, path, points_to.len) && + (path[points_to.len] == '/')) { + strbuf_addbuf(&info->alias, &alias); + strbuf_addbuf(&info->points_to, &points_to); + trace_printf_key(&trace_fsmonitor, + "Found alias for '%s' : '%s' -> '%s'", + path, info->alias.buf, info->points_to.buf); + retval = 0; + goto done; + } + } + retval = 0; /* no alias */ + +done: + strbuf_release(&alias); + strbuf_release(&points_to); + if (closedir(dir) < 0) + return error_errno(_("closedir('%s') failed"), root); + return retval; +} + +char *fsmonitor__resolve_alias(const char *path, + const struct alias_info *info) +{ + if (!info->alias.len) + return NULL; + + if ((!strncmp(info->alias.buf, path, info->alias.len)) + && path[info->alias.len] == '/') { + struct strbuf tmp = STRBUF_INIT; + const char *remainder = path + info->alias.len; + + strbuf_addbuf(&tmp, &info->points_to); + strbuf_add(&tmp, remainder, strlen(remainder)); + return strbuf_detach(&tmp, NULL); + } + + return NULL; +} diff --git a/compat/fsmonitor/fsm-path-utils-win32.c b/compat/fsmonitor/fsm-path-utils-win32.c index a90b8f7925b..0d95bbb416f 100644 --- a/compat/fsmonitor/fsm-path-utils-win32.c +++ b/compat/fsmonitor/fsm-path-utils-win32.c @@ -126,3 +126,20 @@ int fsmonitor__is_fs_remote(const char *path) return -1; return fs.is_remote; } + +/* + * No-op for now. + */ +int fsmonitor__get_alias(const char *path, struct alias_info *info) +{ + return 0; +} + +/* + * No-op for now. + */ +char *fsmonitor__resolve_alias(const char *path, + const struct alias_info *info) +{ + return NULL; +} diff --git a/fsmonitor--daemon.h b/fsmonitor--daemon.h index 2102a5c9ff5..e24838f9a86 100644 --- a/fsmonitor--daemon.h +++ b/fsmonitor--daemon.h @@ -8,6 +8,7 @@ #include "run-command.h" #include "simple-ipc.h" #include "thread-utils.h" +#include "fsmonitor-path-utils.h" struct fsmonitor_batch; struct fsmonitor_token_data; @@ -43,6 +44,7 @@ struct fsmonitor_daemon_state { struct strbuf path_worktree_watch; struct strbuf path_gitdir_watch; + struct alias_info alias; int nr_paths_watching; struct fsmonitor_token_data *current_token_data; @@ -59,6 +61,7 @@ struct fsmonitor_daemon_state { struct ipc_server_data *ipc_server_data; struct strbuf path_ipc; + }; /* diff --git a/fsmonitor-path-utils.h b/fsmonitor-path-utils.h index 41edf5b934f..5bfdfb81c14 100644 --- a/fsmonitor-path-utils.h +++ b/fsmonitor-path-utils.h @@ -1,13 +1,21 @@ #ifndef FSM_PATH_UTILS_H #define FSM_PATH_UTILS_H +#include "strbuf.h" + +struct alias_info +{ + struct strbuf alias; + struct strbuf points_to; +}; + struct fs_info { int is_remote; char *typename; }; /* - * Get some basic filesystem informtion for the given path + * Get some basic filesystem information for the given path * * The caller owns the storage that is occupied by fs_info and * is responsible for releasing it. @@ -23,4 +31,30 @@ int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info); */ int fsmonitor__is_fs_remote(const char *path); +/* + * Get the alias in given path, if any. + * + * Sets alias to the first alias that matches any part of the path. + * + * If an alias is found, info.alias and info.points_to are set to the + * found mapping. + * + * Returns -1 on error, 0 otherwise. + * + * The caller owns the storage that is occupied by info.alias and + * info.points_to and is responsible for releasing it. + */ +int fsmonitor__get_alias(const char *path, struct alias_info *info); + +/* + * Resolve the path against the given alias. + * + * Returns the resolved path if there is one, NULL otherwise. + * + * The caller owns the storage that the returned string occupies and + * is responsible for releasing it. + */ +char *fsmonitor__resolve_alias(const char *path, + const struct alias_info *info); + #endif From patchwork Sun Oct 9 14:37:31 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002025 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E63E7C433FE for ; Sun, 9 Oct 2022 14:37:59 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230211AbiJIOh6 (ORCPT ); Sun, 9 Oct 2022 10:37:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230133AbiJIOhr (ORCPT ); Sun, 9 Oct 2022 10:37:47 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 90A0E27DC4 for ; Sun, 9 Oct 2022 07:37:46 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id n12so13626608wrp.10 for ; Sun, 09 Oct 2022 07:37:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=bGtbzq+IH2Ws4ChKWDCxefvQxY0NorgXVM+ffiB3Qi0=; b=NaDrKYXI+dfK9/UpD3fJuxYb+prZXK9pmL3/a+bvCb/PBPwtJGkgYCa+Z4BPmh3rxu I4nD5bRL1eulfnlXERfqdnfsFREBXuVfGiCK+J7F7vnvfU+tFH1/cJaULhlO7hQfz867 KdRuJZ/XuxINqCBtAxedxHImRmuYpUIC7yrV4pNuBB9+Uw9CTIpKJFZKiTChq+YIiuUz ghwAAab+qVAV479mKBl/RTW87GsBlpw+GiXasKNi/tHc+IrMINtfY5wEOG1XALe4PX2o BdZqePixTW+GKo8Xy23aeZkkb57nRTpuCJ7WOOiL6MZTsSOCqRzwX6VlbWp+5ZYmhBQ/ bpiw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bGtbzq+IH2Ws4ChKWDCxefvQxY0NorgXVM+ffiB3Qi0=; b=tL0hBmOnxiai9BRsDAbGdJjF5cuY/xomXQMxjh5EAGuBzCL+stqkUpQliSFyc+yGNg RpVxDoIINEcQtqAZQBJFkvUX/yYkw1GGdGMPCBNvXQdLzmThg9PDzjqBnaP6/NHbVV1V 57EzL784U0g8YS38QITX+s6IEe1nLCxttQOAFxn0VllBIGwC1+kp6Kc4icKOt5e/1oeJ zVyCO0ajvNEaSUQHenS3nGhLXs17ufJzTPgo6X4vHFzYZAFk1hxI4vNseZoibrcUJHgj 7rZIyOQGpWAFjIwsfOmPDniTBlXS13LT0wgUDVY2Ca1PfAdN1iZqvzWzcXEx4FOGWSk5 +J2w== X-Gm-Message-State: ACrzQf2ryhNHnZS8W1Vfm3C9MZF4MqoOUpFUXFuE5+Rzq5lsclSUUQ7y 4AkHyCocg+VDVlOwqakJ5MmPWeZzoFo= X-Google-Smtp-Source: AMsMyM7obxphVuQcLKvjmzF/mXvV6goDjAeKI9rZvj57Pt/29UIlVJcSOiK8rOSC52MHalc1D0FvMg== X-Received: by 2002:a05:6000:112:b0:22e:58ce:40d4 with SMTP id o18-20020a056000011200b0022e58ce40d4mr9011898wrx.193.1665326264392; Sun, 09 Oct 2022 07:37:44 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id bi10-20020a05600c3d8a00b003b47ff307e1sm7709442wmb.31.2022.10.09.07.37.43 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:43 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:31 +0000 Subject: [PATCH 05/12] fsmonitor: check for compatability before communicating with fsmonitor Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta If fsmonitor is not in a compatible state, warn with an appropriate message. Signed-off-by: Eric DeCosta --- fsmonitor-settings.c | 10 +++++++--- fsmonitor-settings.h | 2 +- fsmonitor.c | 7 +++++++ 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/fsmonitor-settings.c b/fsmonitor-settings.c index 531a1b6f956..ee63a97dc51 100644 --- a/fsmonitor-settings.c +++ b/fsmonitor-settings.c @@ -1,6 +1,7 @@ #include "cache.h" #include "config.h" #include "repository.h" +#include "fsmonitor-ipc.h" #include "fsmonitor-settings.h" #include "fsmonitor-path-utils.h" @@ -242,10 +243,11 @@ enum fsmonitor_reason fsm_settings__get_reason(struct repository *r) return r->settings.fsmonitor->reason; } -char *fsm_settings__get_incompatible_msg(const struct repository *r, +char *fsm_settings__get_incompatible_msg(struct repository *r, enum fsmonitor_reason reason) { struct strbuf msg = STRBUF_INIT; + const char *socket_dir; switch (reason) { case FSMONITOR_REASON_UNTESTED: @@ -281,9 +283,11 @@ char *fsm_settings__get_incompatible_msg(const struct repository *r, goto done; case FSMONITOR_REASON_NOSOCKETS: + socket_dir = dirname((char *)fsmonitor_ipc__get_path(r)); strbuf_addf(&msg, - _("repository '%s' is incompatible with fsmonitor due to lack of Unix sockets"), - r->worktree); + _("socket directory '%s' is incompatible with fsmonitor due" + " to lack of Unix sockets support"), + socket_dir); goto done; } diff --git a/fsmonitor-settings.h b/fsmonitor-settings.h index 0721617b95a..ab02e3995ee 100644 --- a/fsmonitor-settings.h +++ b/fsmonitor-settings.h @@ -33,7 +33,7 @@ enum fsmonitor_mode fsm_settings__get_mode(struct repository *r); const char *fsm_settings__get_hook_path(struct repository *r); enum fsmonitor_reason fsm_settings__get_reason(struct repository *r); -char *fsm_settings__get_incompatible_msg(const struct repository *r, +char *fsm_settings__get_incompatible_msg(struct repository *r, enum fsmonitor_reason reason); struct fsmonitor_settings; diff --git a/fsmonitor.c b/fsmonitor.c index 57d6a483bee..540736b39fd 100644 --- a/fsmonitor.c +++ b/fsmonitor.c @@ -295,6 +295,7 @@ static int fsmonitor_force_update_threshold = 100; void refresh_fsmonitor(struct index_state *istate) { + static int warn_once = 0; struct strbuf query_result = STRBUF_INIT; int query_success = 0, hook_version = -1; size_t bol = 0; /* beginning of line */ @@ -305,6 +306,12 @@ void refresh_fsmonitor(struct index_state *istate) int is_trivial = 0; struct repository *r = istate->repo ? istate->repo : the_repository; enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r); + enum fsmonitor_reason reason = fsm_settings__get_reason(r); + + if (!warn_once && reason > FSMONITOR_REASON_OK) { + warn_once = 1; + warning("%s", fsm_settings__get_incompatible_msg(r, reason)); + } if (fsm_mode <= FSMONITOR_MODE_DISABLED || istate->fsmonitor_has_run_once) From patchwork Sun Oct 9 14:37:32 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002027 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 91529C433FE for ; Sun, 9 Oct 2022 14:38:03 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230217AbiJIOiB (ORCPT ); Sun, 9 Oct 2022 10:38:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46852 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230141AbiJIOhs (ORCPT ); Sun, 9 Oct 2022 10:37:48 -0400 Received: from mail-wr1-x42d.google.com (mail-wr1-x42d.google.com [IPv6:2a00:1450:4864:20::42d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 41FED27CCD for ; Sun, 9 Oct 2022 07:37:47 -0700 (PDT) Received: by mail-wr1-x42d.google.com with SMTP id bv10so10088706wrb.4 for ; Sun, 09 Oct 2022 07:37:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=NZZ/jRI252DzMeVq+3yot+76+uTRZX0nJIDrWhlOFuE=; b=Z6QnnwL76/B0+k2XLphhue+RGYap+mtJB0Se946r/qIFdKv9Xq0I1rF40SNPf/9Hge 1WE/Kt2VmS6NCUlU867qNF0lgf0WpzaTYTekAOWeIQu2kpzxIEry37j8sRSDQpZGZZSK C3y9yNTkRXGFMmtGbWIq0V9+fx/yexsII3N4sbjKDTv4JfjVJLgriUpzl+9OOdNihZs2 hqaJsw1nLxJMQYVNFLeYxTOFrhp5/BZP96nGWYDUHa2sq970UB7izwOIh1+ZW76sCCWM wNWCeaz2FzvSVA6MOBncqax18T1cFshOonBkGRmb31EXfsUxoXlv7bKQEz7Sq6MVdwq2 Q8TQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=NZZ/jRI252DzMeVq+3yot+76+uTRZX0nJIDrWhlOFuE=; b=mN3386Y2tDNoOeqFZV7wJqqzhJu6Hq/s+WjmMFkNxrLhyty2x7wnVpZBZ9fTL6hCHt x+dnmd4z3jXV6JxIEXb/einCPp0k48D10UD/MR/7nLqhjtoiFbfoXqT+aJbDIw4GshW7 WeAQHx2nyUUbdW483wfgqikiPt5KTJPX5DGGqGt0VI+66EpZecKB2AyTTiuO3xGaHInI LwtGnF3n0wWNfGyVc3L+HCY5/wqJYGkoFqmLbxnUj7f+oUssUbHQm4ihId0d7fSpdeBu F04cevX/nIaVPYM62veVYS4gcbL/s+PO8CSCILuSmK5kJ5SB9gbraBqAUxZpYTexwqZr fqYA== X-Gm-Message-State: ACrzQf1a6X5bcc1vItIqkB8IUwRlu9jiN9EVXs08qs9CYU/2RPyIpR8w MDMALkTemCXeoRYGxrHF2w3L2GB6Fls= X-Google-Smtp-Source: AMsMyM5kLRTfKF2kJV8gFVJxiURQ4UUq2HUNApO8KOoOA7sw7mn0nZbonBe7dwsAfjxBcb5cR3fYFw== X-Received: by 2002:adf:f011:0:b0:22e:4485:34c2 with SMTP id j17-20020adff011000000b0022e448534c2mr9432149wro.593.1665326265438; Sun, 09 Oct 2022 07:37:45 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id l19-20020a05600c089300b003c5571c27a1sm3853675wmp.32.2022.10.09.07.37.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:44 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:32 +0000 Subject: [PATCH 06/12] fsmonitor: add documentation for allowRemote and socketDir options Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Add documentation for 'fsmonitor.allowRemote' and 'fsmonitor.socketDir'. Call-out experimental nature of 'fsmonitor.allowRemote' and limited filesystem support for 'fsmonitor.socketDir'. Signed-off-by: Eric DeCosta --- Documentation/config.txt | 2 ++ Documentation/config/fsmonitor--daemon.txt | 11 +++++++ Documentation/git-fsmonitor--daemon.txt | 37 ++++++++++++++++++++-- 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 Documentation/config/fsmonitor--daemon.txt diff --git a/Documentation/config.txt b/Documentation/config.txt index 5b5b9765699..1e205831656 100644 --- a/Documentation/config.txt +++ b/Documentation/config.txt @@ -423,6 +423,8 @@ include::config/filter.txt[] include::config/fsck.txt[] +include::config/fsmonitor--daemon.txt[] + include::config/gc.txt[] include::config/gitcvs.txt[] diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt new file mode 100644 index 00000000000..c225c6c9e74 --- /dev/null +++ b/Documentation/config/fsmonitor--daemon.txt @@ -0,0 +1,11 @@ +fsmonitor.allowRemote:: + By default, the fsmonitor daemon refuses to work against network-mounted + repositories. Setting `fsmonitor.allowRemote` to `true` overrides this + behavior. Only respected when `core.fsmonitor` is set to `true`. + +fsmonitor.socketDir:: + This Mac OS-specific option, if set, specifies the directory in + which to create the Unix domain socket used for communication + between the fsmonitor daemon and various Git commands. The directory must + reside on a native Mac OS filesystem. Only respected when `core.fsmonitor` + is set to `true`. diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt index cc142fb8612..8238eadb0e1 100644 --- a/Documentation/git-fsmonitor--daemon.txt +++ b/Documentation/git-fsmonitor--daemon.txt @@ -3,7 +3,7 @@ git-fsmonitor{litdd}daemon(1) NAME ---- -git-fsmonitor--daemon - A Built-in File System Monitor +git-fsmonitor--daemon - A Built-in Filesystem Monitor SYNOPSIS -------- @@ -17,7 +17,7 @@ DESCRIPTION ----------- A daemon to watch the working directory for file and directory -changes using platform-specific file system notification facilities. +changes using platform-specific filesystem notification facilities. This daemon communicates directly with commands like `git status` using the link:technical/api-simple-ipc.html[simple IPC] interface @@ -63,13 +63,44 @@ CAVEATS ------- The fsmonitor daemon does not currently know about submodules and does -not know to filter out file system events that happen within a +not know to filter out filesystem events that happen within a submodule. If fsmonitor daemon is watching a super repo and a file is modified within the working directory of a submodule, it will report the change (as happening against the super repo). However, the client will properly ignore these extra events, so performance may be affected but it will not cause an incorrect result. +By default, the fsmonitor daemon refuses to work against network-mounted +repositories; this may be overridden by setting `fsmonitor.allowRemote` to +`true`. Note, however, that the fsmonitor daemon is not guaranteed to work +correctly with all network-mounted repositories and such use is considered +experimental. + +On Mac OS, the inter-process communication (IPC) between various Git +commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a +special type of file -- which is supported by native Mac OS filesystems, +but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems +may or may not have the needed support; the fsmonitor daemon is not guaranteed +to work with these filesystems and such use is considered experimental. + +By default, the socket is created in the `.git` directory, however, if the +`.git` directory is on a network-mounted filesystem, it will be instead be +created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a +network-mounted filesystem in which case you must set the configuration +variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native +filesystem in which to create the socket file. + +If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`) +is on a native Mac OS file filesystem the fsmonitor daemon will report an +error that will cause the daemon and the currently running command to exit. + +CONFIGURATION +------------- + +include::includes/cmd-config-section-all.txt[] + +include::config/fsmonitor--daemon.txt[] + GIT --- Part of the linkgit:git[1] suite From patchwork Sun Oct 9 14:37:33 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002028 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9EEDDC433F5 for ; Sun, 9 Oct 2022 14:38:04 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230219AbiJIOiD (ORCPT ); Sun, 9 Oct 2022 10:38:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46838 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230185AbiJIOht (ORCPT ); Sun, 9 Oct 2022 10:37:49 -0400 Received: from mail-wm1-x32d.google.com (mail-wm1-x32d.google.com [IPv6:2a00:1450:4864:20::32d]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2AD64275C8 for ; Sun, 9 Oct 2022 07:37:48 -0700 (PDT) Received: by mail-wm1-x32d.google.com with SMTP id az22-20020a05600c601600b003c6b72797fdso13341wmb.5 for ; Sun, 09 Oct 2022 07:37:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=G8v2wzdj3RYBwH0aN/4T234ARZhUZMQ2Y2dPmI5NLhs=; b=JlUGF5iEqZELO4o3PJJoGT2PHI65aStITXM0kYQplF0aNpuBMZStrOp3d5HwGLCLfx J8/XhnuDjbRqdyRbREN+c2sIm1DyttkXApWqUp+Y4QMu+s9P9yr3OaacdvXF+s3JqOaw XBrUYciQxHN/IU9oPWw1MT1fcbyol13VmMAwpHJzi8/25tgAkRdkyhbZvcjIpX3AdcCV Pm92EhRspNUHvHOh7VnaFvAwuMSoiv5F+w5QJQpB0iFbgqSklNC1l/n4DFu6zqrGHm3I Kp/PoGCZWjC71EVPS3NcOGyU9KTk5aZ2K+c6LC0sIEh7f6eQ91/p18WLUhUfHFcUFrsI 0f5w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=G8v2wzdj3RYBwH0aN/4T234ARZhUZMQ2Y2dPmI5NLhs=; b=QP5h8qwBxJI4Pi8lr1sWzAJ0QfrKUsWSOxc/kzEY1zwYkIIEs6G2jD6shzjQwlYx0V tGVX4EIKD4xr358JAdimBYgJKHAoFLyFJMCD5I+e0dYD92PzMK0tTWcKrLIgzt8gWDyz oT8aKhnxawaUTIfTPOsNcxTwMhU2COmtyEtNjiWB28Y2nZbYw+yVkWCvGlvfsPT9Wtb0 cm/7/48yNoAXiwRo0OpGEFkqj8vjllIx4aRLMCFIiFQM+3KnIFeqvCUTEyiehtlWqbAi +GcWA6IxaHwyHoJVj4Y0fIh+ByI7IdxhIvxCrkZiHQ2XXOnDbuas+UbbW0hiFr+iDKRI QYmA== X-Gm-Message-State: ACrzQf1YpM2SJlHPD7OS4Zv7dsQcHbU6JJq7tWuXOftOxSPfz+tZOFaR 8jaZtKoPW052j8d+d2jfBVR2zD0owI4= X-Google-Smtp-Source: AMsMyM6OAgUComcfE3gJslGXcgGykPCs5IogTjmeRognCg2w/F4T/ibgbBXw8wO6XS/4YtqufpUmCQ== X-Received: by 2002:a05:600c:3c8e:b0:3b4:d224:ae27 with SMTP id bg14-20020a05600c3c8e00b003b4d224ae27mr9728571wmb.187.1665326266378; Sun, 09 Oct 2022 07:37:46 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id v24-20020a1cf718000000b003a6125562e1sm7478241wmh.46.2022.10.09.07.37.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:45 -0700 (PDT) Message-Id: In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:33 +0000 Subject: [PATCH 07/12] fsmonitor: prepare to share code between Mac OS and Linux Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Linux and Mac OS can share some of the code originally developed for Mac OS. Rename the shared code from compat/fsmonitor/fsm-*-dawrin.c to compat/fsmonitor/fsm-*-unix.c Update the build to enable sharing of the fsm-*-unix.c files. Minor update to compat/fsmonitor/fsm-ipc-unix.c to make it cross-platform. Signed-off-by: Eric DeCosta --- Makefile | 6 +++--- .../fsmonitor/{fsm-health-darwin.c => fsm-health-unix.c} | 0 compat/fsmonitor/{fsm-ipc-darwin.c => fsm-ipc-unix.c} | 8 ++++---- .../{fsm-settings-darwin.c => fsm-settings-unix.c} | 0 config.mak.uname | 4 ++++ contrib/buildsystems/CMakeLists.txt | 6 +++--- 6 files changed, 14 insertions(+), 10 deletions(-) rename compat/fsmonitor/{fsm-health-darwin.c => fsm-health-unix.c} (100%) rename compat/fsmonitor/{fsm-ipc-darwin.c => fsm-ipc-unix.c} (89%) rename compat/fsmonitor/{fsm-settings-darwin.c => fsm-settings-unix.c} (100%) diff --git a/Makefile b/Makefile index feb675a6959..31dd6ab2734 100644 --- a/Makefile +++ b/Makefile @@ -2038,13 +2038,13 @@ endif ifdef FSMONITOR_DAEMON_BACKEND COMPAT_CFLAGS += -DHAVE_FSMONITOR_DAEMON_BACKEND COMPAT_OBJS += compat/fsmonitor/fsm-listen-$(FSMONITOR_DAEMON_BACKEND).o - COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_BACKEND).o - COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_BACKEND).o + COMPAT_OBJS += compat/fsmonitor/fsm-health-$(FSMONITOR_DAEMON_COMMON).o + COMPAT_OBJS += compat/fsmonitor/fsm-ipc-$(FSMONITOR_DAEMON_COMMON).o endif ifdef FSMONITOR_OS_SETTINGS COMPAT_CFLAGS += -DHAVE_FSMONITOR_OS_SETTINGS - COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_OS_SETTINGS).o + COMPAT_OBJS += compat/fsmonitor/fsm-settings-$(FSMONITOR_DAEMON_COMMON).o COMPAT_OBJS += compat/fsmonitor/fsm-path-utils-$(FSMONITOR_OS_SETTINGS).o endif diff --git a/compat/fsmonitor/fsm-health-darwin.c b/compat/fsmonitor/fsm-health-unix.c similarity index 100% rename from compat/fsmonitor/fsm-health-darwin.c rename to compat/fsmonitor/fsm-health-unix.c diff --git a/compat/fsmonitor/fsm-ipc-darwin.c b/compat/fsmonitor/fsm-ipc-unix.c similarity index 89% rename from compat/fsmonitor/fsm-ipc-darwin.c rename to compat/fsmonitor/fsm-ipc-unix.c index ce843d63348..3ba3b9e17ed 100644 --- a/compat/fsmonitor/fsm-ipc-darwin.c +++ b/compat/fsmonitor/fsm-ipc-unix.c @@ -10,7 +10,7 @@ static GIT_PATH_FUNC(fsmonitor_ipc__get_default_path, "fsmonitor--daemon.ipc") const char *fsmonitor_ipc__get_path(struct repository *r) { static const char *ipc_path = NULL; - SHA_CTX sha1ctx; + git_SHA_CTX sha1ctx; char *sock_dir = NULL; struct strbuf ipc_file = STRBUF_INIT; unsigned char hash[SHA_DIGEST_LENGTH]; @@ -28,9 +28,9 @@ const char *fsmonitor_ipc__get_path(struct repository *r) return ipc_path; } - SHA1_Init(&sha1ctx); - SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree)); - SHA1_Final(hash, &sha1ctx); + git_SHA1_Init(&sha1ctx); + git_SHA1_Update(&sha1ctx, r->worktree, strlen(r->worktree)); + git_SHA1_Final(hash, &sha1ctx); repo_config_get_string(r, "fsmonitor.socketdir", &sock_dir); diff --git a/compat/fsmonitor/fsm-settings-darwin.c b/compat/fsmonitor/fsm-settings-unix.c similarity index 100% rename from compat/fsmonitor/fsm-settings-darwin.c rename to compat/fsmonitor/fsm-settings-unix.c diff --git a/config.mak.uname b/config.mak.uname index d63629fe807..d454cec47c4 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -68,6 +68,7 @@ ifeq ($(uname_S),Linux) ifneq ($(findstring .el7.,$(uname_R)),) BASIC_CFLAGS += -std=c99 endif + endif ifeq ($(uname_S),GNU/kFreeBSD) HAVE_ALLOCA_H = YesPlease @@ -165,6 +166,7 @@ ifeq ($(uname_S),Darwin) ifndef NO_UNIX_SOCKETS FSMONITOR_DAEMON_BACKEND = darwin FSMONITOR_OS_SETTINGS = darwin + FSMONITOR_DAEMON_COMMON = unix endif endif @@ -453,6 +455,7 @@ ifeq ($(uname_S),Windows) # support it. FSMONITOR_DAEMON_BACKEND = win32 FSMONITOR_OS_SETTINGS = win32 + FSMONITOR_DAEMON_COMMON = win32 NO_SVN_TESTS = YesPlease RUNTIME_PREFIX = YesPlease @@ -645,6 +648,7 @@ ifeq ($(uname_S),MINGW) # support it. FSMONITOR_DAEMON_BACKEND = win32 FSMONITOR_OS_SETTINGS = win32 + FSMONITOR_DAEMON_COMMON = win32 RUNTIME_PREFIX = YesPlease HAVE_WPGMPTR = YesWeDo diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 787738e6fa3..0b26a1a36e3 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -315,13 +315,13 @@ if(SUPPORTS_SIMPLE_IPC) list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-win32.c) elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-unix.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-unix.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-darwin.c) - list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-darwin.c) - list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-darwin.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-darwin.c) add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS) - list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-darwin.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-unix.c) endif() endif() From patchwork Sun Oct 9 14:37:34 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002029 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id C8F4FC433F5 for ; Sun, 9 Oct 2022 14:38:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230223AbiJIOiF (ORCPT ); Sun, 9 Oct 2022 10:38:05 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46874 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230199AbiJIOhu (ORCPT ); Sun, 9 Oct 2022 10:37:50 -0400 Received: from mail-wr1-x435.google.com (mail-wr1-x435.google.com [IPv6:2a00:1450:4864:20::435]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0FE6B2716B for ; Sun, 9 Oct 2022 07:37:49 -0700 (PDT) Received: by mail-wr1-x435.google.com with SMTP id w18so13657677wro.7 for ; Sun, 09 Oct 2022 07:37:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=aCfXpNh5txAG/yjAWSL2RLjvzxamc22TUvq9C7Fo7ZQ=; b=nzB5zufktrFaazcUHNrV+v5pw4b8TiTHLy6sE+6emCnVZuTV/bTn6k+TB6nau5+dNb 0w3BNbqmnsde4X4sBsfKt5T5B/EBlHbMVgmtL68CkkSwCnc2QuOTscvQJ3TER4DHNBEC v8OyrTSWdvMK9EvzM0yLwUHnQ6z0tfYaHIUkQf/Z9a2VJph8vxQTfE4weTeqB/oLRgId 5CePJYdwL/23CXtvMQwlvaxggUqWZDIegmYUpk/1mpfKFCZad4Q+ws388tS0bdlgWGOS HJ2gZsrdUTxBJV20U//aJ7GFwwUG7tfMp99LWZSEdVIbtAhhSsDsPM60dHT1ekPwWCUu uWnQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=aCfXpNh5txAG/yjAWSL2RLjvzxamc22TUvq9C7Fo7ZQ=; b=zB/Ah2hmFDYORmxCcvSYUns5UXoAD/rY+FF0Z3zkQ6Sowz5IK0e/vu9LEZAr9Jvamw UIyE0S46pIdcrpSHvxVUBFzu0OZt0TvpRWxaTx9yEF42AQWP9nCIjS0b1Pk8CcJcGcq+ Ho9PoKpQrsJ6DlGYN+kf02fGGiBCHvdTkbiUwcQKL93bl4tB9sqZRrvkMULv2SIRPcJ4 GUVkEXDdlnlpGLpW97vNU3QWHcEPyCjJC1wHiqhAUDt0d1FY0mFmgclLJeDs0Z5ujHjV QQB4U5rUBL+3kmVmjMt/5d1PQzEDp930uWtY7pbQL7IxEi4y/d/YiLAg1lR4hbosbbSm aeBg== X-Gm-Message-State: ACrzQf2xt5/SYPsdiDuWBx4oKJcNStPzG6kOzIDZGwKU/W90jBQe8uM4 va4bPH+19mDc7v0UUIPIretH8eZPIs8= X-Google-Smtp-Source: AMsMyM4+rskFvqScN3eu+Rh5RNRDuyrt1jqA6dwEc+qWR4NJVwXRyDSYMpHi6+jUERLF7jgZpZUubw== X-Received: by 2002:a5d:6b0e:0:b0:22a:2cb1:6605 with SMTP id v14-20020a5d6b0e000000b0022a2cb16605mr8629214wrw.552.1665326267327; Sun, 09 Oct 2022 07:37:47 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id f8-20020a5d50c8000000b0022e36c1113fsm6824958wrt.13.2022.10.09.07.37.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:46 -0700 (PDT) Message-Id: <5ecbb3082f16956d049cfa98662f8e3384a6aea2.1665326258.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:34 +0000 Subject: [PATCH 08/12] fsmonitor: determine if filesystem is local or remote Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Compare the given path to the mounted filesystems. Find the mount that is the longest prefix of the path (if any) and determine if that mount is on a local or remote filesystem. Signed-off-by: Eric DeCosta --- compat/fsmonitor/fsm-path-utils-linux.c | 163 ++++++++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 compat/fsmonitor/fsm-path-utils-linux.c diff --git a/compat/fsmonitor/fsm-path-utils-linux.c b/compat/fsmonitor/fsm-path-utils-linux.c new file mode 100644 index 00000000000..369692a788f --- /dev/null +++ b/compat/fsmonitor/fsm-path-utils-linux.c @@ -0,0 +1,163 @@ +#include "fsmonitor.h" +#include "fsmonitor-path-utils.h" +#include +#include +#include +#include + +/* + * https://github.com/coreutils/gnulib/blob/master/lib/mountlist.c + */ +#ifndef ME_REMOTE +/* A file system is "remote" if its Fs_name contains a ':' + or if (it is of type (smbfs or cifs) and its Fs_name starts with '//') + or if it is of any other of the listed types + or Fs_name is equal to "-hosts" (used by autofs to mount remote fs). + "VM" file systems like prl_fs or vboxsf are not considered remote here. */ +# define ME_REMOTE(Fs_name, Fs_type) \ + (strchr (Fs_name, ':') != NULL \ + || ((Fs_name)[0] == '/' \ + && (Fs_name)[1] == '/' \ + && (strcmp (Fs_type, "smbfs") == 0 \ + || strcmp (Fs_type, "smb3") == 0 \ + || strcmp (Fs_type, "cifs") == 0)) \ + || strcmp (Fs_type, "acfs") == 0 \ + || strcmp (Fs_type, "afs") == 0 \ + || strcmp (Fs_type, "coda") == 0 \ + || strcmp (Fs_type, "auristorfs") == 0 \ + || strcmp (Fs_type, "fhgfs") == 0 \ + || strcmp (Fs_type, "gpfs") == 0 \ + || strcmp (Fs_type, "ibrix") == 0 \ + || strcmp (Fs_type, "ocfs2") == 0 \ + || strcmp (Fs_type, "vxfs") == 0 \ + || strcmp ("-hosts", Fs_name) == 0) +#endif + +static struct mntent *find_mount(const char *path, const struct statvfs *fs) +{ + const char *const mounts = "/proc/mounts"; + const char *rp = real_pathdup(path, 1); + struct mntent *ment = NULL; + struct mntent *found = NULL; + struct statvfs mntfs; + FILE *fp; + int dlen, plen, flen = 0; + + fp = setmntent(mounts, "r"); + if (!fp) { + error_errno(_("setmntent('%s') failed"), mounts); + return NULL; + } + + plen = strlen(rp); + + /* read all the mount information and compare to path */ + while ((ment = getmntent(fp)) != NULL) { + if (statvfs(ment->mnt_dir, &mntfs)) { + switch (errno) { + case EPERM: + case ESRCH: + case EACCES: + continue; + default: + error_errno(_("statvfs('%s') failed"), ment->mnt_dir); + endmntent(fp); + return NULL; + } + } + + /* is mount on the same filesystem and is a prefix of the path */ + if ((fs->f_fsid == mntfs.f_fsid) && + !strncmp(ment->mnt_dir, rp, strlen(ment->mnt_dir))) { + dlen = strlen(ment->mnt_dir); + if (dlen > plen) + continue; + /* + * root is always a potential match; otherwise look for + * directory prefix + */ + if ((dlen == 1 && ment->mnt_dir[0] == '/') || + (dlen > flen && (!rp[dlen] || rp[dlen] == '/'))) { + flen = dlen; + /* + * https://man7.org/linux/man-pages/man3/getmntent.3.html + * + * The pointer points to a static area of memory which is + * overwritten by subsequent calls to getmntent(). + */ + if (!found) + CALLOC_ARRAY(found, 1); + free(found->mnt_dir); + free(found->mnt_type); + free(found->mnt_fsname); + found->mnt_dir = xmemdupz(ment->mnt_dir, strlen(ment->mnt_dir)); + found->mnt_type = xmemdupz(ment->mnt_type, strlen(ment->mnt_type)); + found->mnt_fsname = xmemdupz(ment->mnt_fsname, strlen(ment->mnt_fsname)); + } + } + } + endmntent(fp); + + return found; +} + +int fsmonitor__get_fs_info(const char *path, struct fs_info *fs_info) +{ + struct mntent *ment; + struct statvfs fs; + + if (statvfs(path, &fs)) + return error_errno(_("statvfs('%s') failed"), path); + + ment = find_mount(path, &fs); + if (!ment) + return -1; + + trace_printf_key(&trace_fsmonitor, + "statvfs('%s') [flags 0x%08lx] '%s' '%s'", + path, fs.f_flag, ment->mnt_type, ment->mnt_fsname); + + if (ME_REMOTE(ment->mnt_fsname, ment->mnt_type)) + fs_info->is_remote = 1; + else + fs_info->is_remote = 0; + + fs_info->typename = ment->mnt_fsname; + free(ment->mnt_dir); + free(ment->mnt_type); + free(ment); + + trace_printf_key(&trace_fsmonitor, + "'%s' is_remote: %d", + path, fs_info->is_remote); + return 0; +} + +int fsmonitor__is_fs_remote(const char *path) +{ + struct fs_info fs; + + if (fsmonitor__get_fs_info(path, &fs)) + return -1; + + free(fs.typename); + + return fs.is_remote; +} + +/* + * No-op for now. + */ +int fsmonitor__get_alias(const char *path, struct alias_info *info) +{ + return 0; +} + +/* + * No-op for now. + */ +char *fsmonitor__resolve_alias(const char *path, + const struct alias_info *info) +{ + return NULL; +} From patchwork Sun Oct 9 14:37:35 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002030 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9362FC433FE for ; Sun, 9 Oct 2022 14:38:10 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230225AbiJIOiJ (ORCPT ); Sun, 9 Oct 2022 10:38:09 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46890 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230140AbiJIOhv (ORCPT ); Sun, 9 Oct 2022 10:37:51 -0400 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 34969275D5 for ; Sun, 9 Oct 2022 07:37:49 -0700 (PDT) Received: by mail-wr1-x42a.google.com with SMTP id bk15so13614801wrb.13 for ; Sun, 09 Oct 2022 07:37:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=w44EzucuxXvW7CuZGC5TbA6vWYPe1HfW/ZV2FLHeXXQ=; b=UkA6V+Snzarv1yPzmTVYLFATA85YpU60PNts5DQDT+CjOZMZVtuQbJuX9mj1oxjF9q AAxL8dfg7nmaBYgZdwG3qX0Rik5XU74bbPxBUIvzbDfqT8a5vDW9hxzFM1t8WZgphzd5 F1SWJyQhUzySG4HvqUkZT6zG0pZpN0kAekGFFvKPk/TW+pZ7iZZcuP9S0vau+kY39pbQ DPQI29fLm9bCp+ZAj2PiR6rlROd4F/XyDbtFFo/V9+pQ1fEB8aEfNqjV0GE+tJAZowgf LuysrNPDPUHBBBp/bcmFguqsvbQ+ikoJwY//96o2wZ4DeCiPH27cgLBpfF03dJR+mng/ aYoA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=w44EzucuxXvW7CuZGC5TbA6vWYPe1HfW/ZV2FLHeXXQ=; b=eFBZDR/uYlyBGcIWgzkgwMwu9lmB01UmPbgwylYdoaFh22l8/EJYygiGrpUYLKPELj IA+P9LHURaBKHqJpQxXm5mvGojGGyT1Kgh8BQSUUt6XhrnmgrtL1G0Yrqit6w26hic/b pOkPACz3uQpkOjiCBByGQP2M+6QLG2c/fmhjRgcXaE7+cGbiMlq1hMBNn9N95oq9aJCn MGbY2JuGLoPQDmMRGSqA6B/qYjgl2/brc/IrbqVxpoK2/StgWy3GHNvPwvoeieIG8FK1 WE2OUtgORlPMC19fSzGwYdXFnUsPNRLnXhIDFChYHO6IV2As5/mrOO5FeFND/386aOCy fnRQ== X-Gm-Message-State: ACrzQf2/4UzUVzNgXtQY+R9V0fWeVADYsMYsxi7eLU7+EhGnoxQN+N1V AML6FIu6CDhXbCaU6HJZfHfwXnzuyZQ= X-Google-Smtp-Source: AMsMyM5lOqHZ953JQ4gamQfjjVoPWw1pwu6a00uZALKH+uJHaTZIzF12ljh8/oUYo9pDoMd2GrGreQ== X-Received: by 2002:a5d:64ab:0:b0:226:d997:ad5c with SMTP id m11-20020a5d64ab000000b00226d997ad5cmr8595293wrp.602.1665326268351; Sun, 09 Oct 2022 07:37:48 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id j6-20020a05600c190600b003a601a1c2f7sm14032808wmq.19.2022.10.09.07.37.47 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:47 -0700 (PDT) Message-Id: <7465fe7a8b4c0e3c3ac7cf99581914f83b13cb19.1665326258.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:35 +0000 Subject: [PATCH 09/12] fsmonitor: implement filesystem change listener for Linux Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Implement a filesystem change listener for Linux based on the inotify API: https://man7.org/linux/man-pages/man7/inotify.7.html inotify requires registering a watch on every directory in the worktree and special handling of moves/renames. Signed-off-by: Eric DeCosta --- compat/fsmonitor/fsm-listen-linux.c | 664 ++++++++++++++++++++++++++++ 1 file changed, 664 insertions(+) create mode 100644 compat/fsmonitor/fsm-listen-linux.c diff --git a/compat/fsmonitor/fsm-listen-linux.c b/compat/fsmonitor/fsm-listen-linux.c new file mode 100644 index 00000000000..244832fbec7 --- /dev/null +++ b/compat/fsmonitor/fsm-listen-linux.c @@ -0,0 +1,664 @@ +#include "cache.h" +#include "fsmonitor.h" +#include "fsm-listen.h" +#include "fsmonitor--daemon.h" +#include +#include +#include +#include + +/* + * Safe value to bitwise OR with rest of mask for + * kernels that do not support IN_MASK_CREATE + */ +#ifndef IN_MASK_CREATE +#define IN_MASK_CREATE 0x00000000 +#endif + +enum shutdown_reason { + SHUTDOWN_CONTINUE = 0, + SHUTDOWN_STOP, + SHUTDOWN_ERROR, + SHUTDOWN_FORCE +}; + +struct watch_entry { + struct hashmap_entry ent; + int wd; + uint32_t cookie; + const char *dir; +}; + +struct rename_entry { + struct hashmap_entry ent; + time_t whence; + uint32_t cookie; + const char *dir; +}; + +struct fsm_listen_data { + int fd_inotify; + enum shutdown_reason shutdown; + struct hashmap watches; + struct hashmap renames; + struct hashmap revwatches; +}; + +static int watch_entry_cmp(const void *cmp_data, + const struct hashmap_entry *eptr, + const struct hashmap_entry *entry_or_key, + const void *keydata) +{ + const struct watch_entry *e1, *e2; + + e1 = container_of(eptr, const struct watch_entry, ent); + e2 = container_of(eptr, const struct watch_entry, ent); + return e1->wd != e2->wd; +} + +static int revwatches_entry_cmp(const void *cmp_data, + const struct hashmap_entry *eptr, + const struct hashmap_entry *entry_or_key, + const void *keydata) +{ + const struct watch_entry *e1, *e2; + + e1 = container_of(eptr, const struct watch_entry, ent); + e2 = container_of(eptr, const struct watch_entry, ent); + return strcmp(e1->dir, e2->dir); +} + +static int rename_entry_cmp(const void *cmp_data, + const struct hashmap_entry *eptr, + const struct hashmap_entry *entry_or_key, + const void *keydata) +{ + const struct rename_entry *e1, *e2; + + e1 = container_of(eptr, const struct rename_entry, ent); + e2 = container_of(eptr, const struct rename_entry, ent); + return e1->cookie != e2->cookie; +} + +/* + * Register an inotify watch, add watch descriptor to path mapping + * and the reverse mapping. + */ +static int add_watch(const char *path, struct fsm_listen_data *data) +{ + const char *interned = strintern(path); + struct watch_entry *w1, *w2; + + /* add the inotify watch, don't allow watches to be modified */ + int wd = inotify_add_watch(data->fd_inotify, interned, + (IN_ALL_EVENTS | IN_ONLYDIR | IN_MASK_CREATE) + ^ IN_ACCESS ^ IN_CLOSE ^ IN_OPEN); + if (wd < 0) + return error_errno("inotify_add_watch('%s') failed", interned); + + /* add watch descriptor -> directory mapping */ + CALLOC_ARRAY(w1, 1); + w1->wd = wd; + w1->dir = interned; + hashmap_entry_init(&w1->ent, memhash(&w1->wd, sizeof(int))); + hashmap_add(&data->watches, &w1->ent); + + /* add directory -> watch descriptor mapping */ + CALLOC_ARRAY(w2, 1); + w2->wd = wd; + w2->dir = interned; + hashmap_entry_init(&w2->ent, memhash(w2->dir, strlen(w2->dir))); + hashmap_add(&data->revwatches, &w2->ent); + + return 0; +} + +/* + * Remove the inotify watch, the watch descriptor to path mapping + * and the reverse mapping. + */ +static void remove_watch(struct watch_entry *w, + struct fsm_listen_data *data) +{ + struct watch_entry k1, k2, *w1, *w2; + + /* remove watch, ignore error if kernel already did it */ + if (inotify_rm_watch(data->fd_inotify, w->wd) && errno != EINVAL) + error_errno("inotify_rm_watch() failed"); + + hashmap_entry_init(&k1.ent, memhash(&w->wd, sizeof(int))); + w1 = hashmap_remove_entry(&data->watches, &k1, ent, NULL); + if (!w1) + BUG("Double remove of watch for '%s'", w->dir); + + if (w1->cookie) + BUG("Removing watch for '%s' which has a pending rename", w1->dir); + + hashmap_entry_init(&k2.ent, memhash(w->dir, strlen(w->dir))); + w2 = hashmap_remove_entry(&data->revwatches, &k2, ent, NULL); + if (!w2) + BUG("Double remove of reverse watch for '%s'", w->dir); + + /* w1->dir and w2->dir are interned strings, we don't own them */ + free(w1); + free(w2); +} + +/* + * Check for stale directory renames. + * + * https://man7.org/linux/man-pages/man7/inotify.7.html + * + * Allow for some small timeout to account for the fact that insertion of the + * IN_MOVED_FROM+IN_MOVED_TO event pair is not atomic, and the possibility that + * there may not be any IN_MOVED_TO event. + * + * If the IN_MOVED_TO event is not received within the timeout then events have + * been missed and the monitor is in an inconsistent state with respect to the + * filesystem. + */ +static int check_stale_dir_renames(struct hashmap *renames, time_t max_age) +{ + struct rename_entry *re; + struct hashmap_iter iter; + + hashmap_for_each_entry(renames, &iter, re, ent) { + if (re->whence <= max_age) + return -1; + } + return 0; +} + +/* + * Track pending renames. + * + * Tracking is done via a event cookie to watch descriptor mapping. + * + * A rename is not complete until matching a IN_MOVED_TO event is received + * for a corresponding IN_MOVED_FROM event. + */ +static void add_dir_rename(uint32_t cookie, const char *path, + struct fsm_listen_data *data) +{ + struct watch_entry k, *w; + struct rename_entry *re; + + /* lookup the watch descriptor for the given path */ + hashmap_entry_init(&k.ent, memhash(path, strlen(path))); + w = hashmap_get_entry(&data->revwatches, &k, ent, NULL); + if (!w) /* should never happen */ + BUG("No watch for '%s'", path); + w->cookie = cookie; + + /* add the pending rename to match against later */ + CALLOC_ARRAY(re, 1); + re->dir = w->dir; + re->cookie = w->cookie; + re->whence = time(NULL); + hashmap_entry_init(&re->ent, memhash(&re->cookie, sizeof(uint32_t))); + hashmap_add(&data->renames, &re->ent); +} + +/* + * Handle directory renames + * + * Once a IN_MOVED_TO event is received, lookup the rename tracking information + * via the event cookie and use this information to update the watch. + */ +static void rename_dir(uint32_t cookie, const char *path, + struct fsm_listen_data *data) +{ + struct rename_entry rek, *re; + struct watch_entry k, *w; + + /* lookup a pending rename to match */ + rek.cookie = cookie; + hashmap_entry_init(&rek.ent, memhash(&rek.cookie, sizeof(uint32_t))); + re = hashmap_get_entry(&data->renames, &rek, ent, NULL); + if (re) { + k.dir = re->dir; + hashmap_entry_init(&k.ent, memhash(k.dir, strlen(k.dir))); + w = hashmap_get_entry(&data->revwatches, &k, ent, NULL); + if (w) { + w->cookie = 0; /* rename handled */ + remove_watch(w, data); + add_watch(path, data); + } else { + BUG("No matching watch"); + } + } else { + BUG("No matching cookie"); + } +} + +/* + * Recursively add watches to every directory under path + */ +static int register_inotify(const char *path, struct fsm_listen_data *data) +{ + DIR *dir; + struct strbuf current = STRBUF_INIT; + struct dirent *de; + struct stat fs; + int ret = -1; + + dir = opendir(path); + if (!dir) + return error_errno("opendir('%s') failed", path); + + while ((de = readdir_skip_dot_and_dotdot(dir)) != NULL) { + strbuf_reset(¤t); + strbuf_addf(¤t, "%s/%s", path, de->d_name); + if (lstat(current.buf, &fs)) { + error_errno("lstat('%s') failed", current.buf); + goto failed; + } + + /* recurse into directory */ + if (S_ISDIR(fs.st_mode)) { + if (add_watch(current.buf, data)) + goto failed; + if (register_inotify(current.buf, data)) + goto failed; + } + } + ret = 0; + +failed: + strbuf_release(¤t); + if (closedir(dir) < 0) + return error_errno("closedir('%s') failed", path); + return ret; +} + +static int em_rename_dir_from(u_int32_t mask) +{ + return ((mask & IN_ISDIR) && (mask & IN_MOVED_FROM)); +} + +static int em_rename_dir_to(u_int32_t mask) +{ + return ((mask & IN_ISDIR) && (mask & IN_MOVED_TO)); +} + +static int em_remove_watch(u_int32_t mask) +{ + return (mask & IN_DELETE_SELF); +} + +static int em_dir_renamed(u_int32_t mask) +{ + return ((mask & IN_ISDIR) && (mask & IN_MOVE)); +} + +static int em_dir_created(u_int32_t mask) +{ + return ((mask & IN_ISDIR) && (mask & IN_CREATE)); +} + +static int em_dir_deleted(uint32_t mask) +{ + return ((mask & IN_ISDIR) && (mask & IN_DELETE)); +} + +static int em_force_shutdown(u_int32_t mask) +{ + return (mask & IN_UNMOUNT) || (mask & IN_Q_OVERFLOW); +} + +static int em_ignore(u_int32_t mask) +{ + return (mask & IN_IGNORED) || (mask & IN_MOVE_SELF); +} + +static void log_mask_set(const char *path, u_int32_t mask) +{ + struct strbuf msg = STRBUF_INIT; + + if (mask & IN_ACCESS) + strbuf_addstr(&msg, "IN_ACCESS|"); + if (mask & IN_MODIFY) + strbuf_addstr(&msg, "IN_MODIFY|"); + if (mask & IN_ATTRIB) + strbuf_addstr(&msg, "IN_ATTRIB|"); + if (mask & IN_CLOSE_WRITE) + strbuf_addstr(&msg, "IN_CLOSE_WRITE|"); + if (mask & IN_CLOSE_NOWRITE) + strbuf_addstr(&msg, "IN_CLOSE_NOWRITE|"); + if (mask & IN_OPEN) + strbuf_addstr(&msg, "IN_OPEN|"); + if (mask & IN_MOVED_FROM) + strbuf_addstr(&msg, "IN_MOVED_FROM|"); + if (mask & IN_MOVED_TO) + strbuf_addstr(&msg, "IN_MOVED_TO|"); + if (mask & IN_CREATE) + strbuf_addstr(&msg, "IN_CREATE|"); + if (mask & IN_DELETE) + strbuf_addstr(&msg, "IN_DELETE|"); + if (mask & IN_DELETE_SELF) + strbuf_addstr(&msg, "IN_DELETE_SELF|"); + if (mask & IN_MOVE_SELF) + strbuf_addstr(&msg, "IN_MOVE_SELF|"); + if (mask & IN_UNMOUNT) + strbuf_addstr(&msg, "IN_UNMOUNT|"); + if (mask & IN_Q_OVERFLOW) + strbuf_addstr(&msg, "IN_Q_OVERFLOW|"); + if (mask & IN_IGNORED) + strbuf_addstr(&msg, "IN_IGNORED|"); + if (mask & IN_ISDIR) + strbuf_addstr(&msg, "IN_ISDIR|"); + + trace_printf_key(&trace_fsmonitor, "inotify_event: '%s', mask=%#8.8x %s", + path, mask, msg.buf); + + strbuf_release(&msg); +} + +int fsm_listen__ctor(struct fsmonitor_daemon_state *state) +{ + int fd; + int ret = 0; + struct fsm_listen_data *data; + + CALLOC_ARRAY(data, 1); + state->listen_data = data; + state->listen_error_code = -1; + data->shutdown = SHUTDOWN_ERROR; + + fd = inotify_init1(O_NONBLOCK); + if (fd < 0) + return error_errno("inotify_init1() failed"); + + data->fd_inotify = fd; + + hashmap_init(&data->watches, watch_entry_cmp, NULL, 0); + hashmap_init(&data->renames, rename_entry_cmp, NULL, 0); + hashmap_init(&data->revwatches, revwatches_entry_cmp, NULL, 0); + + if (add_watch(state->path_worktree_watch.buf, data)) + ret = -1; + else if (register_inotify(state->path_worktree_watch.buf, data)) + ret = -1; + else if (state->nr_paths_watching > 1) { + if (add_watch(state->path_gitdir_watch.buf, data)) + ret = -1; + else if (register_inotify(state->path_gitdir_watch.buf, data)) + ret = -1; + } + + if (!ret) { + state->listen_error_code = 0; + data->shutdown = SHUTDOWN_CONTINUE; + } + + return ret; +} + +void fsm_listen__dtor(struct fsmonitor_daemon_state *state) +{ + struct fsm_listen_data *data; + struct hashmap_iter iter; + struct watch_entry *w; + int fd; + + if (!state || !state->listen_data) + return; + + data = state->listen_data; + fd = data->fd_inotify; + + hashmap_for_each_entry(&data->watches, &iter, w, ent) { + w->cookie = 0; /* ignore any pending renames */ + remove_watch(w, data); + } + hashmap_clear(&data->watches); + + hashmap_clear(&data->revwatches); /* remove_watch freed the entries */ + + hashmap_clear_and_free(&data->renames, struct rename_entry, ent); + + FREE_AND_NULL(state->listen_data); + + if (fd && (close(fd) < 0)) + error_errno(_("closing inotify file descriptor failed")); +} + +void fsm_listen__stop_async(struct fsmonitor_daemon_state *state) +{ + if (!state->listen_data->shutdown) + state->listen_data->shutdown = SHUTDOWN_STOP; +} + +/* + * Process a single inotify event and queue for publication. + */ +static int process_event(const char *path, + const struct inotify_event *event, + struct fsmonitor_batch *batch, + struct string_list *cookie_list, + struct fsmonitor_daemon_state *state) +{ + const char *rel; + const char *last_sep; + + switch (fsmonitor_classify_path_absolute(state, path)) { + case IS_INSIDE_DOT_GIT_WITH_COOKIE_PREFIX: + case IS_INSIDE_GITDIR_WITH_COOKIE_PREFIX: + /* Use just the filename of the cookie file. */ + last_sep = find_last_dir_sep(path); + string_list_append(cookie_list, + last_sep ? last_sep + 1 : path); + break; + case IS_INSIDE_DOT_GIT: + case IS_INSIDE_GITDIR: + break; + case IS_DOT_GIT: + case IS_GITDIR: + /* + * If .git directory is deleted or renamed away, + * we have to quit. + */ + if (em_dir_deleted(event->mask)) { + trace_printf_key(&trace_fsmonitor, + "event: gitdir removed"); + state->listen_data->shutdown = SHUTDOWN_FORCE; + goto done; + } + + if (em_dir_renamed(event->mask)) { + trace_printf_key(&trace_fsmonitor, + "event: gitdir renamed"); + state->listen_data->shutdown = SHUTDOWN_FORCE; + goto done; + } + break; + case IS_WORKDIR_PATH: + /* normal events in the working directory */ + if (trace_pass_fl(&trace_fsmonitor)) + log_mask_set(path, event->mask); + + rel = path + state->path_worktree_watch.len + 1; + fsmonitor_batch__add_path(batch, rel); + + if (em_dir_deleted(event->mask)) + break; + + /* received IN_MOVE_FROM, add tracking for expected IN_MOVE_TO */ + if (em_rename_dir_from(event->mask)) + add_dir_rename(event->cookie, path, state->listen_data); + + /* received IN_MOVE_TO, update watch to reflect new path */ + if (em_rename_dir_to(event->mask)) + rename_dir(event->cookie, path, state->listen_data); + + if (em_dir_created(event->mask)) { + if (add_watch(path, state->listen_data)) { + state->listen_data->shutdown = SHUTDOWN_ERROR; + goto done; + } + if (register_inotify(path, state->listen_data)) { + state->listen_data->shutdown = SHUTDOWN_ERROR; + goto done; + } + } + break; + case IS_OUTSIDE_CONE: + default: + trace_printf_key(&trace_fsmonitor, + "ignoring '%s'", path); + break; + } + return 0; +done: + return -1; +} + +/* + * Read the inotify event stream and pre-process events before further + * processing and eventual publishing. + */ +static void handle_events(struct fsmonitor_daemon_state *state) +{ + /* See https://man7.org/linux/man-pages/man7/inotify.7.html */ + char buf[4096] + __attribute__ ((aligned(__alignof__(struct inotify_event)))); + + struct hashmap watches = state->listen_data->watches; + struct fsmonitor_batch *batch = NULL; + struct string_list cookie_list = STRING_LIST_INIT_DUP; + struct watch_entry k, *w; + struct strbuf path; + const struct inotify_event *event; + int fd = state->listen_data->fd_inotify; + ssize_t len; + char *ptr, *p; + + strbuf_init(&path, PATH_MAX); + + for(;;) { + len = read(fd, buf, sizeof(buf)); + if (len == -1 && errno != EAGAIN) { + error_errno(_("reading inotify message stream failed")); + state->listen_data->shutdown = SHUTDOWN_ERROR; + goto done; + } + + /* nothing to read */ + if (len <= 0) + goto done; + + /* Loop over all events in the buffer. */ + for (ptr = buf; ptr < buf + len; + ptr += sizeof(struct inotify_event) + event->len) { + + event = (const struct inotify_event *) ptr; + + if (em_ignore(event->mask)) + continue; + + /* File system was unmounted or event queue overflowed */ + if (em_force_shutdown(event->mask)) { + if (trace_pass_fl(&trace_fsmonitor)) + log_mask_set("Forcing shutdown", event->mask); + state->listen_data->shutdown = SHUTDOWN_FORCE; + goto done; + } + + hashmap_entry_init(&k.ent, memhash(&event->wd, sizeof(int))); + k.wd = event->wd; + + w = hashmap_get_entry(&watches, &k, ent, NULL); + if (!w) /* should never happen */ + BUG("No watch for '%s'", event->name); + + /* directory watch was removed */ + if (em_remove_watch(event->mask)) { + remove_watch(w, state->listen_data); + continue; + } + + strbuf_reset(&path); + strbuf_add(&path, w->dir, strlen(w->dir)); + strbuf_addch(&path, '/'); + strbuf_add(&path, event->name, strlen(event->name)); + + p = fsmonitor__resolve_alias(path.buf, &state->alias); + if (!p) + p = strbuf_detach(&path, NULL); + + if (!batch) + batch = fsmonitor_batch__new(); + + if (process_event(p, event, batch, &cookie_list, state)) { + free(p); + goto done; + } + free(p); + } + strbuf_reset(&path); + fsmonitor_publish(state, batch, &cookie_list); + string_list_clear(&cookie_list, 0); + batch = NULL; + } +done: + strbuf_release(&path); + fsmonitor_batch__free_list(batch); + string_list_clear(&cookie_list, 0); +} + +/* + * Non-blocking read of the inotify events stream. The inotify fd is polled + * every few millisec to help minimize the number of queue overflows. + */ +void fsm_listen__loop(struct fsmonitor_daemon_state *state) +{ + int poll_num; + const int interval = 1000; + time_t checked = time(NULL); + struct pollfd fds[1]; + fds[0].fd = state->listen_data->fd_inotify; + fds[0].events = POLLIN; + + for(;;) { + switch (state->listen_data->shutdown) { + case SHUTDOWN_CONTINUE: + poll_num = poll(fds, 1, 10); + if (poll_num == -1) { + if (errno == EINTR) + continue; + error_errno(_("polling inotify message stream failed")); + state->listen_data->shutdown = SHUTDOWN_ERROR; + continue; + } + + if ((time(NULL) - checked) >= interval) { + checked = time(NULL); + if (check_stale_dir_renames(&state->listen_data->renames, + checked - interval)) { + trace_printf_key(&trace_fsmonitor, + "Missed IN_MOVED_TO events, forcing shutdown"); + state->listen_data->shutdown = SHUTDOWN_FORCE; + continue; + } + } + + if (poll_num > 0 && (fds[0].revents & POLLIN)) + handle_events(state); + + continue; + case SHUTDOWN_ERROR: + state->listen_error_code = -1; + ipc_server_stop_async(state->ipc_server_data); + break; + case SHUTDOWN_FORCE: + state->listen_error_code = 0; + ipc_server_stop_async(state->ipc_server_data); + break; + case SHUTDOWN_STOP: + default: + state->listen_error_code = 0; + break; + } + return; + } +} From patchwork Sun Oct 9 14:37:36 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002031 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5512FC433F5 for ; Sun, 9 Oct 2022 14:38:11 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230226AbiJIOiK (ORCPT ); Sun, 9 Oct 2022 10:38:10 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230203AbiJIOhv (ORCPT ); Sun, 9 Oct 2022 10:37:51 -0400 Received: from mail-wr1-x434.google.com (mail-wr1-x434.google.com [IPv6:2a00:1450:4864:20::434]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E921E2716B for ; Sun, 9 Oct 2022 07:37:50 -0700 (PDT) Received: by mail-wr1-x434.google.com with SMTP id r13so13626995wrj.11 for ; Sun, 09 Oct 2022 07:37:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=bGYyUaPSgkCtAEhuDD2/mhECBE8b1dUOf87VuRjyQ4s=; b=HpQoD9d4ooJauiA9Y+N//RDhRRKucp6MmBj8oFyUOZnc9tT8rYhxZaJzQD3p+awH5i gPCg6sP4oA2YZISrmwqbClthxB+JP8TkBWbO0IgtDg8mDCl77Tg2MrbhMtHC/yq+AYFp QQngDAlGc1XXDrr3yy4wg7lR+m1hco+aNygU5AqpYvo9bKz+MqRRJoZYAeK7675T4hZt hMuVwRxdJEb6QWrFYQC42XcW+8qiV80mHN8vP7bKOdy8RJSoeCjKlLOk8EinxX/owlhE IUR2lwerMXoVrjWvC9li4VaNbCfBd6cDkZFbZ3stfszNGRb5YEuSUaEhqn6CxhB6UW9v O5NA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=bGYyUaPSgkCtAEhuDD2/mhECBE8b1dUOf87VuRjyQ4s=; b=QaGRyfuXPY04KPf7F6ddIqonQAEe6TE3Ckc93HrJl0LwD5UwIlra5ct4KKFgS3vp4L fDucF9AijRxd0rsPa7VWC7TSUQcaR/2GBE7Gi84QLMdnnbL2pZmh/GuLEFaDsSXTQ8Tp iiy0HAzR3FnRu56M6pE+rDcAgNZZkT38Yulp8b3LQIuo25xiv84Cl7Bfh+0VjJzg/fyr KdOY30BAk30DL/nHQeRYmCr1K1FIWdgqsIEn9QQlaKtpEs7Oub+QSSiRCzsSx6uqmZeG qz6nnBuKnKSNEfCA31CUnAK2njUu//DqNopr3zOFLL/Ep1B1O6k/kxrwjy2SrLAt/sZo vRhw== X-Gm-Message-State: ACrzQf3k2nQ7C3YK+Tcznvn/I1ovj25Y8jF764UR/SApBsO2OR7RonDY i5bk/fvdHD2OvXL3LyuOuBpzWYImCwI= X-Google-Smtp-Source: AMsMyM7SAgxEs3bblmVIBO8THAyD2HjxPeo3yjHeVeiEuqyDFf3IASsegGJEcx0eYqAAkfXCKKH8Jg== X-Received: by 2002:a5d:4050:0:b0:22c:dfcc:675b with SMTP id w16-20020a5d4050000000b0022cdfcc675bmr8502476wrp.105.1665326269281; Sun, 09 Oct 2022 07:37:49 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id bt7-20020a056000080700b0022e62529888sm6873080wrb.67.2022.10.09.07.37.48 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:48 -0700 (PDT) Message-Id: <3a2db9aa07697fd4b66b533d1afee4f49cef0248.1665326258.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:36 +0000 Subject: [PATCH 10/12] fsmonitor: enable fsmonitor for Linux Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Uodate build to enable fsmonitor for Linux. Signed-off-by: Eric DeCosta --- config.mak.uname | 9 +++++++++ contrib/buildsystems/CMakeLists.txt | 11 ++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/config.mak.uname b/config.mak.uname index d454cec47c4..04988266835 100644 --- a/config.mak.uname +++ b/config.mak.uname @@ -69,6 +69,15 @@ ifeq ($(uname_S),Linux) BASIC_CFLAGS += -std=c99 endif + # The builtin FSMonitor on Linux builds upon Simple-IPC. Both require + # Unix domain sockets and PThreads. + ifndef NO_PTHREADS + ifndef NO_UNIX_SOCKETS + FSMONITOR_DAEMON_BACKEND = linux + FSMONITOR_OS_SETTINGS = linux + FSMONITOR_DAEMON_COMMON = unix + endif + endif endif ifeq ($(uname_S),GNU/kFreeBSD) HAVE_ALLOCA_H = YesPlease diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 0b26a1a36e3..afabfcdefdd 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -304,7 +304,16 @@ else() endif() if(SUPPORTS_SIMPLE_IPC) - if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-ipc-unix.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-unix.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-linux.c) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-path-utils-linux.c) + + add_compile_definitions(HAVE_FSMONITOR_OS_SETTINGS) + list(APPEND compat_SOURCES compat/fsmonitor/fsm-settings-unix.c) + elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") add_compile_definitions(HAVE_FSMONITOR_DAEMON_BACKEND) list(APPEND compat_SOURCES compat/fsmonitor/fsm-listen-win32.c) list(APPEND compat_SOURCES compat/fsmonitor/fsm-health-win32.c) From patchwork Sun Oct 9 14:37:37 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002032 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4083FC433FE for ; Sun, 9 Oct 2022 14:38:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230241AbiJIOih (ORCPT ); Sun, 9 Oct 2022 10:38:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:46976 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230138AbiJIOhy (ORCPT ); Sun, 9 Oct 2022 10:37:54 -0400 Received: from mail-wm1-x32a.google.com (mail-wm1-x32a.google.com [IPv6:2a00:1450:4864:20::32a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 28EDB27B1F for ; Sun, 9 Oct 2022 07:37:52 -0700 (PDT) Received: by mail-wm1-x32a.google.com with SMTP id iv17so5477795wmb.4 for ; Sun, 09 Oct 2022 07:37:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=qxgJjmbh+xLfyZbtDof9epBzQHRl8IpFyALiN1Oh+EM=; b=p5r0PGnol+5P6RY6gnjTsBBXcUCpektnqA+tYuNOxqQauBvTW2In6NSExuTnpJ18xr Y0/DY42EIUDomlD7hQjufHVyfoRFUv3tJFSb7csxtbLAVuepMoerU38UF9zOJ4CkcBf4 XIA7LDxoRq2VysT7q4DximIn/17kE+7h+ckPKT2Uagd46+XRVC91SilT60UFowozQA8H AqfJ5lSPFnkh24M+378u3apGkWO0DFdAilRZrcoN3Ojvj+wtGMoGbtW7NdpEgfhKzBp0 WxjYW/94iZw6MXl2Q2uNESDGM4NtcqqWw3AGqQCLGEq82xw8NfLaruA86N2TUA4PDMUo o1zA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qxgJjmbh+xLfyZbtDof9epBzQHRl8IpFyALiN1Oh+EM=; b=x8Ff9XVjc/PZ6wpP7npUknRUZuyp1TD5HdD+S0BX+Tfz4gag+FbvI+r74wbUj8hhv9 y7ak92qyw/Am0KoaXbh+Uo00WTU/7k90W6NjmRfKBHVNq1lx7jDIz7d7mbdk7wFyF3Fl F5uEGiDGKK4zrnACHUbh+qh18Pg3vpf7g5if3mF/qV/DIpvf9VJQ6FoEDa+ANuozDKH7 xz84N6an5k1AubupgQr9AURcM5/SM5qD4HF2GtVteH1I4TkAxuq4NADLWK/aGik1feRz Rs43/v6hxu4lYTsVDUHKhQhdIF4Z1+ZHZ19XY9vEK79ewbKG28KWVWmuWe9L2+AvSDRH ck+Q== X-Gm-Message-State: ACrzQf3L4Dqd3WBjkY9hyHnSvH3H2xKAtd89KE4S9t6XNBFM+WIwuaZD qcVHstJOh5Kv2lp7xKFUtFG7E2mbXOg= X-Google-Smtp-Source: AMsMyM62vF/OgZCM7Rq9kK1CJx2Y0J2ateLp/4XmaVtXWLbji9uhA9ZyOR23BV9jHZi1jyZ36wfqdw== X-Received: by 2002:a05:600c:218d:b0:3b4:7749:c920 with SMTP id e13-20020a05600c218d00b003b47749c920mr17275009wme.190.1665326270252; Sun, 09 Oct 2022 07:37:50 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id i18-20020a5d5592000000b0021e51c039c5sm6807599wrv.80.2022.10.09.07.37.49 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:49 -0700 (PDT) Message-Id: <743bdacded5183b5b11c9f19c24b07fa26eded24.1665326258.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:37 +0000 Subject: [PATCH 11/12] fsmonitor: test updates Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta t7527-builtin-fsmonitor was leaking fsmonitor--daemon processes in some cases. Accomodate slight difference in the number of events generated on Linux. On lower-powered systems, spin a little to give the daemon time to respond to and log filesystem events. Signed-off-by: Eric DeCosta --- t/t7527-builtin-fsmonitor.sh | 58 +++++++++++++++++++++++++++--------- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/t/t7527-builtin-fsmonitor.sh b/t/t7527-builtin-fsmonitor.sh index 56c0dfffea6..19a243588e2 100755 --- a/t/t7527-builtin-fsmonitor.sh +++ b/t/t7527-builtin-fsmonitor.sh @@ -13,7 +13,7 @@ fi stop_daemon_delete_repo () { r=$1 && test_might_fail git -C $r fsmonitor--daemon stop && - rm -rf $1 + rm -rf $r } start_daemon () { @@ -72,6 +72,32 @@ start_daemon () { ) } +IMPLICIT_TIMEOUT=5 + +wait_for_update () { + func=$1 && + file=$2 && + sz=$(wc -c < "$file") && + last=0 && + $func && + k=0 && + while test "$k" -lt $IMPLICIT_TIMEOUT + do + nsz=$(wc -c < "$file") + if test "$nsz" -gt "$sz" + then + if test "$last" -eq "$nsz" + then + return 0 + fi + last=$nsz + fi + sleep 1 + k=$(( $k + 1 )) + done && + return 0 +} + # Is a Trace2 data event present with the given catetory and key? # We do not care what the value is. # @@ -137,7 +163,6 @@ test_expect_success 'implicit daemon start' ' # machines (where it might take a moment to wake and reschedule the # daemon process) to avoid false alarms during test runs.) # -IMPLICIT_TIMEOUT=5 verify_implicit_shutdown () { r=$1 && @@ -373,6 +398,10 @@ create_files () { echo 3 >dir2/new } +rename_directory () { + mv dirtorename dirrenamed +} + rename_files () { mv rename renamed && mv dir1/rename dir1/renamed && @@ -427,7 +456,7 @@ test_expect_success 'edit some files' ' start_daemon --tf "$PWD/.git/trace" && - edit_files && + wait_for_update edit_files "$PWD/.git/trace" && test-tool fsmonitor-client query --token 0 && @@ -442,7 +471,7 @@ test_expect_success 'create some files' ' start_daemon --tf "$PWD/.git/trace" && - create_files && + wait_for_update create_files "$PWD/.git/trace" && test-tool fsmonitor-client query --token 0 && @@ -456,7 +485,7 @@ test_expect_success 'delete some files' ' start_daemon --tf "$PWD/.git/trace" && - delete_files && + wait_for_update delete_files "$PWD/.git/trace" && test-tool fsmonitor-client query --token 0 && @@ -470,7 +499,7 @@ test_expect_success 'rename some files' ' start_daemon --tf "$PWD/.git/trace" && - rename_files && + wait_for_update rename_files "$PWD/.git/trace" && test-tool fsmonitor-client query --token 0 && @@ -487,7 +516,7 @@ test_expect_success 'rename directory' ' start_daemon --tf "$PWD/.git/trace" && - mv dirtorename dirrenamed && + wait_for_update rename_directory "$PWD/.git/trace" && test-tool fsmonitor-client query --token 0 && @@ -500,7 +529,7 @@ test_expect_success 'file changes to directory' ' start_daemon --tf "$PWD/.git/trace" && - file_to_directory && + wait_for_update file_to_directory "$PWD/.git/trace" && test-tool fsmonitor-client query --token 0 && @@ -513,7 +542,7 @@ test_expect_success 'directory changes to a file' ' start_daemon --tf "$PWD/.git/trace" && - directory_to_file && + wait_for_update directory_to_file "$PWD/.git/trace" && test-tool fsmonitor-client query --token 0 && @@ -561,7 +590,7 @@ test_expect_success 'flush cached data' ' test-tool -C test_flush fsmonitor-client query --token "builtin:test_00000002:0" >actual_2 && nul_to_q actual_q2 && - grep "^builtin:test_00000002:0Q$" actual_q2 && + grep "^builtin:test_00000002:[0-1]Q$" actual_q2 && >test_flush/file_3 && @@ -732,7 +761,8 @@ u_values="$u1 $u2" for u in $u_values do test_expect_success "unicode in repo root path: $u" ' - test_when_finished "stop_daemon_delete_repo $u" && + test_when_finished \ + "stop_daemon_delete_repo `echo "$u" | sed 's:x:\\\\\\\\\\\\\\x:g'`" && git init "$u" && echo 1 >"$u"/file1 && @@ -814,8 +844,7 @@ my_match_and_clean () { } test_expect_success 'submodule always visited' ' - test_when_finished "git -C super fsmonitor--daemon stop; \ - rm -rf super; \ + test_when_finished "rm -rf super; \ rm -rf sub" && create_super super && @@ -883,7 +912,8 @@ have_t2_error_event () { } test_expect_success "stray submodule super-prefix warning" ' - test_when_finished "rm -rf super; \ + test_when_finished "git -C super/dir_1/dir_2/sub fsmonitor--daemon stop; \ + rm -rf super; \ rm -rf sub; \ rm super-sub.trace" && From patchwork Sun Oct 9 14:37:38 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eric DeCosta X-Patchwork-Id: 13002033 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id DFA45C433F5 for ; Sun, 9 Oct 2022 14:38:41 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230253AbiJIOij (ORCPT ); Sun, 9 Oct 2022 10:38:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:47004 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230146AbiJIOh4 (ORCPT ); Sun, 9 Oct 2022 10:37:56 -0400 Received: from mail-wr1-x42a.google.com (mail-wr1-x42a.google.com [IPv6:2a00:1450:4864:20::42a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D6DA027CCD for ; Sun, 9 Oct 2022 07:37:51 -0700 (PDT) Received: by mail-wr1-x42a.google.com with SMTP id bk15so13614880wrb.13 for ; Sun, 09 Oct 2022 07:37:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:from:to:cc:subject:date :message-id:reply-to; bh=Oi1JhA2Y49B3vsv8LyQZ/nUzDuStw5WBLGMA8BZqLVA=; b=P0ZcnYOjTLOBkaF1l7Hg5kp1y2NFOp0EZum0L/c9Q7y6Ps06jMhUALqywCICDexy9r dv+782m3MK79/fhIWHBl3+5Pk9itBgyQEqNSDJYGYY7x2qywx9gRdIFATtJAJVOJ1cuk xw+SIRAE61lH1jTdAdacL0FMpndqCew4P77Rsy8uD+r8Mc3+tCxL/ZVKkV5LTFb17FeV ldxtOzZFPSiYKHAdh6Efk44lFj0ilOcvUsWncXzakJqj/tDt/BnvioB3fgGwGfl+WH8j 2jhwfvWcBRqCRFZRzErlmetM7mufCBTbdMWV1zOBfXT2lZ/CjM5p4ZLFASu7kJZXnvvf HXIw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=cc:to:mime-version:content-transfer-encoding:fcc:subject:date:from :references:in-reply-to:message-id:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Oi1JhA2Y49B3vsv8LyQZ/nUzDuStw5WBLGMA8BZqLVA=; b=g7Cdd/dgYX7Y/vW04sdP2ihvt8gJG89tdU/+0m2yBlHhUlqwkXQ1FapsfipLSC9lYT tm47UGFXGGAMYlblyujKYVF32HTk8MlIQ82BKWMS61/C5ueAZtc3jSg5x+wFkSsMCJ4w bOmZUMA80/5JjgjpCdLkmjdSuVIyEBk9bR3fK3N/0Hgk4uHucKL2UBfmQszTIlpRbgVI 8XI2pd67yuRzcAXlOidSM+/J3ee//rf8M4R0w5jA+UkDdYcSoLOzxc5dGkfJqKj/23sn GKz9nDqqV5umNBpTKMFGnio8JGXe9Ms3lKkg8H7UZ+Fu68kGC8/rmKeqFSe8oiydYuqG jd0Q== X-Gm-Message-State: ACrzQf30L7rPBNEZn9YqRaQg2y3tiePGki7U26bLKiOCIQN3mMLJWoY8 HGTaFvCon5EvVBCGT5/hcldqmyxHtDc= X-Google-Smtp-Source: AMsMyM4CaIqsgpPouXzqJgVCRoJiabd/mXx1p3fP191CYhT4qlICh0eZFy1HTprga2dDuH5aJEPx+Q== X-Received: by 2002:a5d:490f:0:b0:22e:4bae:c06d with SMTP id x15-20020a5d490f000000b0022e4baec06dmr8716990wrq.549.1665326271175; Sun, 09 Oct 2022 07:37:51 -0700 (PDT) Received: from [127.0.0.1] ([13.74.141.28]) by smtp.gmail.com with ESMTPSA id k16-20020adfe8d0000000b0022cd0c8c696sm6536344wrn.103.2022.10.09.07.37.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 09 Oct 2022 07:37:50 -0700 (PDT) Message-Id: <77ed35b3b80de9ecfea179357115428ab89d9864.1665326258.git.gitgitgadget@gmail.com> In-Reply-To: References: Date: Sun, 09 Oct 2022 14:37:38 +0000 Subject: [PATCH 12/12] fsmonitor: update doc for Linux Fcc: Sent MIME-Version: 1.0 To: git@vger.kernel.org Cc: Eric DeCosta , Eric DeCosta Precedence: bulk List-ID: X-Mailing-List: git@vger.kernel.org From: Eric DeCosta From: Eric DeCosta Update the documentation for Linux. Signed-off-by: Eric DeCosta --- Documentation/config/fsmonitor--daemon.txt | 4 ++-- Documentation/git-fsmonitor--daemon.txt | 24 ++++++++++++++-------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/Documentation/config/fsmonitor--daemon.txt b/Documentation/config/fsmonitor--daemon.txt index c225c6c9e74..2cafb040d96 100644 --- a/Documentation/config/fsmonitor--daemon.txt +++ b/Documentation/config/fsmonitor--daemon.txt @@ -4,8 +4,8 @@ fsmonitor.allowRemote:: behavior. Only respected when `core.fsmonitor` is set to `true`. fsmonitor.socketDir:: - This Mac OS-specific option, if set, specifies the directory in + Mac OS and Linux-specific option. If set, specifies the directory in which to create the Unix domain socket used for communication between the fsmonitor daemon and various Git commands. The directory must - reside on a native Mac OS filesystem. Only respected when `core.fsmonitor` + reside on a native filesystem. Only respected when `core.fsmonitor` is set to `true`. diff --git a/Documentation/git-fsmonitor--daemon.txt b/Documentation/git-fsmonitor--daemon.txt index 8238eadb0e1..c2b08229c74 100644 --- a/Documentation/git-fsmonitor--daemon.txt +++ b/Documentation/git-fsmonitor--daemon.txt @@ -76,23 +76,31 @@ repositories; this may be overridden by setting `fsmonitor.allowRemote` to correctly with all network-mounted repositories and such use is considered experimental. -On Mac OS, the inter-process communication (IPC) between various Git +On Linux and Mac OS, the inter-process communication (IPC) between various Git commands and the fsmonitor daemon is done via a Unix domain socket (UDS) -- a -special type of file -- which is supported by native Mac OS filesystems, -but not on network-mounted filesystems, NTFS, or FAT32. Other filesystems -may or may not have the needed support; the fsmonitor daemon is not guaranteed -to work with these filesystems and such use is considered experimental. +special type of file -- which is supported by many native Linux and Mac OS +filesystems, but not on network-mounted filesystems, NTFS, or FAT32. Other +filesystems may or may not have the needed support; the fsmonitor daemon is not +guaranteed to work with these filesystems and such use is considered +experimental. By default, the socket is created in the `.git` directory, however, if the `.git` directory is on a network-mounted filesystem, it will be instead be created at `$HOME/.git-fsmonitor-*` unless `$HOME` itself is on a network-mounted filesystem in which case you must set the configuration -variable `fsmonitor.socketDir` to the path of a directory on a Mac OS native +variable `fsmonitor.socketDir` to the path of a directory on a native filesystem in which to create the socket file. If none of the above directories (`.git`, `$HOME`, or `fsmonitor.socketDir`) -is on a native Mac OS file filesystem the fsmonitor daemon will report an -error that will cause the daemon and the currently running command to exit. +is on a native Linux or Mac OS filesystem the fsmonitor daemon will report +an error that will cause the daemon to exit and the currently running command +to issue a warning. + +On Linux, the fsmonitor daemon registers a watch for each directory in the +repository. The default per-user limit for the number of watches on most Linux +systems is 8192. This may not be sufficient for large repositories or if +multiple instances of the fsmonitor daemon are running. +See https://watchexec.github.io/docs/inotify-limits.html[Linux inotify limits] for more information. CONFIGURATION -------------