summaryrefslogtreecommitdiffstats
path: root/refs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--refs.c25
-rw-r--r--refs/packed-backend.c23
2 files changed, 34 insertions, 14 deletions
diff --git a/refs.c b/refs.c
index cd297ee4bd..1ab0bb54d3 100644
--- a/refs.c
+++ b/refs.c
@@ -1772,7 +1772,7 @@ int resolve_gitlink_ref(const char *submodule, const char *refname,
struct ref_store_hash_entry
{
- struct hashmap_entry ent; /* must be the first member! */
+ struct hashmap_entry ent;
struct ref_store *refs;
@@ -1781,11 +1781,16 @@ struct ref_store_hash_entry
};
static int ref_store_hash_cmp(const void *unused_cmp_data,
- const void *entry, const void *entry_or_key,
+ const struct hashmap_entry *eptr,
+ const struct hashmap_entry *entry_or_key,
const void *keydata)
{
- const struct ref_store_hash_entry *e1 = entry, *e2 = entry_or_key;
- const char *name = keydata ? keydata : e2->name;
+ const struct ref_store_hash_entry *e1, *e2;
+ const char *name;
+
+ e1 = container_of(eptr, const struct ref_store_hash_entry, ent);
+ e2 = container_of(entry_or_key, const struct ref_store_hash_entry, ent);
+ name = keydata ? keydata : e2->name;
return strcmp(e1->name, name);
}
@@ -1796,7 +1801,7 @@ static struct ref_store_hash_entry *alloc_ref_store_hash_entry(
struct ref_store_hash_entry *entry;
FLEX_ALLOC_STR(entry, name, name);
- hashmap_entry_init(entry, strhash(name));
+ hashmap_entry_init(&entry->ent, strhash(name));
entry->refs = refs;
return entry;
}
@@ -1815,12 +1820,15 @@ static struct ref_store *lookup_ref_store_map(struct hashmap *map,
const char *name)
{
struct ref_store_hash_entry *entry;
+ unsigned int hash;
if (!map->tablesize)
/* It's initialized on demand in register_ref_store(). */
return NULL;
- entry = hashmap_get_from_hash(map, strhash(name), name);
+ hash = strhash(name);
+ entry = hashmap_get_entry_from_hash(map, hash, name,
+ struct ref_store_hash_entry, ent);
return entry ? entry->refs : NULL;
}
@@ -1863,10 +1871,13 @@ static void register_ref_store_map(struct hashmap *map,
struct ref_store *refs,
const char *name)
{
+ struct ref_store_hash_entry *entry;
+
if (!map->tablesize)
hashmap_init(map, ref_store_hash_cmp, NULL, 0);
- if (hashmap_put(map, alloc_ref_store_hash_entry(name, refs)))
+ entry = alloc_ref_store_hash_entry(name, refs);
+ if (hashmap_put(map, &entry->ent))
BUG("%s ref_store '%s' initialized twice", type, name);
}
diff --git a/refs/packed-backend.c b/refs/packed-backend.c
index c01c7f5901..4458a0f69c 100644
--- a/refs/packed-backend.c
+++ b/refs/packed-backend.c
@@ -1012,14 +1012,23 @@ int packed_refs_lock(struct ref_store *ref_store, int flags, struct strbuf *err)
}
/*
- * Now that we hold the `packed-refs` lock, make sure that our
- * snapshot matches the current version of the file. Normally
- * `get_snapshot()` does that for us, but that function
- * assumes that when the file is locked, any existing snapshot
- * is still valid. We've just locked the file, but it might
- * have changed the moment *before* we locked it.
+ * There is a stat-validity problem might cause `update-ref -d`
+ * lost the newly commit of a ref, because a new `packed-refs`
+ * file might has the same on-disk file attributes such as
+ * timestamp, file size and inode value, but has a changed
+ * ref value.
+ *
+ * This could happen with a very small chance when
+ * `update-ref -d` is called and at the same time another
+ * `pack-refs --all` process is running.
+ *
+ * Now that we hold the `packed-refs` lock, it is important
+ * to make sure we could read the latest version of
+ * `packed-refs` file no matter we have just mmap it or not.
+ * So what need to do is clear the snapshot if we hold it
+ * already.
*/
- validate_snapshot(refs);
+ clear_snapshot(refs);
/*
* Now make sure that the packed-refs file as it exists in the