Re: [PATCH v3 3/3] core: convert build-time USE_NSEC into runtime core.useNanosec

Patrick Steinhardt <[email protected]>
Newsgroups org.kernel.vger.git
Message-ID <[email protected]>
On Tue, Aug 18, 2026 at 10:59:47AM -0400, D. Ben Knoble wrote:
> Racy Git problems persist today, manifesting themselves in the
> performance of commands like "git diff" in new worktrees [1]. We have
> long had a build knob "USE_NSEC" to tell Git to use in-core nanosecond
> precision when available, which mitigates most if not all racy issues,
> but most builds we know about it don't use it. In part, that's because

s/about it/about/

> 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.

Should we mentino here that this may not be safe on all platforms and/or
filesystems, in addition to linking to racy-hit?

And do we really want to link to the HTML page here? The user may be
reading a manpage, so doing so feels a bit weird to me.

> diff --git a/environment.c b/environment.c
> index 6676e6f5ae..c7f6b801f4 100644
> --- a/environment.c
> +++ b/environment.c
> @@ -571,6 +571,13 @@ int git_default_core_config(const char *var, const char *value,
>  		return 0;
>  	}
>  
> +#ifndef NO_NSEC
> +	if (!strcmp(var, "core.usenanosec")) {
> +		cfg->use_nanosec = git_config_bool(var, value);
> +		return 0;
> +	}
> +#endif

Do we want to omit a warning in case the config is enabled and we have
NO_SEC set? Or would that be too obnoxious?

> @@ -769,6 +776,9 @@ 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();
> +#ifndef NO_NSEC
> +	cfg->use_nanosec = 0;
> +#endif

Can't we set this unconditionally? The respective field exists
unconditionally, too.

> diff --git a/read-cache.c b/read-cache.c
> index 6c449f393d..31888f77ee 100644
> --- a/read-cache.c
> +++ b/read-cache.c
> @@ -353,12 +353,18 @@ 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)
>  {
> +#ifndef NO_NSEC
> +	int use_nsec = repo_config_values(istate->repo)->use_nanosec;
> +#endif
> +
>  	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))
> +#ifndef NO_NSEC
> +		/* 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
>  #else
>  		istate->timestamp.sec <= sd->sd_mtime.sec
>  #endif

I think this would be a bit more readable if we had a single NO_NSEC
block.

> diff --git a/statinfo.c b/statinfo.c
> index 5e00af127d..2f2cec6282 100644
> --- a/statinfo.c
> +++ b/statinfo.c
> @@ -72,12 +72,14 @@ 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;
> +#ifndef NO_NSEC
> +	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;
> +	}
>  #endif

There's one more site in "builtin/update-index.c" where we mention
USE_NSEC that wasn't updated as part of this patch.

Thanks!

Patrick
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.