mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-04 00:47:00 +01:00
fix(fuse,core): remediate audit bugs B23, B26-B29, B33 and update BUGS tracking
- B23: Generate synthetic StagedWrite sidecars in rescue_scratch when sidecar is corrupted - B26: Add open_count and unlinked state fields to defer node removal and cache eviction on unlinked open files until release - B27: Discard orphaned write revisions for local UIDs unlinked prior to upload - B28: Add emergency_evict to ContentCache for LRU blob eviction upon ENOSPC - B29: Implement FUSE forget handler and forget_lookup in state to prune unreferenced inodes - B33: Quarantine failing drain ops on HTTP 40x / max retries to unblock offline sync queue - docs: Track audit items B18-B36 in docs/BUGS.md with fix details and verification results
This commit is contained in:
1 parent
fe75998cea
commit
1cd6a26be3
5 files changed
+427
-38
No files matched your search
@@ -18,6 +18,9 @@ pub(crate) struct Entry {
|
||||
pub(crate) uid: NodeUid,
|
||||
pub(crate) parent: u64,
|
||||
pub(crate) node: Node,
|
||||
pub(crate) lookup_count: u64,
|
||||
pub(crate) open_count: u32,
|
||||
pub(crate) unlinked: bool,
|
||||
}
|
||||
|
||||
/// A set of non-overlapping `[start, end)` byte ranges, kept sorted and merged.
|
||||
@@ -194,11 +197,26 @@ impl State {
|
||||
uid: node.uid.clone(),
|
||||
parent,
|
||||
node,
|
||||
lookup_count: 1,
|
||||
open_count: 0,
|
||||
unlinked: false,
|
||||
},
|
||||
);
|
||||
ino
|
||||
}
|
||||
|
||||
/// Decrement lookup count for an inode and prune if lookup_count == 0 && open_count == 0 && unlinked.
|
||||
pub(crate) fn forget_lookup(&mut self, ino: u64, nlookup: u64) -> Option<(u64, String)> {
|
||||
if let Some(entry) = self.entries.get_mut(&ino) {
|
||||
entry.lookup_count = entry.lookup_count.saturating_sub(nlookup);
|
||||
if entry.lookup_count == 0 && entry.open_count == 0 && entry.unlinked {
|
||||
let uid = entry.uid.clone();
|
||||
return self.forget(&uid);
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Allocate (or reuse) a stable inode for a node that came *from* the
|
||||
/// database, which is why nothing is written back.
|
||||
pub(crate) fn intern_from_db(&mut self, parent: u64, node: Node) -> u64 {
|
||||
@@ -253,6 +271,22 @@ impl State {
|
||||
false
|
||||
}
|
||||
|
||||
/// Forget a node or, if open handles exist (open_count > 0), mark it unlinked
|
||||
/// and remove it from parent children so lookups fail while open reads succeed.
|
||||
pub(crate) fn forget_or_unlink(&mut self, uid: &NodeUid) -> Option<(u64, String)> {
|
||||
if let Some(&ino) = self.by_uid.get(uid)
|
||||
&& let Some(entry) = self.entries.get_mut(&ino)
|
||||
&& entry.open_count > 0
|
||||
{
|
||||
entry.unlinked = true;
|
||||
if let Some(kids) = self.children.get_mut(&entry.parent) {
|
||||
kids.retain(|&k| k != ino);
|
||||
}
|
||||
return Some((entry.parent, entry.node.name.clone()));
|
||||
}
|
||||
self.forget(uid)
|
||||
}
|
||||
|
||||
/// Forget a node entirely: drop its inode, its uid mapping, its own cached
|
||||
/// listing, its slot in its parent's listing, and its DB row. Returns
|
||||
/// `(parent_ino, name)` when the node was known, so the caller can notify
|
||||
|
||||
Reference in new issue
Block a user