diff options
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Lock a cache slot with flock
The slot lock was a POSIX record lock, which a process loses the moment any descriptor on the file closes, and the fill puts the lock file on stdout, which every exec filter and snapshot compressor closes with its dup2. A second request on the slot could then rebuild it under the first and splice the two pages. An flock holds until the last descriptor goes.
Diffstat (limited to 'source')
-rw-r--r--source/cache.c13
1 file changed, 6 insertions, 7 deletions
diff --git a/source/cache.c b/source/cache.c
index 82b3aad..9594fd6 100644
--- a/source/cache.c
+++ b/source/cache.c
@@ -13,6 +13,7 @@
#include "cgit.h"
#include "html.h"
#include "shared.h"
+#include <sys/file.h>
#ifdef HAVE_LINUX_SENDFILE
#include <sys/sendfile.h>
#endif
@@ -232,18 +233,16 @@ static int close_lock(struct cache_slot *slot)
*/
static int lock_slot(struct cache_slot *slot)
{
- struct flock lock = {
- .l_type = F_WRLCK,
- .l_whence = SEEK_SET,
- .l_start = 0,
- .l_len = 0,
- };
struct stat held, named;
slot->lock_fd = open(slot->lock_path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
if (slot->lock_fd == -1)
return errno;
- if (fcntl(slot->lock_fd, F_SETLK, &lock) < 0) {
+ // An flock rather than a POSIX record lock. The descriptor is put on
+ // stdout for the fill, and a record lock is dropped as soon as any
+ // descriptor on the file closes, which an exec filter does to stdout,
+ // while an flock holds until the last descriptor closes.
+ if (flock(slot->lock_fd, LOCK_EX | LOCK_NB) < 0) {
int saved_errno = errno;
close(slot->lock_fd);
slot->lock_fd = -1;