git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v2 08/20] log_ref_setup(): improve robustness against races

From
Michael Haggerty <mhagger@alum.mit.edu>
Date
Feb 25, 2016, 13:16 UTC
Message-ID
<2554cdb15206319537c694299f7c78238e7706b3.1456405699.git.mhagger@alum.mit.edu>
In-Reply-To
<cover.1456405698.git.mhagger@alum.mit.edu>

Change log_ref_setup() to use raceproof_create_file() to create the new logfile. This makes it more robust against a race against another process that might be trying to clean up empty directories while we are trying to create a new logfile.

This also means that it will only call create_leading_directories() if open() fails, which should be a net win. Even in the cases where we are willing to create a new logfile, it will usually be the case that the logfile already exists, or if not then that the directory containing the logfile already exists. In such cases, we will save some work that was previously done unconditionally.

Signed-off-by: Michael Haggerty <mhagger@alum.mit.edu>
---
 refs/files-backend.c | 46 +++++++++++++++++++++-------------------------
 1 file changed, 21 insertions(+), 25 deletions(-)
diff --git a/refs/files-backend.c b/refs/files-backend.c
index 8fff1a8..2cc9489 100644
--- a/refs/files-backend.c
+++ b/refs/files-backend.c
@@ -2582,6 +2582,14 @@ static int commit_ref(struct ref_lock *lock)
 	return 0;
 }
 
+static int open_or_create_logfile(const char *path, void *cb)
+{
+	int *fd = cb;
+
+	*fd = open(path, O_APPEND | O_WRONLY | O_CREAT, 0666);
+	return (*fd < 0) ? -1 : 0;
+}
+
 /*
  * Create a reflog for a ref.  If force_create = 0, the reflog will
  * only be created for certain refs (those for which
@@ -2593,36 +2601,24 @@ static int log_ref_setup(const char *refname, struct strbuf *logfile, struct str
 	int logfd;
 
 	strbuf_git_path(logfile, "logs/%s", refname);
+
 	if (force_create || should_autocreate_reflog(refname)) {
-		if (safe_create_leading_directories(logfile->buf) < 0) {
-			strbuf_addf(err, "unable to create directory for %s: "
-				    "%s", logfile->buf, strerror(errno));
-			return -1;
-		}
-		logfd = open(logfile->buf, O_APPEND | O_WRONLY | O_CREAT, 0666);
-		if (logfd < 0) {
-			if (errno == EISDIR) {
-				/*
-				 * The directory that is in the way might be
-				 * empty. Try to remove it.
-				 */
-				if (remove_empty_directories(logfile)) {
-					strbuf_addf(err, "There are still logs under "
-						    "'%s'", logfile->buf);
-					return -1;
-				}
-				logfd = open(logfile->buf, O_APPEND | O_WRONLY | O_CREAT, 0666);
-			}
-
-			if (logfd < 0) {
+		if (raceproof_create_file(logfile->buf, open_or_create_logfile, &logfd) < 0) {
+			if (errno == ENOENT) {
+				strbuf_addf(err, "unable to create directory for %s: "
+					    "%s", logfile->buf, strerror(errno));
+			} else if (errno == EISDIR) {
+				strbuf_addf(err, "there are still logs under %s",
+					    logfile->buf);
+			} else {
 				strbuf_addf(err, "unable to append to %s: %s",
 					    logfile->buf, strerror(errno));
-				return -1;
 			}
+			return -1;
+		} else {
+			adjust_shared_perm(logfile->buf);
+			close(logfd);
 		}
-
-		adjust_shared_perm(logfile->buf);
-		close(logfd);
 	} else {
 		logfd = open(logfile->buf, O_APPEND | O_WRONLY, 0666);
 		if (logfd < 0) {
-- 
2.7.0
Previous: Michael HaggertyNext: Michael Haggerty
Message 9 of 21 in “Delete directories left empty after ref deletion”
  1. 00/20 Delete directories left empty after ref deletionMichael Haggerty, Feb 25, 2016
  2. 01/20 safe_create_leading_directories_const(): preserve errnoMichael Haggerty, Feb 25, 2016
  3. 02/20 safe_create_leading_directories(): set errno on SCLD_EXISTSMichael Haggerty, Feb 25, 2016
  4. 03/20 raceproof_create_file(): new functionMichael Haggerty, Feb 25, 2016
  5. 04/20 lock_ref_sha1_basic(): use raceproof_create_file()Michael Haggerty, Feb 25, 2016
  6. 05/20 rename_tmp_log(): use raceproof_create_file()Michael Haggerty, Feb 25, 2016
  7. 06/20 rename_tmp_log(): improve error reportingMichael Haggerty, Feb 25, 2016
  8. 07/20 log_ref_setup(): separate code for create vs non-createMichael Haggerty, Feb 25, 2016
  9. 08/20 log_ref_setup(): improve robustness against racesMichael Haggerty, Feb 25, 2016
  10. 09/20 log_ref_setup(): pass the open file descriptor back to the callerMichael Haggerty, Feb 25, 2016
  11. 10/20 log_ref_write_1(): don't depend on logfileMichael Haggerty, Feb 25, 2016
  12. 11/20 log_ref_setup(): manage the name of the reflog file internallyMichael Haggerty, Feb 25, 2016
  13. 12/20 log_ref_write_1(): inline functionMichael Haggerty, Feb 25, 2016
  14. 13/20 try_remove_empty_parents(): rename parameter "name" -> "refname"Michael Haggerty, Feb 25, 2016
  15. 14/20 try_remove_empty_parents(): don't trash argument contentsMichael Haggerty, Feb 25, 2016
  16. 15/20 try_remove_empty_parents(): don't accommodate consecutive slashesMichael Haggerty, Feb 25, 2016
  17. 16/20 t5505: use "for-each-ref" to test for the non-existence of referencesMichael Haggerty, Feb 25, 2016
  18. 17/20 delete_ref_loose(): derive loose reference path from lockMichael Haggerty, Feb 25, 2016
  19. 18/20 delete_ref_loose(): inline functionMichael Haggerty, Feb 25, 2016
  20. 19/20 try_remove_empty_parents(): teach to remove parents of reflogs, tooMichael Haggerty, Feb 25, 2016
  21. 20/20 ref_transaction_commit(): clean up empty directoriesMichael Haggerty, Feb 25, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.