create_symref: write reflog while holding lock

We generally hold a lock on the matching ref while writing to its reflog; this prevents two simultaneous writers from clobbering each other's reflog lines (it does not even have to be two symref updates; because we don't hold the lock, we could race with somebody writing to the pointed-to ref via HEAD, for example). We can fix this by writing the reflog before we commit the lockfile. This runs the risk of writing the reflog but failing the final rename(), but at least we now err on the same side as the rest of the ref code. Noticed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net> Reviewed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Dec 29, 2015 at 00:57 UTC 396da8f7a07ae02a6152e0c0fc3eaac8a99b4c65
1 file changed +2 -1
refs/files-backend.c
+2 -1
@@ -2850,12 +2850,13 @@ static int create_symref_locked(struct ref_lock *lock, const char *refname,
2850 return error("unable to fdopen %s: %s",
2851 lock->lk->tempfile.filename.buf, strerror(errno));
2852
2853 + update_symref_reflog(lock, refname, target, logmsg);
2854 +
2855 /* no error check; commit_ref will check ferror */
2856 fprintf(lock->lk->tempfile.fp, "ref: %s\n", target);
2857 if (commit_ref(lock) < 0)
2858 return error("unable to write symref for %s: %s", refname,
2859 strerror(errno));
2858 - update_symref_reflog(lock, refname, target, logmsg);
2860 return 0;
2861 }
2862