Bind prepared artifact selection against reclaim

This commit is contained in:
ms2k 2026-07-22 01:51:46 +09:00
commit 1bd1d395d9

View file

@ -351,6 +351,13 @@ pub fn try_exclusive_flock(file: File) -> io::Result<ExclusiveFileLock> {
Ok(ExclusiveFileLock(file))
}
/// # Errors
/// Returns an error when the nonblocking shared lock is unavailable.
pub fn try_shared_flock(file: File) -> io::Result<SharedFileLock> {
flock(file.as_fd(), FlockOperation::NonBlockingLockShared)?;
Ok(SharedFileLock(file))
}
#[derive(Debug)]
pub struct ExclusiveFileLock(File);
@ -360,6 +367,15 @@ impl AsFd for ExclusiveFileLock {
}
}
#[derive(Debug)]
pub struct SharedFileLock(File);
impl AsFd for SharedFileLock {
fn as_fd(&self) -> std::os::fd::BorrowedFd<'_> {
self.0.as_fd()
}
}
/// # Errors
/// Returns an error unless the replacement and containing directory are synced.
pub fn atomic_replace(path: &Path, bytes: &[u8]) -> io::Result<()> {
@ -459,7 +475,7 @@ pub fn require_mount_identity(path: &Path, expected: MountIdentity) -> io::Resul
#[cfg(test)]
mod tests {
use std::fs::OpenOptions;
use std::fs::{File, OpenOptions};
use std::io::{Read, Write};
use std::os::unix::fs::symlink;
@ -468,6 +484,7 @@ mod tests {
use super::{
RegularFileMailbox, atomic_replace, current_mount_identity, namespace_identity,
require_mount_identity, require_write_sealed, sealed_memfd, try_exclusive_flock,
try_shared_flock,
};
fn test_directory(name: &str) -> std::path::PathBuf {
@ -552,6 +569,21 @@ mod tests {
std::fs::remove_dir_all(directory).unwrap();
}
#[test]
fn shared_flock_excludes_reclaim_until_every_claim_closes() {
let directory = test_directory("shared-flock");
let path = directory.join("artifact");
std::fs::create_dir(&path).unwrap();
let first = try_shared_flock(File::open(&path).unwrap()).unwrap();
let second = try_shared_flock(File::open(&path).unwrap()).unwrap();
assert!(try_exclusive_flock(File::open(&path).unwrap()).is_err());
drop(first);
assert!(try_exclusive_flock(File::open(&path).unwrap()).is_err());
drop(second);
assert!(try_exclusive_flock(File::open(&path).unwrap()).is_ok());
std::fs::remove_dir_all(directory).unwrap();
}
#[test]
fn namespace_identity_is_stable_for_same_namespace() {
let first = namespace_identity(std::path::Path::new("/proc/self/ns/mnt")).unwrap();