diff --git a/Documentation/config/core.adoc b/Documentation/config/core.adoc index 340329edc3..33104444ab 100644 --- a/Documentation/config/core.adoc +++ b/Documentation/config/core.adoc @@ -118,6 +118,12 @@ core.trustctime:: crawlers and some backup systems). See linkgit:git-update-index[1]. True by default. +core.useNanosec:: + If true, use nanosecond precision for ctime and mtime + comparisions between the index and the working tree (if Git + was compiled to store it). + See link:technical/racy-git.html[Racy Git]. False by default. + core.splitIndex:: If true, the split-index feature of the index will be used. See linkgit:git-update-index[1]. False by default. diff --git a/Documentation/technical/racy-git.adoc b/Documentation/technical/racy-git.adoc index 59bea66c0f..499231585b 100644 --- a/Documentation/technical/racy-git.adoc +++ b/Documentation/technical/racy-git.adoc @@ -39,8 +39,8 @@ files) from `st_mode` member, `st_mtime` and `st_ctime` timestamps, `st_uid`, `st_gid`, `st_ino`, and `st_size` members. With a `USE_STDEV` compile-time option, `st_dev` is also compared, but this is not enabled by default because this member -is not stable on network filesystems. With `USE_NSEC` -compile-time option, `st_mtim.tv_nsec` and `st_ctim.tv_nsec` +is not stable on network filesystems. With 'core.useNanosec' +config setting, `st_mtim.tv_nsec` and `st_ctim.tv_nsec` members are also compared. On Linux, this is not enabled by default because in-core timestamps can have finer granularity than on-disk timestamps, resulting in meaningless changes when an @@ -49,9 +49,10 @@ of git://git.kernel.org/pub/scm/linux/kernel/git/tglx/history.git ([PATCH] Sync in core time granularity with filesystems, 2005-01-04). This patch is included in kernel 2.6.11 and newer, but only fixes the issue for file systems with exactly 1 ns or 1 s -resolution. Other file systems are still broken in current Linux -kernels (e.g. CEPH, CIFS, NTFS, UDF), see -https://lore.kernel.org/lkml/5577240D.7020309@gmail.com/ +resolution. As of kernel 4.3, other file systems (CEPH, CIFS, NTFS, UFS, FUSE) +were fixed; see https://public-inbox.org/git/5605D88A.20104%40gmail.com/. FAT +has been fixed since 2015. The usual suspects (ext2, ext4, XFS) are known to +work, too. Racy Git -------- diff --git a/Makefile b/Makefile index fac3e8879c..b4ebcb9e83 100644 --- a/Makefile +++ b/Makefile @@ -197,18 +197,11 @@ include shared.mak # Define NO_NORETURN if using buggy versions of gcc 4.6+ and profile feedback, # as the compiler can crash (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=49299) # -# Define USE_NSEC below if you want git to care about sub-second file mtimes -# and ctimes. Note that you need recent glibc (at least 2.2.4) for this. On -# Linux, kernel 2.6.11 or newer is required for reliable sub-second file times -# on file systems with exactly 1 ns or 1 s resolution. If you intend to use Git -# on other file systems (e.g. CEPH, CIFS, NTFS, UDF), don't enable USE_NSEC. See -# Documentation/technical/racy-git.adoc for details. -# # Define USE_ST_TIMESPEC if your "struct stat" uses "st_ctimespec" instead of # "st_ctim" # # Define NO_NSEC if your "struct stat" does not have "st_ctim.tv_nsec" -# available. This automatically turns USE_NSEC off. +# available. # # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-index perspective. @@ -1935,9 +1928,6 @@ endif ifdef NO_ST_BLOCKS_IN_STRUCT_STAT BASIC_CFLAGS += -DNO_ST_BLOCKS_IN_STRUCT_STAT endif -ifdef USE_NSEC - BASIC_CFLAGS += -DUSE_NSEC -endif ifdef USE_ST_TIMESPEC BASIC_CFLAGS += -DUSE_ST_TIMESPEC endif diff --git a/builtin/update-index.c b/builtin/update-index.c index 241abd4332..8e0c25655f 100644 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@ -130,7 +130,7 @@ static void xrmdir(const char *path) static void avoid_racy(void) { /* - * not use if we could usleep(10) if USE_NSEC is defined. The + * not use if we could usleep(10) if core.useNanosec is defined. The * field nsec could be there, but the OS could choose to * ignore it? */ diff --git a/compat/posix.h b/compat/posix.h index e2e794cad7..51ee03233b 100644 --- a/compat/posix.h +++ b/compat/posix.h @@ -487,7 +487,6 @@ int git_qsort_s(void *base, size_t nmemb, size_t size, } while (0) #ifdef NO_NSEC -#undef USE_NSEC #define ST_CTIME_NSEC(st) 0 #define ST_MTIME_NSEC(st) 0 #else diff --git a/configure.ac b/configure.ac index cfb50112bf..fc956776ab 100644 --- a/configure.ac +++ b/configure.ac @@ -351,12 +351,6 @@ GIT_PARSE_WITH(iconv)) ## --enable-FEATURE[=ARG] and --disable-FEATURE # -# Define USE_NSEC below if you want git to care about sub-second file mtimes -# and ctimes. Note that you need recent glibc (at least 2.2.4) for this, and -# it will BREAK YOUR LOCAL DIFFS! show-diff and anything using it will likely -# randomly break unless your underlying filesystem supports those sub-second -# times (my ext3 doesn't). -# # Define USE_STDEV below if you want git to care about the underlying device # change being considered an inode change from the update-index perspective. diff --git a/environment.c b/environment.c index 6676e6f5ae..e6a50060e8 100644 --- a/environment.c +++ b/environment.c @@ -571,6 +571,11 @@ int git_default_core_config(const char *var, const char *value, return 0; } + if (!strcmp(var, "core.usenanosec")) { + cfg->use_nanosec = git_config_bool(var, value); + return 0; + } + /* Add other config variables here and to Documentation/config.adoc. */ return platform_core_config(var, value, ctx, cb); } @@ -769,6 +774,7 @@ void repo_config_values_init(struct repo_config_values *cfg) cfg->ignore_case = 0; cfg->trust_executable_bit = 1; cfg->has_symlinks = platform_has_symlinks(); + cfg->use_nanosec = 0; /* section "sparse" config values */ cfg->sparse_expect_files_outside_of_patterns = 0; diff --git a/environment.h b/environment.h index e7ec5b0437..a35534afe5 100644 --- a/environment.h +++ b/environment.h @@ -139,6 +139,7 @@ struct repo_config_values { int ignore_case; int trust_executable_bit; int has_symlinks; + int use_nanosec; /* section "sparse" config values */ int sparse_expect_files_outside_of_patterns; diff --git a/read-cache.c b/read-cache.c index 6c449f393d..297646c357 100644 --- a/read-cache.c +++ b/read-cache.c @@ -353,15 +353,16 @@ static int ce_match_stat_basic(const struct cache_entry *ce, struct stat *st) static int is_racy_stat(const struct index_state *istate, const struct stat_data *sd) { + int use_nsec = 0; + repo_config_get_bool(the_repository, "core.useNanosec", &use_nsec); + return (istate->timestamp.sec && -#ifdef USE_NSEC - /* nanosecond timestamped files can also be racy! */ - (istate->timestamp.sec < sd->sd_mtime.sec || - (istate->timestamp.sec == sd->sd_mtime.sec && - istate->timestamp.nsec <= sd->sd_mtime.nsec)) -#else - istate->timestamp.sec <= sd->sd_mtime.sec -#endif + /* nanosecond timestamped files can also be racy! */ + use_nsec + ? (istate->timestamp.sec < sd->sd_mtime.sec || + (istate->timestamp.sec == sd->sd_mtime.sec && + istate->timestamp.nsec <= sd->sd_mtime.nsec)) + : istate->timestamp.sec <= sd->sd_mtime.sec ); } diff --git a/statinfo.c b/statinfo.c index 5e00af127d..d9ddcf9382 100644 --- a/statinfo.c +++ b/statinfo.c @@ -72,13 +72,13 @@ int match_stat_data(const struct stat_data *sd, struct stat *st) sd->sd_ctime.sec != (unsigned int)st->st_ctime) changed |= CTIME_CHANGED; -#ifdef USE_NSEC - if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) - changed |= MTIME_CHANGED; - if (cfg->trust_ctime && cfg->check_stat && - sd->sd_ctime.nsec != ST_CTIME_NSEC(*st)) - changed |= CTIME_CHANGED; -#endif + if (cfg->use_nanosec) { + if (cfg->check_stat && sd->sd_mtime.nsec != ST_MTIME_NSEC(*st)) + changed |= MTIME_CHANGED; + if (cfg->trust_ctime && cfg->check_stat && + sd->sd_ctime.nsec != ST_CTIME_NSEC(*st)) + changed |= CTIME_CHANGED; + } if (cfg->check_stat) { if (sd->sd_uid != (unsigned int) st->st_uid ||