diff options
Diffstat (limited to 'source/cache.c')
| -rw-r--r-- | source/cache.c | 13 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1 file changed, 13 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) |
