diff options
| -rw-r--r-- | source/cache.c | 13 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| -rw-r--r-- | source/cgit.c | 13 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2 files changed, 26 insertions, 0 deletions
diff --git a/source/cache.c b/source/cache.c index 95275fb..682f225 100644 --- a/source/cache.c +++ b/source/cache.c @@ -224,6 +224,7 @@ static int lock_slot(struct cache_slot *slot) .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); @@ -235,6 +236,18 @@ static int lock_slot(struct cache_slot *slot) slot->lock_fd = -1; return saved_errno; } + // The lock landed on whatever inode the path named at open. A holder + // finishing in between renames that inode into place as the live + // slot, so truncating it on the strength of the stale descriptor + // would tear down the page 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(slot->lock_fd, &held) || stat(slot->lock_path, &named) || + held.st_ino != named.st_ino || held.st_dev != named.st_dev) { + close(slot->lock_fd); + slot->lock_fd = -1; + return EAGAIN; + } // 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(slot->lock_fd, 0) < 0) 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"))) { |
