From f4327cc6a0f3fb0df9de52d03d8f0384d10c264c Mon Sep 17 00:00:00 2001 From: Colin Walters Date: Tue, 30 Apr 2013 19:34:20 -0400 Subject: [PATCH] repo: Fix race condition in async checkout When multiple threads need to uncompress an object, there was a race condition where thread A could get EEXIST, unlink, then thread B calls linkat(), then thread A tries to link() but fails. We can just loop in this case. --- src/libostree/ostree-repo.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/libostree/ostree-repo.c b/src/libostree/ostree-repo.c index e793875b..f4ad8fe4 100644 --- a/src/libostree/ostree-repo.c +++ b/src/libostree/ostree-repo.c @@ -3194,6 +3194,7 @@ checkout_file_hardlink (OstreeRepo *self, gboolean ret_was_supported = FALSE; ot_lobj GFile *dir = NULL; + again: if (dirfd != -1 && linkat (-1, gs_file_get_path_cached (source), dirfd, gs_file_get_basename_cached (destination), 0) != -1) @@ -3218,11 +3219,7 @@ checkout_file_hardlink (OstreeRepo *self, * So we can't make this atomic. */ (void) unlink (gs_file_get_path_cached (destination)); - if (link (gs_file_get_path_cached (source), gs_file_get_path_cached (destination)) < 0) - { - ot_util_set_error_from_errno (error, errno); - goto out; - } + goto again; ret_was_supported = TRUE; } else