From ea388696e9992dbc8cd0876a06a81f4ce67238cd Mon Sep 17 00:00:00 2001 From: Bryce Kwon Date: Sun, 23 Aug 2026 17:50:41 -1000 Subject: Give up a scan or slot whose lock file was renamed --- source/cache.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'source/cache.c') 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) -- cgit v2.8.0