Skip to content

Commit 921fd3e

Browse files
committed
Propose allowing unlink for LocalUnopened files
Files created but never opened (LocalUnopened) have no S3 state and can be unlinked. This prevents files from getting stuck in a state where they cannot be deleted. Signed-off-by: Maksim Beiner <maksim-beiner@idexx.com>
1 parent 8adc754 commit 921fd3e

File tree

1 file changed

+18
-2
lines changed

1 file changed

+18
-2
lines changed

mountpoint-s3-fs/src/superblock.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -614,11 +614,21 @@ impl<OC: ObjectClient + Send + Sync + Clone> Metablock for Superblock<OC> {
614614
};
615615

616616
match write_status {
617-
WriteStatus::LocalUnopened | WriteStatus::LocalOpen | WriteStatus::PendingRename => {
617+
// Safe to delete - no upload has started yet.
618+
WriteStatus::LocalUnopened => {
619+
debug!(
620+
parent = parent_ino,
621+
?name,
622+
"unlink on LocalUnopened file, no s3 cleanup needed",
623+
);
624+
}
625+
WriteStatus::LocalOpen | WriteStatus::PendingRename => {
626+
// Active upload in progress - cannot safely delete without cancellation logic.
618627
// In the future, we may permit `unlink` and cancel any in-flight uploads.
619628
warn!(
620629
parent = parent_ino,
621630
?name,
631+
?write_status,
622632
"unlink on local file not allowed until write is complete",
623633
);
624634
return Err(InodeError::UnlinkNotPermittedWhileWriting(inode.err()));
@@ -652,13 +662,19 @@ impl<OC: ObjectClient + Send + Sync + Clone> Metablock for Superblock<OC> {
652662
debug_assert!(false, "inodes never change kind");
653663
return Err(InodeError::NotADirectory(parent.err()));
654664
}
655-
InodeKindData::Directory { children, .. } => {
665+
InodeKindData::Directory {
666+
children,
667+
writing_children,
668+
..
669+
} => {
656670
// We want to remove the original child.
657671
// If there is a mismatch in inode number between the existing inode and the deleted inode, we invalidate the existing inode's stat.
658672
// If for some reason the child with the specified name was already removed, we do nothing as this is the desired state.
659673
if let Some(existing_inode) = children.get(inode.name()) {
660674
if existing_inode.ino() == inode.ino() {
661675
children.remove(inode.name());
676+
// Also clean up writing_children for local files in LocalUnopened state
677+
writing_children.remove(&inode.ino());
662678
} else {
663679
// Mismatch in inode number, thus the existing inode might not be the same one we deleted
664680
let mut state = existing_inode.get_mut_inode_state_no_check();

0 commit comments

Comments
 (0)