Skip to content

Commit ae4a283

Browse files
mhaggergitster
authored andcommitted
rename_tmp_log(): handle a possible mkdir/rmdir race
If a directory vanishes while renaming the temporary reflog file, retry (up to 3 times). This could happen if another process deletes the directory created by safe_create_leading_directories() just before we rename the file into the directory. As far as I can tell, this race could not occur internal to git. The only time that a directory under $GIT_DIR/logs is deleted is if room has to be made for a log file for a reference with the same name; for example, in the following sequence: git branch foo/bar # Creates file .git/logs/refs/heads/foo/bar git branch -d foo/bar # Deletes file but leaves .git/logs/refs/heads/foo/ git branch foo # Deletes .git/logs/refs/heads/foo/ But the only reason the last command deletes the directory is because it wants to create a file with the same name. So if another process (e.g., git branch foo/baz ) wants to create that directory, one of the two is doomed to failure anyway because of a D/F conflict. Signed-off-by: Michael Haggerty <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent fa59ae7 commit ae4a283

File tree

1 file changed

+10
-1
lines changed

1 file changed

+10
-1
lines changed

refs.c

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2530,12 +2530,14 @@ int delete_ref(const char *refname, const unsigned char *sha1, int delopt)
25302530

25312531
static int rename_tmp_log(const char *newrefname)
25322532
{
2533+
int attempts_remaining = 3;
2534+
2535+
retry:
25332536
if (safe_create_leading_directories(git_path("logs/%s", newrefname))) {
25342537
error("unable to create directory for %s", newrefname);
25352538
return -1;
25362539
}
25372540

2538-
retry:
25392541
if (rename(git_path(TMP_RENAMED_LOG), git_path("logs/%s", newrefname))) {
25402542
if (errno==EISDIR || errno==ENOTDIR) {
25412543
/*
@@ -2548,6 +2550,13 @@ static int rename_tmp_log(const char *newrefname)
25482550
return -1;
25492551
}
25502552
goto retry;
2553+
} else if (errno == ENOENT && --attempts_remaining > 0) {
2554+
/*
2555+
* Maybe another process just deleted one of
2556+
* the directories in the path to newrefname.
2557+
* Try again from the beginning.
2558+
*/
2559+
goto retry;
25512560
} else {
25522561
error("unable to move logfile "TMP_RENAMED_LOG" to logs/%s: %s",
25532562
newrefname, strerror(errno));

0 commit comments

Comments
 (0)