Document Linux USB mount-option workaround for OSError after Ctrl-D (#229)#491
Conversation
On Linux, the default vfat mount options for the CIRCUITPY USB MSC drive defer writes via the kernel page cache. When CircuitPython is soft-rebooted (Ctrl-D) immediately after a save, the device may see an inconsistent filesystem and report OSError: [Errno 5] Input/output error. This is a host-OS behavior, not a web-editor or firmware bug. macOS and Windows are unaffected. Network and Bluetooth workflows are also unaffected. Changes: - Add isLinux() helper in js/common/utilities.js (excludes Chrome OS and Android to avoid false positives). - Add a collapsible Linux-only notice in the USB connect dialog that surfaces the udisksctl remount commands. - Add docs/LINUX_USB_MOUNT.md with full guidance, including a permanent udev rule using ID_FS_LABEL='CIRCUITPY' and UDISKS_MOUNT_OPTIONS+='sync'. No code changes to the FSAPI client or REPL-based read-only fallback path (circuitpython#327 behavior preserved). Fixes circuitpython#229.
|
@makermelissa I am not sure this is a great long-term solution, because it is a big deal for the user to add the udev rule, etc. On Chromebooks, it is impossible for the average user. The problem is more that the "File System Access API" doesn't provide an fsync, and we should lobby for that., I spent years making sure various editors do fsync's after file write: https://learn.adafruit.com/welcome-to-circuitpython/recommended-editors, https://github.com/adafruit/Atom-fsync-on-save, etc. Since there is a mechanism in the web editor now for doing file edits through the REPL for boards that don't present CIRCUITPY, would an alternative be to detect the editor is running on Linux, and revert to REPL-based file writes? |
|
The REPL based idea is worth exploring. It would require the user to eject the Circuit Python drive so it's not read only, but that's definitely a simpler solution. I'm out of hours this week, but I'll see if we can revert and take that approach instead. |
|
Another option is possibly to just ignore the error. The writes do happen immediately and I discovered that waiting 30 seconds before reloading avoided the error altogether. |
Fixes #229.
What
On Linux, the default
vfatmount options for the CIRCUITPY USB MSC drive defer writes via the kernel page cache. When CircuitPython is soft-rebooted (Ctrl+D) immediately after a save from the web editor, the device may see an inconsistent filesystem and report:This is a host-OS behavior, not a web-editor or firmware bug. macOS and Windows are unaffected. Network and Bluetooth workflows are also unaffected — only the USB workflow on Linux.
Why this approach
I spent a fair bit of time exploring code-side workarounds (
createWritable({mode: "exclusive"}), post-write file re-open, REPL nudges, warm-up flushes, etc.). None of them were reliably fixing the bug — the writes really are sitting in the host kernel page cache for up to ~30 s, and the browser File System Access API does not expose any way to forcefsync(). Verified empirically: remounting CIRCUITPY with-o syncmakes the bug disappear in 3/3 trials. Restoring the default mount brings it back.So instead of a fragile JS workaround, this PR documents the host-OS fix and surfaces it at the right moment — when a Linux user is opening the USB connect dialog.
Changes
js/common/utilities.js: addisLinux()helper. Usesnavigator.userAgentData.platformfirst (modern Chromium) and falls back touserAgent, explicitly excluding Chrome OS and Android to avoid false positives.index.html: add a collapsed<details>notice in the USB connect dialog's "Select USB Host Folder" step. Hidden by default; shown only whenisLinux()is true.js/workflows/usb.js: inshowConnect(), query the notice element and toggle itshiddenattribute based onisLinux().sass/layout/_layout.scss: styling for the notice — soft-yellow info box with code-block formatting and a custom disclosure triangle.docs/LINUX_USB_MOUNT.md: full guidance document covering:udisksctl unmount+udisksctl mount -o sync)udevrule usingENV{ID_FS_LABEL}=="CIRCUITPY"andUDISKS_MOUNT_OPTIONS+="sync")What this PR does not change
js/common/fsapi-file-transfer.js— kept pristine.Verification
mount -o sync→ no OSError in 3/3 trials.npm run build).isLinux()is true; hidden when false.