mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-04 00:47:00 +01:00
fix(fuse): never adopt a node another queued create is making
A file renamed away from a.txt while its create was on the wire, and a new a.txt made after it, could both land on the first file's node: the second create found a fresh, empty a.txt and took it for its own unanswered create. The first file's rename then carried the second one's bytes away. A create now leaves alone a node that another create is making under the same name, and one the tree already knows. It waits for the name like for any other queued change (docs/BUGS.md B147).
This commit is contained in:
1 parent
4eccdeeda6
commit
77d0f254fc
3 files changed
+40
No files matched your search
@@ -1160,6 +1160,19 @@ impl Core {
|
||||
parent: &NodeUid,
|
||||
name: &str,
|
||||
) -> Result<Option<NodeUid>, Box<dyn std::error::Error>> {
|
||||
// A second file queued under the same name, after the first was
|
||||
// renamed away, finds the first one's node fresh and empty while its
|
||||
// create is on the wire. Taking it put both files on one node, and the
|
||||
// first one's rename took the second one's bytes along
|
||||
// (docs/BUGS.md B147).
|
||||
let racing = self
|
||||
.creating
|
||||
.lock()
|
||||
.iter()
|
||||
.any(|(id, (p, n))| *id != op.id && p == parent && n == name);
|
||||
if racing {
|
||||
return Ok(None);
|
||||
}
|
||||
let uids = self
|
||||
.rt
|
||||
.block_on(self.drive.enumerate_folder_children_node_uids(parent))?;
|
||||
@@ -1170,6 +1183,12 @@ impl Core {
|
||||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
// A node in the tree was answered for, by this mount or by a listing:
|
||||
// the same race after the first create landed. Without the adoption,
|
||||
// an unanswered twin forks a conflict copy, which loses nothing.
|
||||
if self.state().by_uid.contains_key(&twin.uid) {
|
||||
return Ok(None);
|
||||
}
|
||||
// The light listing carries no file size, and an adoptable file is
|
||||
// exactly an empty one.
|
||||
let twin = match twin.kind {
|
||||
|
||||
@@ -12,6 +12,25 @@ Conventions:
|
||||
|
||||
---
|
||||
|
||||
## B147 — A new file made under a name just renamed away can share the first file's node
|
||||
|
||||
**Status:** Fixed (unverified).
|
||||
**Found:** 2026-10-04, by `sim::run::tests::three_clients_one_writer_each`, seed 2, in about one
|
||||
run of eight. Client 1 made `a.txt`, renamed it to `b.txt`, and made `a.txt` again. Drive ended
|
||||
up without `b.txt`, and `e.md`, a later rename of the new `a.txt`, held `b.txt`'s bytes.
|
||||
|
||||
**Where:** `Core::adoptable_twin` in `crates/pdfs-fuse/src/drain.rs`.
|
||||
|
||||
**Cause.** The first file's create went out as `a.txt` and the rename was queued behind it. While
|
||||
that create was on the wire, the second file's create found `a.txt` taken by a fresh, empty file,
|
||||
which is how the node of an unanswered create of its own looks, and adopted it. Both local files
|
||||
landed on the one node, and the first file's rename took it to `b.txt`.
|
||||
|
||||
**Fix.** A create no longer adopts a node another create is making under the same name and folder:
|
||||
it waits for that one to land, as for any name a queued change holds. Nor does it adopt a node
|
||||
already in the tree, which was answered for. An unanswered twin the tree has already listed
|
||||
lands as a conflict copy, which loses nothing.
|
||||
|
||||
## B146 — A file renamed just as its upload lands can go back to its old name
|
||||
|
||||
**Status:** Fixed (unverified).
|
||||
|
||||
@@ -44,6 +44,8 @@ are kept.
|
||||
A file made a moment before was taken for deleted and dropped from the queue (B145).
|
||||
- **A file renamed just as its upload lands keeps its new name.** The tree could take back the
|
||||
name Drive still had (B146).
|
||||
- **A new file made under a name another file just left no longer takes that file's place on
|
||||
Drive.** Both could land on one node, and one file's content was lost (B147).
|
||||
|
||||
## [2.10.0] — 2026-10-03
|
||||
|
||||
|
||||
Reference in new issue
Block a user