From 3da770ce3557975660162793e00239ac91a7af68 Mon Sep 17 00:00:00 2001 From: Natanael Copa Date: Thu, 6 May 2021 12:22:55 +0200 Subject: [PATCH] abuild-fetch: simplify and fix locking Simplify locking by using lockf(3). It is POSIX compatible and should work over NFS. Fix download race condition when: 1) host A creates lockfile and aquire lock to fetch from distfiles mirror 2) host B opens the lockfile and waits for lock 3) host A gets 404 from distfiles, releases lock and deletes the lockfile, which host A has an open file handle for 4) host B gets lock of the deleted file and downloads file 5) host A retries download and creates a new lockfile, but is not blocked by host B, even if it should Solve this by releaseing the lock, give the other processes a chance to aquire it (using sleep(0)), and then only delete the lockfile if: a) download was successful (no 404) or b) no-one else has a lock. This reverts commit 281720ec39d4 (abuild-fetch: aquire a second lock using flock(2)) fixes #10026 --- abuild-fetch.c | 46 ++++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/abuild-fetch.c b/abuild-fetch.c index f7f0a08..18c0612 100644 --- a/abuild-fetch.c +++ b/abuild-fetch.c @@ -80,45 +80,26 @@ int fork_exec(char *argv[], int showerr) static int aquire_lock(const char *lockfile) { - struct flock fl = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 1, - .l_len = 0, - }; - int lockfd = open(lockfile, O_WRONLY|O_CREAT, 0660); if (lockfd < 0) err(1, "%s", lockfile); - /* create NFS-safe lock */ - if (fcntl(lockfd, F_SETLK, &fl) < 0) { - int i; - printf("Waiting for %s ...\n", lockfile); - for (i=0; i<10; i++) { - int r = fcntl(lockfd, F_SETLKW, &fl); - if (r == 0) - break; - if (r == -1 && errno != ESTALE) - err(1, "fcntl(F_SETLKW)"); - sleep(1); - } - } - - int r = flock(lockfd, LOCK_EX); - if (r == -1) - err(1, "flock: %s", lockfile); + if (lockf(lockfd, F_LOCK, 0) == -1) + err(1, "failed to aquire lock: %s", lockfile); return lockfd; } static void release_lock(int lockfd) { - int r = flock(lockfd, LOCK_UN); - if (r == -1) - err(1, "flock"); + if (lockf(lockfd, F_ULOCK, 0) == -1) + err(1, "failed to release lock"); - close(lockfd); +} + +static int try_lock(int lockfd) +{ + return lockf(lockfd, F_TLOCK, 0) == 0; } /* create or wait for an NFS-safe lockfile and fetch url with curl or wget */ @@ -197,9 +178,14 @@ int fetch(char *url, const char *destdir, bool insecure) rename(partfile, outfile); fetch_done: - unlink(lockfile); release_lock(lockfd); - lockfile[0] = '\0'; + + // give other processes the chance to aquire the lock if they have the file open + sleep(0); + + if (status == 0 || try_lock(lockfd)) + unlink(lockfile); + close(lockfd); return status; }