Diff options
| author | Bryce Kwon <bryce@brycekwon.com> | |
|---|---|---|
| committer | Bryce Kwon <bryce@brycekwon.com> | |
| commit | ||
| parent | ||
| tree | ||
| download | ||
Lock the cached repolist with flock
The slot lock has to be an flock, since an exec filter drops a record
lock when it closes the stdout a fill writes through. The scan only got
by with fcntl because nothing reopens its file while it runs. One kind
of lock lets the two share their code, and on Linux, where the kinds
never see each other, an flock on the scan's file now holds a scan off
like any other.
Diffstat (limited to 'source')
| -rw-r--r-- | source/cgit.c | 13 |
1 file changed, 4 insertions, 9 deletions
diff --git a/source/cgit.c b/source/cgit.c index f5f3138..e98210f 100644 --- a/source/cgit.c +++ b/source/cgit.c @@ -27,6 +27,7 @@ #include "ui-shared.h" #include "ui-snapshot.h" #include "ui-stats.h" +#include <sys/file.h> // Deliberately small. The whole body is read at once and handed to the auth // filter, so a filter never has to defend itself against a huge or a @@ -317,19 +318,13 @@ static void parse_args(int argc, const char **argv) } /* - * The lock is a fcntl lock rather than the mere existence of the lock file, + * The lock is an flock rather than the mere existence of the lock file, * because a lock the kernel drops with its process cannot outlive a scan * killed mid-run. A leftover file would count as a scan forever in progress. */ static int generate_cached_repolist(const char *path, const char *cached_rc) { struct strbuf locked_rc = STRBUF_INIT; - struct flock lock = { - .l_type = F_WRLCK, - .l_whence = SEEK_SET, - .l_start = 0, - .l_len = 0, - }; struct stat held, named; int err = 0; int fd; @@ -343,13 +338,13 @@ static int generate_cached_repolist(const char *path, const char *cached_rc) fprintf(stderr, "[cgit] Unable to open %s: %s (%d)\n", locked_rc.buf, strerror(err), err); goto out; } - if (fcntl(fd, F_SETLK, &lock) < 0) { + if (flock(fd, LOCK_EX | LOCK_NB) < 0) { // A lock held elsewhere only means concurrent requests, which // is not worth a line in the server log. Any other failure, a // filesystem without lock support say, silently costs a scan // on every request and does deserve one. err = errno; - if (err != EACCES && err != EAGAIN) + if (err != EWOULDBLOCK) fprintf(stderr, "[cgit] Unable to lock %s: %s (%d)\n", locked_rc.buf, strerror(err), err); close(fd); goto out; |
