[PATCH 04/20] lock_ref_sha1_basic(): use raceproof_create_file()
From: Michael Haggerty <hidden>
Date: 2016-06-15 23:08:16
Subsystem:
the rest · Maintainer:
Linus Torvalds
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 <redacted> --- 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