diff options
context:
space:
mode:
authorBryce Kwon <bryce@brycekwon.com>
committerBryce Kwon <bryce@brycekwon.com>
commit
parent
tree
download
Give up a scan or slot whose lock file was renamed
Diffstat (limited to 'source/cgit.c')
-rw-r--r--source/cgit.c13
1 file changed, 13 insertions, 0 deletions
diff --git a/source/cgit.c b/source/cgit.c
index 6644213..42325a0 100644
--- a/source/cgit.c
+++ b/source/cgit.c
@@ -350,6 +350,7 @@ static int generate_cached_repolist(const char *path, const char *cached_rc)
.l_start = 0,
.l_len = 0,
};
+ struct stat held, named;
int err = 0;
int fd;
int first;
@@ -370,6 +371,18 @@ static int generate_cached_repolist(const char *path, const char *cached_rc)
close(fd);
goto out;
}
+ // The lock landed on whatever inode the path named at open. A holder
+ // finishing in between renames that inode into place as the live
+ // list, so truncating it on the strength of the stale descriptor
+ // would tear down the list other requests are reading. Once the path
+ // is confirmed to still name this file the rename can no longer
+ // happen, because doing so takes the lock now held here.
+ if (fstat(fd, &held) || stat(locked_rc.buf, &named) ||
+ held.st_ino != named.st_ino || held.st_dev != named.st_dev) {
+ err = EAGAIN;
+ close(fd);
+ goto out;
+ }
// A run that died before its rename leaves the lock file behind, so
// start from empty now that nobody else can be writing it.
if (ftruncate(fd, 0) < 0 || !(f = fdopen(fd, "w"))) {