Re: [PATCH 2/2] object-file: retry linking file into place when occluding file vanishes

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Fri, Jan 03, 2025 at 02:40:58PM -0500, Jeff King wrote:

> I suspect there's a way to write this as a loop that would be more
> structured, but it would be a bigger refactor. Bonus points if it also
> get rid of the try_rename goto, too. ;)
> 
> I'm OK punting on that, though.

For fun, here's a version without any goto's in it, that should behave
the same. But it would be very easy to miss a case. So I don't know if
it is worth the regression risk, and I don't blame you if you delete
this message without looking carefully. ;)

Diff is kind of hard to read, so you may want to apply (on top of your
patches) and just look at the post-image.

diff --git a/object-file.c b/object-file.c
index 88432cc9c0..923d75a889 100644
--- a/object-file.c
+++ b/object-file.c
@@ -2037,58 +2037,66 @@ int finalize_object_file(const char *tmpfile, const char *filename)
 int finalize_object_file_flags(const char *tmpfile, const char *filename,
 			       enum finalize_object_file_flags flags)
 {
-	int ret;
+	int tries = 5;
 
-retry:
-	ret = 0;
+	while (tries-- > 0) {
+		int ret = 0;
+		if (object_creation_mode != OBJECT_CREATION_USES_RENAMES) {
+			if (!link(tmpfile, filename)) {
+				unlink_or_warn(tmpfile);
+				break;
+			}
+			ret = errno;
+		}
 
-	if (object_creation_mode == OBJECT_CREATION_USES_RENAMES)
-		goto try_rename;
-	else if (link(tmpfile, filename))
-		ret = errno;
-	else
-		unlink_or_warn(tmpfile);
+		/*
+		 * Coda hack - coda doesn't like cross-directory links,
+		 * so we fall back to a rename, which will mean that it
+		 * won't be able to check collisions, but that's not a
+		 * big deal.
+		 *
+		 * The same holds for FAT formatted media.
+		 *
+		 * When this succeeds, we just return.  We have nothing
+		 * left to unlink.
+		 */
+		if (!ret || ret == EEXIST) {
+			struct stat st;
 
-	/*
-	 * Coda hack - coda doesn't like cross-directory links,
-	 * so we fall back to a rename, which will mean that it
-	 * won't be able to check collisions, but that's not a
-	 * big deal.
-	 *
-	 * The same holds for FAT formatted media.
-	 *
-	 * When this succeeds, we just return.  We have nothing
-	 * left to unlink.
-	 */
-	if (ret && ret != EEXIST) {
-		struct stat st;
+			if (!stat(filename, &st))
+				ret = EEXIST;
+			else if (!rename(tmpfile, filename))
+				break;
+			else
+				ret = errno;
+		}
 
-	try_rename:
-		if (!stat(filename, &st))
-			ret = EEXIST;
-		else if (!rename(tmpfile, filename))
-			goto out;
-		else
-			ret = errno;
-	}
-	if (ret) {
+		/* Do not retry most filesystem errors */
 		if (ret != EEXIST) {
 			int saved_errno = errno;
 			unlink_or_warn(tmpfile);
 			errno = saved_errno;
 			return error_errno(_("unable to write file %s"), filename);
 		}
-		if (!(flags & FOF_SKIP_COLLISION_CHECK)) {
-			ret = check_collision(tmpfile, filename);
-			if (ret == CHECK_COLLISION_DEST_VANISHED)
-				goto retry;
-			else if (ret)
-				return -1;
+
+		ret = (flags & FOF_SKIP_COLLISION_CHECK) ? 0 :
+			check_collision(tmpfile, filename);
+
+		if (!ret) {
+			/* Same contents (or we are allowed to assume such). */
+			unlink_or_warn(tmpfile);
+			break;
 		}
-		unlink_or_warn(tmpfile);
+
+		if (ret != CHECK_COLLISION_DEST_VANISHED)
+			return -1; /* check_collision() already complained */
+
+		/* loop again to retry vanished destination */
 	}
 
-out:
+	if (tries < 0)
+		return error(_("unable to write repeatedly vanishing file %s"), filename);
+
 	if (adjust_shared_perm(filename))
 		return error(_("unable to set permission to '%s'"), filename);
 	return 0;

-Peff




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux