Instead of coding the retry loop inline, use raceproof_create_file() to make lock acquisition safe against directory creation/deletion races. Signed-off-by: Michael Haggerty <mhagger@xxxxxxxxxxxx> --- refs/files-backend.c | 47 +++++++++++++++++++---------------------------- 1 file changed, 19 insertions(+), 28 deletions(-) diff --git a/refs/files-backend.c b/refs/files-backend.c index b569762..a549942 100644 --- a/refs/files-backend.c +++ b/refs/files-backend.c @@ -1889,6 +1889,19 @@ static int remove_empty_directories(struct strbuf *path) return remove_dir_recursively(path, REMOVE_DIR_EMPTY_ONLY); } +struct create_reflock_data { + struct lock_file *lk; + int lflags; +}; + +static int create_reflock(const char *path, void *cb) +{ + struct create_reflock_data *data = cb; + + return hold_lock_file_for_update(data->lk, path, data->lflags) < 0 + ? -1 : 0; +} + /* * Locks a ref returning the lock on success and NULL on failure. * On failure errno is set to something meaningful. @@ -1906,10 +1919,9 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, struct ref_lock *lock; int last_errno = 0; int type; - int lflags = 0; int mustexist = (old_sha1 && !is_null_sha1(old_sha1)); int resolve_flags = 0; - int attempts_remaining = 3; + struct create_reflock_data create_reflock_data = {NULL, 0}; assert(err); @@ -1921,7 +1933,7 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, resolve_flags |= RESOLVE_REF_ALLOW_BAD_NAME; if (flags & REF_NODEREF) { resolve_flags |= RESOLVE_REF_NO_RECURSE; - lflags |= LOCK_NO_DEREF; + create_reflock_data.lflags |= LOCK_NO_DEREF; } refname = resolve_ref_unsafe(refname, resolve_flags, @@ -1980,35 +1992,14 @@ static struct ref_lock *lock_ref_sha1_basic(const char *refname, lock->orig_ref_name = xstrdup(orig_refname); strbuf_git_path(&ref_file, "%s", refname); - retry: - switch (safe_create_leading_directories_const(ref_file.buf)) { - case SCLD_OK: - break; /* success */ - case SCLD_VANISHED: - if (--attempts_remaining > 0) - goto retry; - /* fall through */ - default: + create_reflock_data.lk = lock->lk; + + if (raceproof_create_file(ref_file.buf, create_reflock, &create_reflock_data)) { last_errno = errno; - strbuf_addf(err, "unable to create directory for %s", - ref_file.buf); + unable_to_lock_message(ref_file.buf, errno, err); goto error_return; } - if (hold_lock_file_for_update(lock->lk, ref_file.buf, lflags) < 0) { - last_errno = errno; - if (errno == ENOENT && --attempts_remaining > 0) - /* - * Maybe somebody just deleted one of the - * directories leading to ref_file. Try - * again: - */ - goto retry; - else { - unable_to_lock_message(ref_file.buf, errno, err); - goto error_return; - } - } if (verify_lock(lock, old_sha1, mustexist, err)) { last_errno = errno; goto error_return; -- 2.7.0 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html