git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
* [PATCH] dir.c: print correct errno when opendir() fails
@ 2018-01-18  9:50 Nguyễn Thái Ngọc Duy
  2018-01-19 21:09 ` Junio C Hamano
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
  0 siblings, 2 replies; 12+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2018-01-18  9:50 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

The call invalidate_directory() between opendir() and warning_errno() in
theory could make some system calls and change errno. Prevent that by
warning immediately after opendir().

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 This is on top of nd/fix-untracked-cache-invalidation which is now on
 'next'. Sorry I waited too long to send the replacement and it's now
 too late.

 dir.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/dir.c b/dir.c
index dd1e50c328..55736d3e2a 100644
--- a/dir.c
+++ b/dir.c
@@ -1795,14 +1795,14 @@ static int open_cached_dir(struct cached_dir *cdir,
 		return 0;
 	c_path = path->len ? path->buf : ".";
 	cdir->fdir = opendir(c_path);
+	if (!cdir->fdir)
+		warning_errno(_("could not open directory '%s'"), c_path);
 	if (dir->untracked) {
 		invalidate_directory(dir->untracked, untracked);
 		dir->untracked->dir_opened++;
 	}
-	if (!cdir->fdir) {
-		warning_errno(_("could not open directory '%s'"), c_path);
+	if (!cdir->fdir)
 		return -1;
-	}
 	return 0;
 }
 
-- 
2.15.1.600.g899a5f85c6


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH] dir.c: print correct errno when opendir() fails
  2018-01-18  9:50 [PATCH] dir.c: print correct errno when opendir() fails Nguyễn Thái Ngọc Duy
@ 2018-01-19 21:09 ` Junio C Hamano
  2018-01-21 11:52   ` Duy Nguyen
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
  1 sibling, 1 reply; 12+ messages in thread
From: Junio C Hamano @ 2018-01-19 21:09 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git

Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:

> The call invalidate_directory() between opendir() and warning_errno() in
> theory could make some system calls and change errno. Prevent that by
> warning immediately after opendir().
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> ---
>  This is on top of nd/fix-untracked-cache-invalidation which is now on
>  'next'. Sorry I waited too long to send the replacement and it's now
>  too late.

Well, we'll see a rewind of 'next' soonish anyway, so you can just
tell me to tentatively kick it back to 'pu' to be replaced with a
reroll if you prefer.




>  dir.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/dir.c b/dir.c
> index dd1e50c328..55736d3e2a 100644
> --- a/dir.c
> +++ b/dir.c
> @@ -1795,14 +1795,14 @@ static int open_cached_dir(struct cached_dir *cdir,
>  		return 0;
>  	c_path = path->len ? path->buf : ".";
>  	cdir->fdir = opendir(c_path);
> +	if (!cdir->fdir)
> +		warning_errno(_("could not open directory '%s'"), c_path);
>  	if (dir->untracked) {
>  		invalidate_directory(dir->untracked, untracked);
>  		dir->untracked->dir_opened++;
>  	}
> -	if (!cdir->fdir) {
> -		warning_errno(_("could not open directory '%s'"), c_path);
> +	if (!cdir->fdir)
>  		return -1;
> -	}
>  	return 0;
>  }

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] dir.c: print correct errno when opendir() fails
  2018-01-19 21:09 ` Junio C Hamano
@ 2018-01-21 11:52   ` Duy Nguyen
  0 siblings, 0 replies; 12+ messages in thread
From: Duy Nguyen @ 2018-01-21 11:52 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Git Mailing List

On Sat, Jan 20, 2018 at 4:09 AM, Junio C Hamano <gitster@pobox.com> wrote:
> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:
>
>> The call invalidate_directory() between opendir() and warning_errno() in
>> theory could make some system calls and change errno. Prevent that by
>> warning immediately after opendir().
>>
>> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
>> ---
>>  This is on top of nd/fix-untracked-cache-invalidation which is now on
>>  'next'. Sorry I waited too long to send the replacement and it's now
>>  too late.
>
> Well, we'll see a rewind of 'next' soonish anyway, so you can just
> tell me to tentatively kick it back to 'pu' to be replaced with a
> reroll if you prefer.

Please kick it back to 'pu'.
-- 
Duy

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 0/5] nd/fix-untracked-cache-invalidation updates
  2018-01-18  9:50 [PATCH] dir.c: print correct errno when opendir() fails Nguyễn Thái Ngọc Duy
  2018-01-19 21:09 ` Junio C Hamano
