Commit 94743daf2efbc875076f52dcea075415a2208aab

Patrick Steinhardt 2019-02-15T11:16:46

refdb_fs: fix race when migrating loose to packed refs in iteration Right now, we first load the packed refs cache and only afterwards load the loose references. This is susceptible to a race when the loose ref is being migrated to a packed cache by e.g. git-pack-refs(1): libgit2 git-pack-refs 1. We load the packed ref, which does not yet have the migrated reference. 2. git-pack-refs updates the packed ref file to have the migrated ref. 3. git-pack-refs deletes the old loose ref. 4. We look up the loose ref. So we now do not find the reference at all and will never iterate over it. Fix the issue by reversing the order: instead of first loading the packed refs, we will now look up the loose reference first. If it has already been deleted, then it must already be present in the packed-refs by definition, as git.git will only delete the reference after updating the packed refs file.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
diff --git a/src/refdb_fs.c b/src/refdb_fs.c
index b805093..30aa1a8 100644
--- a/src/refdb_fs.c
+++ b/src/refdb_fs.c
@@ -694,10 +694,10 @@ static int refdb_fs_backend__iterator(
 		goto out;
 	}
 
-	if ((error = packed_reload(backend)) < 0)
+	if ((error = iter_load_loose_paths(backend, iter)) < 0)
 		goto out;
 
-	if ((error = iter_load_loose_paths(backend, iter)) < 0)
+	if ((error = packed_reload(backend)) < 0)
 		goto out;
 
 	if ((error = git_sortedcache_copy(&iter->cache, backend->refcache, 1, NULL, NULL)) < 0)