mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-03 16:41:26 +01:00
fix(fuse): download the base of a file open for writing on a worker
A read on a write handle was answered on the dispatch loop to keep its order with the handle's writes, and when the bytes it asked for were neither written nor cached it downloaded them there, holding every request of the mount for up to the read deadline. The loop now answers from the scratch file and the local caches only, and hands a read that needs a download to a transfer worker with the handle as it was when the read came in (B227).
This commit is contained in:
1 parent
f8c60c9753
commit
d4ef9116c8
3 files changed
+203
-63
No files matched your search
+53
-26
@@ -100,10 +100,11 @@ a live account since.
|
||||
|
||||
| Entry | Title |
|
||||
|---|---|
|
||||
| [B227](#b227--reading-a-file-open-for-writing-downloads-on-the-dispatch-loop) | Reading a file open for writing downloads on the dispatch loop |
|
||||
| [B226](#b226--thumbnails-of-portrait-phone-photos-lie-on-their-side) | Thumbnails of portrait phone photos lie on their side |
|
||||
| [B225](#b225--a-takeout-photo-without-a-sidecar-takes-a-siblings-name-and-date) | A Takeout photo without a sidecar takes a sibling's name and date |
|
||||
| [B223](#b223--a-damaged-config-file-is-replaced-with-defaults-on-the-next-settings-change) | A damaged config file is replaced with defaults on the next settings change |
|
||||
| [B224](#b224--fallocate-zero-ranges-are-undone-and-collapse-ranges-corrupt-the-file) | `fallocate` zero ranges are undone and collapse ranges corrupt the file |
|
||||
| [B223](#b223--a-damaged-config-file-is-replaced-with-defaults-on-the-next-settings-change) | A damaged config file is replaced with defaults on the next settings change |
|
||||
| [B222](#b222--a-full-disk-at-close-is-reported-to-nobody-and-fsync-on-a-read-only-file-fails) | A full disk at close is reported to nobody, and `fsync` on a read-only file fails |
|
||||
| [B221](#b221--a-cold-listing-holds-the-global-lock-across-a-database-transaction) | A cold listing holds the global lock across a database transaction |
|
||||
| [B220](#b220--thumbnails-on-a-stalled-link-hold-up-every-other-request) | Thumbnails on a stalled link hold up every other request |
|
||||
@@ -329,6 +330,32 @@ a live account since.
|
||||
|
||||
Newest first.
|
||||
|
||||
### B227 — Reading a file open for writing downloads on the dispatch loop
|
||||
|
||||
**Status:** Fixed, not verified live
|
||||
**Found:** 2026-10-16, architecture audit (`FINDINGS.md` 2.1.2).
|
||||
**Where:** `read` in `crates/pdfs-fuse/src/filesystem.rs`; `Core::serve_open_read_local` and
|
||||
`assemble_open_read` in `crates/pdfs-fuse/src/reads.rs`
|
||||
|
||||
**Repro:** On a slow link, open a large file that is only on Drive with `O_RDWR`, write a few
|
||||
bytes, and read elsewhere in it, as SQLite and many editors do, while another program uses the
|
||||
mount.
|
||||
|
||||
**Cause.** A read on a file open for writing was always answered on the dispatch loop, so that it
|
||||
kept its order with the writes on the same handle. When the bytes it asked for were neither
|
||||
written nor cached, it downloaded them there, for up to the 120 s read deadline plus the wait
|
||||
for a connection. Every other request of the mount waited behind it.
|
||||
|
||||
**Fix.** The dispatch loop answers such a read from the scratch file and the local caches only.
|
||||
When a range of the base would have to be downloaded, the read goes to a transfer worker, with
|
||||
the handle as it was when the read came in. The kernel issued the read before any later write,
|
||||
so that is the content it asked for.
|
||||
|
||||
**Test:** `reads::open_read_tests::a_read_needing_the_base_says_so_instead_of_fetching`; the
|
||||
simulation runs cover the order of writes and reads on one handle.
|
||||
|
||||
---
|
||||
|
||||
### B226 — Thumbnails of portrait phone photos lie on their side
|
||||
|
||||
**Status:** Fixed, not verified live
|
||||
@@ -379,31 +406,6 @@ by its own rule. It takes the capture time from that sidecar and keeps its own n
|
||||
|
||||
---
|
||||
|
||||
### B223 — A damaged config file is replaced with defaults on the next settings change
|
||||
|
||||
**Status:** Fixed, not verified live
|
||||
**Found:** 2026-10-16, architecture audit (`FINDINGS.md` 1.10).
|
||||
**Where:** `AppDirs::save_config`, `AppDirs::load_config` and `refuse_to_replace_unreadable` in
|
||||
`crates/pdfs-core/src/config.rs`
|
||||
|
||||
**Repro:** Truncate `~/.config/proton-drive-linux/config.json`, then change any setting in the
|
||||
app, or let the daemon record its device.
|
||||
|
||||
**Cause.** `load_config` gives defaults for a file it cannot parse, and logs that it leaves the
|
||||
file alone. But every setter loads, changes one field and saves, in the daemon and in the app.
|
||||
So the first change after the damage wrote the defaults over the file, losing the mountpoint,
|
||||
the device the client had adopted, the ignore rules and the `open_with` choices. ARCHITECTURE
|
||||
§10.5 says the file is never replaced with defaults. The first-run default was also written with a
|
||||
plain `std::fs::write`, which is not atomic and takes the umask's mode.
|
||||
|
||||
**Fix.** `save_config` refuses while the file on disk exists and does not parse, and says which
|
||||
file to fix. The first-run default goes through `save_config`, so it is written atomically with
|
||||
mode 0600.
|
||||
|
||||
**Test:** `config::tests::an_unreadable_config_is_never_written_over`.
|
||||
|
||||
---
|
||||
|
||||
### B224 — `fallocate` zero ranges are undone and collapse ranges corrupt the file
|
||||
|
||||
**Status:** Fixed, not verified live
|
||||
@@ -431,6 +433,31 @@ the lock is not held across it.
|
||||
|
||||
---
|
||||
|
||||
### B223 — A damaged config file is replaced with defaults on the next settings change
|
||||
|
||||
**Status:** Fixed, not verified live
|
||||
**Found:** 2026-10-16, architecture audit (`FINDINGS.md` 1.10).
|
||||
**Where:** `AppDirs::save_config`, `AppDirs::load_config` and `refuse_to_replace_unreadable` in
|
||||
`crates/pdfs-core/src/config.rs`
|
||||
|
||||
**Repro:** Truncate `~/.config/proton-drive-linux/config.json`, then change any setting in the
|
||||
app, or let the daemon record its device.
|
||||
|
||||
**Cause.** `load_config` gives defaults for a file it cannot parse, and logs that it leaves the
|
||||
file alone. But every setter loads, changes one field and saves, in the daemon and in the app.
|
||||
So the first change after the damage wrote the defaults over the file, losing the mountpoint,
|
||||
the device the client had adopted, the ignore rules and the `open_with` choices. ARCHITECTURE
|
||||
§10.5 says the file is never replaced with defaults. The first-run default was also written with a
|
||||
plain `std::fs::write`, which is not atomic and takes the umask's mode.
|
||||
|
||||
**Fix.** `save_config` refuses while the file on disk exists and does not parse, and says which
|
||||
file to fix. The first-run default goes through `save_config`, so it is written atomically with
|
||||
mode 0600.
|
||||
|
||||
**Test:** `config::tests::an_unreadable_config_is_never_written_over`.
|
||||
|
||||
---
|
||||
|
||||
### B222 — A full disk at close is reported to nobody, and `fsync` on a read-only file fails
|
||||
|
||||
**Status:** Fixed, not verified live
|
||||
|
||||
Reference in new issue
Block a user