@ 2018-01-24  9:30 ` Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 1/5] status: add a failing test showing a core.untrackedCache bug Nguyễn Thái Ngọc Duy
                     ` (5 more replies)
  1 sibling, 6 replies; 12+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2018-01-24  9:30 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

This is a small update where the last two patches on 'pu' are merged
in one. The final content is exactly the same as on 'pu'.

Nguyễn Thái Ngọc Duy (3):
  dir.c: avoid stat() in valid_cached_dir()
  dir.c: fix missing dir invalidation in untracked code
  dir.c: stop ignoring opendir() error in open_cached_dir()

Ævar Arnfjörð Bjarmason (2):
  status: add a failing test showing a core.untrackedCache bug
  update-index doc: note a fixed bug in the untracked cache

 Documentation/git-update-index.txt | 16 +++++++
 dir.c                              | 31 +++++++++-----
 t/t7063-status-untracked-cache.sh  | 87 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 124 insertions(+), 10 deletions(-)

-- 
2.16.0.47.g3d9b0fac3a


^ permalink raw reply	[flat|nested] 12+ messages in thread

* [PATCH 1/5] status: add a failing test showing a core.untrackedCache bug
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
@ 2018-01-24  9:30   ` Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 2/5] dir.c: avoid stat() in valid_cached_dir() Nguyễn Thái Ngọc Duy
                     ` (4 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2018-01-24  9:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason,
	Nguyễn Thái Ngọc Duy

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

The untracked cache gets confused when a directory is swapped out for
a file. It is easiest to reproduce this by swapping out a directory
with a symlink to another directory, and as the tests show the symlink
case is the only case we've found where "git status" will subsequently
report incorrect information, even though it's possible to otherwise
get the untracked cache into a state where its internal data
structures don't reflect reality.

In the symlink case, whatever files are inside the target of the
symlink will be incorrectly shown as untracked. This issue does not
happen if the symlink links to another file, only if it links to
another directory.

A stand-alone testcase for copying into a terminal:

    (
        rm -rf /tmp/testrepo &&
        git init /tmp/testrepo &&
        cd /tmp/testrepo &&
        mkdir x y &&
        touch x/a y/b &&
        git add x/a y/b &&
        git commit -msnap &&
        git rm -rf y &&
        ln -s x y &&
        git add y &&
        git commit -msnap2 &&
        git checkout HEAD~ &&
        git status &&
        git checkout master &&
        sleep 1 &&
        git status &&
        git status
    )

This will incorrectly show y/a as an untracked file. Both the "git
status" call right before "git checkout master" and the "sleep 1"
after the "checkout master" are needed to reproduce this, presumably
due to the untracked cache tracking on the basis of cached whole
seconds from stat(2).

When git gets into this state, a workaround to fix it is to issue a
one-off:

    git -c core.untrackedCache=false status

For the non-symlink case, the bug is that the output of
test-dump-untracked-cache should not include:

   /one/ 0000000000000000000000000000000000000000 recurse valid

It being in the output implies that cached traversal of root includes
the directory "one" which does not exist on disk anymore.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 t/t7063-status-untracked-cache.sh | 87 +++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index e5fb892f95..dba7f50bbb 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -22,6 +22,12 @@ avoid_racy() {
 	sleep 1
 }
 
+status_is_clean() {
+	>../status.expect &&
+	git status --porcelain >../status.actual &&
+	test_cmp ../status.expect ../status.actual
+}
+
 test_lazy_prereq UNTRACKED_CACHE '
 	{ git update-index --test-untracked-cache; ret=$?; } &&
 	test $ret -ne 1
@@ -683,4 +689,85 @@ test_expect_success 'untracked cache survives a commit' '
 	test_cmp ../before ../after
 '
 
+test_expect_success 'teardown worktree' '
+	cd ..
+'
+
+test_expect_success SYMLINKS 'setup worktree for symlink test' '
+	git init worktree-symlink &&
+	cd worktree-symlink &&
+	git config core.untrackedCache true &&
+	mkdir one two &&
+	touch one/file two/file &&
+	git add one/file two/file &&
+	git commit -m"first commit" &&
+	git rm -rf one &&
+	ln -s two one &&
+	git add one &&
+	git commit -m"second commit"
+'
+
+test_expect_failure SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
+	git checkout HEAD~ &&
+	status_is_clean &&
+	status_is_clean &&
+	git checkout master &&
+	avoid_racy &&
+	status_is_clean &&
+	status_is_clean
+'
+
+test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=false' '
+	git config core.untrackedCache false &&
+	git checkout HEAD~ &&
+	status_is_clean &&
+	status_is_clean &&
+	git checkout master &&
+	avoid_racy &&
+	status_is_clean &&
+	status_is_clean
+'
+
+test_expect_success 'setup worktree for non-symlink test' '
+	git init worktree-non-symlink &&
+	cd worktree-non-symlink &&
+	git config core.untrackedCache true &&
+	mkdir one two &&
+	touch one/file two/file &&
+	git add one/file two/file &&
+	git commit -m"first commit" &&
+	git rm -rf one &&
+	cp two/file one &&
+	git add one &&
+	git commit -m"second commit"
+'
+
+test_expect_failure '"status" after file replacement should be clean with UC=true' '
+	git checkout HEAD~ &&
+	status_is_clean &&
+	status_is_clean &&
+	git checkout master &&
+	avoid_racy &&
+	status_is_clean &&
+	test-dump-untracked-cache >../actual &&
+	grep -F "recurse valid" ../actual >../actual.grep &&
+	cat >../expect.grep <<EOF &&
+/ 0000000000000000000000000000000000000000 recurse valid
+/two/ 0000000000000000000000000000000000000000 recurse valid
+EOF
+	status_is_clean &&
+	test_cmp ../expect.grep ../actual.grep
+'
+
+test_expect_success '"status" after file replacement should be clean with UC=false' '
+	git config core.untrackedCache false &&
+	git checkout HEAD~ &&
+	status_is_clean &&
+	status_is_clean &&
+	git checkout master &&
+	avoid_racy &&
+	status_is_clean &&
+	status_is_clean
+'
+
 test_done
-- 
2.16.0.47.g3d9b0fac3a


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 2/5] dir.c: avoid stat() in valid_cached_dir()
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 1/5] status: add a failing test showing a core.untrackedCache bug Nguyễn Thái Ngọc Duy
@ 2018-01-24  9:30   ` Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 3/5] dir.c: fix missing dir invalidation in untracked code Nguyễn Thái Ngọc Duy
                     ` (3 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2018-01-24  9:30 UTC (permalink / raw)
  To: git; +Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy

stat() may follow a symlink and return stat data of the link's target
instead of the link itself. We are concerned about the link itself.

It's kind of hard to demonstrate the bug. I think when path->buf is a
symlink, we most likely find that its target's stat data does not
match our cached one, which means we ignore the cache and fall back to
slow path.

This is performance issue, not correctness (though we could still
catch it by verifying test-dump-untracked-cache. The less unlikely
case is, link target stat data matches the cached version and we
incorrectly go fast path, ignoring real data on disk. A test for this
may involve manipulating stat data, which may be not portable.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 dir.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/dir.c b/dir.c
index 3c54366a17..ee1605f004 100644
--- a/dir.c
+++ b/dir.c
@@ -1739,7 +1739,7 @@ static int valid_cached_dir(struct dir_struct *dir,
 	 */
 	refresh_fsmonitor(istate);
 	if (!(dir->untracked->use_fsmonitor && untracked->valid)) {
-		if (stat(path->len ? path->buf : ".", &st)) {
+		if (lstat(path->len ? path->buf : ".", &st)) {
 			invalidate_directory(dir->untracked, untracked);
 			memset(&untracked->stat_data, 0, sizeof(untracked->stat_data));
 			return 0;
-- 
2.16.0.47.g3d9b0fac3a


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 3/5] dir.c: fix missing dir invalidation in untracked code
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 1/5] status: add a failing test showing a core.untrackedCache bug Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 2/5] dir.c: avoid stat() in valid_cached_dir() Nguyễn Thái Ngọc Duy
@ 2018-01-24  9:30   ` Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 4/5] update-index doc: note a fixed bug in the untracked cache Nguyễn Thái Ngọc Duy
                     ` (2 subsequent siblings)
  5 siblings, 0 replies; 12+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2018-01-24  9:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

Let's start with how create a new directory cache after the last one
becomes invalid (e.g. because its dir mtime has changed...). In
open_cached_dir():

1. We start out with valid_cached_dir() returning false, which should
   call invalidate_directory() to put a directory state back to
   initial state, no untracked entries (untracked_nr zero), no sub
   directory traversal (dirs[].recurse zero).

2. Since the cache cannot be used, we go the slow path opendir() and
   go through items one by one via readdir(). All the directories on
   disk will be added back to the cache (if not already exist in
   dirs[]) and its flag "recurse" gets changed to one to note that
   it's part of the cached dir travesal next time.

3. By the time we reach close_cached_dir() we should have a good
   subdir list in dirs[]. Those with "recurse" flag set are the ones
   present in the on-disk directory. The directory is now marked
   "valid".

Next time read_directory() is called, since the directory is marked
valid, it will skip readdir(), go fast path and traverse through
dirs[] array instead.

Steps one and two need some tight cooperation. If a subdir is removed,
readdir() will not find it and of course we cannot examine/invalidate
it. To make sure removed directories on disk are gone from the cache,
step one must make sure recurse flag of all subdirs are zero.

But that's not true. If "valid" flag is already false, there is a
chance we go straight to the end of valid_cached_dir() without calling
invalidate_directory(). Or we fail to meet the "if (untracked-valid)"
condition and skip over the invalidate_directory().

After step 3, we mark the cache valid. Any stale subdir with incorrect
recurse flag becomes a real subdir next time we traverse the directory
using dirs[] array.

We could avoid this by making sure invalidate_directory() is always
called (therefore dirs[].recurse cleared) at the beginning of
open_cached_dir(). Which is what this patch does.

As to how we get into this situation, the key in the test is this
command

    git checkout master

where "one/file" is replaced with "one" in the index. This index
update triggers untracked_cache_invalidate_path(), which clears valid
flag of the root directory while keeping "recurse" flag on the subdir
"one" on. On the next git-status, we go through steps 1-3 above and
save an incorrect cache on disk. The second git-status blindly follows
the bad cache data and shows the problem.

This is arguably because of a bad design where "recurse" flag plays
double roles: whether a directory should be saved on disk, and whether
it is part of a directory traversal.

We need to keep recurse flag set at "checkout master" because of the
first role: we need to keep subdir caches (dir "two" for example has
not been touched at all, no reason to throw its cache away).

As long as we make sure to ignore/reset "recurse" flag at the
beginning of a directory traversal, we're good. But maybe eventually
we should separate these two roles.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
---
 dir.c                             | 22 ++++++++++++++--------
 t/t7063-status-untracked-cache.sh |  4 ++--
 2 files changed, 16 insertions(+), 10 deletions(-)

diff --git a/dir.c b/dir.c
index ee1605f004..44b4dd2ec8 100644
--- a/dir.c
+++ b/dir.c
@@ -733,7 +733,16 @@ static void invalidate_directory(struct untracked_cache *uc,
 				 struct untracked_cache_dir *dir)
 {
 	int i;
-	uc->dir_invalidated++;
+
+	/*
+	 * Invalidation increment here is just roughly correct. If
+	 * untracked_nr or any of dirs[].recurse is non-zero, we
+	 * should increment dir_invalidated too. But that's more
+	 * expensive to do.
+	 */
+	if (dir->valid)
+		uc->dir_invalidated++;
+
 	dir->valid = 0;
 	dir->untracked_nr = 0;
 	for (i = 0; i < dir->dirs_nr; i++)
@@ -1740,23 +1749,18 @@ static int valid_cached_dir(struct dir_struct *dir,
 	refresh_fsmonitor(istate);
 	if (!(dir->untracked->use_fsmonitor && untracked->valid)) {
 		if (lstat(path->len ? path->buf : ".", &st)) {
-			invalidate_directory(dir->untracked, untracked);
 			memset(&untracked->stat_data, 0, sizeof(untracked->stat_data));
 			return 0;
 		}
 		if (!untracked->valid ||
 			match_stat_data_racy(istate, &untracked->stat_data, &st)) {
-			if (untracked->valid)
-				invalidate_directory(dir->untracked, untracked);
 			fill_stat_data(&untracked->stat_data, &st);
 			return 0;
 		}
 	}
 
-	if (untracked->check_only != !!check_only) {
-		invalidate_directory(dir->untracked, untracked);
+	if (untracked->check_only != !!check_only)
 		return 0;
-	}
 
 	/*
 	 * prep_exclude will be called eventually on this directory,
@@ -1788,8 +1792,10 @@ static int open_cached_dir(struct cached_dir *cdir,
 	if (valid_cached_dir(dir, untracked, istate, path, check_only))
 		return 0;
 	cdir->fdir = opendir(path->len ? path->buf : ".");
-	if (dir->untracked)
+	if (dir->untracked) {
+		invalidate_directory(dir->untracked, untracked);
 		dir->untracked->dir_opened++;
+	}
 	if (!cdir->fdir)
 		return -1;
 	return 0;
diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh
index dba7f50bbb..46b947824f 100755
--- a/t/t7063-status-untracked-cache.sh
+++ b/t/t7063-status-untracked-cache.sh
@@ -707,7 +707,7 @@ test_expect_success SYMLINKS 'setup worktree for symlink test' '
 	git commit -m"second commit"
 '
 
-test_expect_failure SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
+test_expect_success SYMLINKS '"status" after symlink replacement should be clean with UC=true' '
 	git checkout HEAD~ &&
 	status_is_clean &&
 	status_is_clean &&
@@ -742,7 +742,7 @@ test_expect_success 'setup worktree for non-symlink test' '
 	git commit -m"second commit"
 '
 
-test_expect_failure '"status" after file replacement should be clean with UC=true' '
+test_expect_success '"status" after file replacement should be clean with UC=true' '
 	git checkout HEAD~ &&
 	status_is_clean &&
 	status_is_clean &&
-- 
2.16.0.47.g3d9b0fac3a


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 4/5] update-index doc: note a fixed bug in the untracked cache
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
                     ` (2 preceding siblings ...)
  2018-01-24  9:30   ` [PATCH 3/5] dir.c: fix missing dir invalidation in untracked code Nguyễn Thái Ngọc Duy
@ 2018-01-24  9:30   ` Nguyễn Thái Ngọc Duy
  2018-01-24  9:30   ` [PATCH 5/5] dir.c: stop ignoring opendir() error in open_cached_dir() Nguyễn Thái Ngọc Duy
  2018-01-24 11:47   ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Ævar Arnfjörð Bjarmason
  5 siblings, 0 replies; 12+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2018-01-24  9:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Ævar Arnfjörð Bjarmason,
	Nguyễn Thái Ngọc Duy

From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>

Document the bug tested for in my "status: add a failing test showing
a core.untrackedCache bug" and fixed in Duy's "dir.c: fix missing dir
invalidation in untracked code".

Since this is very likely something others will encounter in the
future on older versions, and it's not obvious how to fix it let's
document both that it exists, and how to "fix" it with a one-off
command.

As noted in that commit, even though this bug gets the untracked cache
into a bad state, we have not yet found a case where this is user
visible, and thus it makes sense for these docs to focus on the
symlink case only.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 Documentation/git-update-index.txt | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/Documentation/git-update-index.txt b/Documentation/git-update-index.txt
index bdb0342593..128e0c671f 100644
--- a/Documentation/git-update-index.txt
+++ b/Documentation/git-update-index.txt
@@ -464,6 +464,22 @@ command reads the index; while when `--[no-|force-]untracked-cache`
 are used, the untracked cache is immediately added to or removed from
 the index.
 
+Before 2.16, the untracked cache had a bug where replacing a directory
+with a symlink to another directory could cause it to incorrectly show
+files tracked by git as untracked. See the "status: add a failing test
+showing a core.untrackedCache bug" commit to git.git. A workaround for
+that was (and this might work for other undiscoverd bugs in the
+future):
+
+----------------
+$ git -c core.untrackedCache=false status
+----------------
+
+This bug has also been shown to affect non-symlink cases of replacing
+a directory with a file when it comes to the internal structures of
+the untracked cache, but no case has been found where this resulted in
+wrong "git status" output.
+
 File System Monitor
 -------------------
 
-- 
2.16.0.47.g3d9b0fac3a


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [PATCH 5/5] dir.c: stop ignoring opendir() error in open_cached_dir()
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
                     ` (3 preceding siblings ...)
  2018-01-24  9:30   ` [PATCH 4/5] update-index doc: note a fixed bug in the untracked cache Nguyễn Thái Ngọc Duy
@ 2018-01-24  9:30   ` Nguyễn Thái Ngọc Duy
  2018-02-01 23:00     ` Ævar Arnfjörð Bjarmason
  2018-01-24 11:47   ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Ævar Arnfjörð Bjarmason
  5 siblings, 1 reply; 12+ messages in thread
From: Nguyễn Thái Ngọc Duy @ 2018-01-24  9:30 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Nguyễn Thái Ngọc Duy,
	Ævar Arnfjörð Bjarmason

A follow-up to the recently fixed bugs in the untracked
invalidation. If opendir() fails it should show a warning, perhaps
this should die, but if this ever happens the error is probably
recoverable for the user, and dying would just make things worse.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 dir.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/dir.c b/dir.c
index 44b4dd2ec8..55736d3e2a 100644
--- a/dir.c
+++ b/dir.c
@@ -1787,11 +1787,16 @@ static int open_cached_dir(struct cached_dir *cdir,
 			   struct strbuf *path,
 			   int check_only)
 {
+	const char *c_path;
+
 	memset(cdir, 0, sizeof(*cdir));
 	cdir->untracked = untracked;
 	if (valid_cached_dir(dir, untracked, istate, path, check_only))
 		return 0;
-	cdir->fdir = opendir(path->len ? path->buf : ".");
+	c_path = path->len ? path->buf : ".";
+	cdir->fdir = opendir(c_path);
+	if (!cdir->fdir)
+		warning_errno(_("could not open directory '%s'"), c_path);
 	if (dir->untracked) {
 		invalidate_directory(dir->untracked, untracked);
 		dir->untracked->dir_opened++;
-- 
2.16.0.47.g3d9b0fac3a


^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/5] nd/fix-untracked-cache-invalidation updates
  2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
                     ` (4 preceding siblings ...)
  2018-01-24  9:30   ` [PATCH 5/5] dir.c: stop ignoring opendir() error in open_cached_dir() Nguyễn Thái Ngọc Duy
@ 2018-01-24 11:47   ` Ævar Arnfjörð Bjarmason
  2018-01-24 20:41     ` Junio C Hamano
  5 siblings, 1 reply; 12+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-01-24 11:47 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano


On Wed, Jan 24 2018, Nguyễn Thái Ngọc Duy jotted:

> This is a small update where the last two patches on 'pu' are merged
> in one. The final content is exactly the same as on 'pu'.
>
> Nguyễn Thái Ngọc Duy (3):
>   dir.c: avoid stat() in valid_cached_dir()
>   dir.c: fix missing dir invalidation in untracked code
>   dir.c: stop ignoring opendir() error in open_cached_dir()
>
> Ævar Arnfjörð Bjarmason (2):
>   status: add a failing test showing a core.untrackedCache bug
>   update-index doc: note a fixed bug in the untracked cache

Looks good to me.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 0/5] nd/fix-untracked-cache-invalidation updates
  2018-01-24 11:47   ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Ævar Arnfjörð Bjarmason
@ 2018-01-24 20:41     ` Junio C Hamano
  0 siblings, 0 replies; 12+ messages in thread
From: Junio C Hamano @ 2018-01-24 20:41 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Nguyễn Thái Ngọc Duy, git

Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:

> On Wed, Jan 24 2018, Nguyễn Thái Ngọc Duy jotted:
>
>> This is a small update where the last two patches on 'pu' are merged
>> in one. The final content is exactly the same as on 'pu'.
>>
>> Nguyễn Thái Ngọc Duy (3):
>>   dir.c: avoid stat() in valid_cached_dir()
>>   dir.c: fix missing dir invalidation in untracked code
>>   dir.c: stop ignoring opendir() error in open_cached_dir()
>>
>> Ævar Arnfjörð Bjarmason (2):
>>   status: add a failing test showing a core.untrackedCache bug
>>   update-index doc: note a fixed bug in the untracked cache
>
> Looks good to me.

Yup, looks good.  Thanks, both.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH 5/5] dir.c: stop ignoring opendir() error in open_cached_dir()
  2018-01-24  9:30   ` [PATCH 5/5] dir.c: stop ignoring opendir() error in open_cached_dir() Nguyễn Thái Ngọc Duy
@ 2018-02-01 23:00     ` Ævar Arnfjörð Bjarmason
  0 siblings, 0 replies; 12+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-02-01 23:00 UTC (permalink / raw)
  To: Nguyễn Thái Ngọc Duy; +Cc: git, Junio C Hamano


On Wed, Jan 24 2018, Nguyễn Thái Ngọc Duy jotted:

> A follow-up to the recently fixed bugs in the untracked
> invalidation. If opendir() fails it should show a warning, perhaps
> this should die, but if this ever happens the error is probably
> recoverable for the user, and dying would just make things worse.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
> ---
>  dir.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
>
> diff --git a/dir.c b/dir.c
> index 44b4dd2ec8..55736d3e2a 100644
> --- a/dir.c
> +++ b/dir.c
> @@ -1787,11 +1787,16 @@ static int open_cached_dir(struct cached_dir *cdir,
>  			   struct strbuf *path,
>  			   int check_only)
>  {
> +	const char *c_path;
> +
>  	memset(cdir, 0, sizeof(*cdir));
>  	cdir->untracked = untracked;
>  	if (valid_cached_dir(dir, untracked, istate, path, check_only))
>  		return 0;
> -	cdir->fdir = opendir(path->len ? path->buf : ".");
> +	c_path = path->len ? path->buf : ".";
> +	cdir->fdir = opendir(c_path);
> +	if (!cdir->fdir)
> +		warning_errno(_("could not open directory '%s'"), c_path);
>  	if (dir->untracked) {
>  		invalidate_directory(dir->untracked, untracked);
>  		dir->untracked->dir_opened++;

I haven't found the root cause yet, but we should not release a 2.17
with this patch.

I tried deploying a 2.16.1 + various patches (including this) internally
today, and on a test set of 236 machines with existing checkouts
(already using untracked cache) 79 would spew "warning: could not open
directory" warnings, warning about a lot of directories that did not
exist at the currently checked-out commit.

The warnings go away on a one-off:

    git -c core.untrackedCache=false status

So there's some issue where an existing index with stale UC will be used
by a newer version of git, and will start very verbosely warning about
every directory referenced that can't be found anymore.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2018-02-01 23:00 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-18  9:50 [PATCH] dir.c: print correct errno when opendir() fails Nguyễn Thái Ngọc Duy
2018-01-19 21:09 ` Junio C Hamano
2018-01-21 11:52   ` Duy Nguyen
2018-01-24  9:30 ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Nguyễn Thái Ngọc Duy
2018-01-24  9:30   ` [PATCH 1/5] status: add a failing test showing a core.untrackedCache bug Nguyễn Thái Ngọc Duy
2018-01-24  9:30   ` [PATCH 2/5] dir.c: avoid stat() in valid_cached_dir() Nguyễn Thái Ngọc Duy
2018-01-24  9:30   ` [PATCH 3/5] dir.c: fix missing dir invalidation in untracked code Nguyễn Thái Ngọc Duy
2018-01-24  9:30   ` [PATCH 4/5] update-index doc: note a fixed bug in the untracked cache Nguyễn Thái Ngọc Duy
2018-01-24  9:30   ` [PATCH 5/5] dir.c: stop ignoring opendir() error in open_cached_dir() Nguyễn Thái Ngọc Duy
2018-02-01 23:00     ` Ævar Arnfjörð Bjarmason
2018-01-24 11:47   ` [PATCH 0/5] nd/fix-untracked-cache-invalidation updates Ævar Arnfjörð Bjarmason
2018-01-24 20:41     ` Junio C Hamano

Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).