On Wednesday, 31 January 2024 06:43:00 GMT Abyss Ether via devel wrote: > I created a simple PoC udev rule to mount USB Storage devices with the "sync > option. Available here : > https://github.com/larina3315/personal-stuff/blob/main/linux/10-usb-storage > .rules > Currently, USB Storage devices are mounted without the "sync" option, > causing their writes to be cached. This causes an issue, especially with > GUI file managers like GNOME Files, where after a file copy operation, it > would notify the user that the operation has been completed. If the user > then tries to unmount the USB Storage device, they get notified that data > is still being written to disk and that they should not remove the USB > Storage device from their PC/Laptop/device. > This can take a more severe form if the user is using a CLI/GUI utility that > DOES NOT inform the user that data is still being written, like the 'cp' > CLI utility, the user might be misled into thinking that all writes have > finished and plug the USB drive out, at which point data corruption due to > unfinished writes occur. > This is why, I think functionality should be included in Fedora Linux (or > atleast in Fedora Workstation and other desktop spins) such that USB > Storage devices are mounted with the "sync" options by default. -- Coming at the problem in a different direction; the kernel has options to limit how much data is in flight to any given device, but the Fedora system doesn't set these. See https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-class-bdi for documentation. As per the experiment documented below, if we set per- device BDI options "sensibly" based on the device's performance, we'd be able to reduce the window of surprise for users, without forcing all writes to be unbuffered via the "sync" option; instead, we could reduce the buffer to under a second for removable devices, and thus ensure that the user isn't surprised by massive data loss when they remove a device. As a nice side-effect, these changes would also speed up unmount operations from a GUI, since it limits the amount of dirty data to be written back before the unmount completes. The experiment follows: First, there's global settings: [sfarnsworth@ USB]$ sysctl vm | grep dirty sysctl: permission denied on key 'vm.mmap_rnd_bits' sysctl: permission denied on key 'vm.mmap_rnd_compat_bits' vm.dirty_background_bytes = 0 vm.dirty_background_ratio = 10 vm.dirty_bytes = 0 vm.dirty_expire_centisecs = 3000 vm.dirty_ratio = 20 vm.dirty_writeback_centisecs = 1500 vm.dirtytime_expire_seconds = 43200 sysctl: permission denied on key 'vm.stat_refresh' This tells me that on my system, we use up to 10% of my total RAM (64 GiB) as buffering for writes without even accessing the device, and up to 20% as buffering before the kernel will force a process to wait while it writes data out to the device. I just plugged a 4 GiB USB 2.0 stick into my machine, and I get the following values: [sfarnsworth@ /sys/class/bdi/8:0]$ grep . * max_bytes:7245996032 max_ratio:100 max_ratio_fine:1000000 min_bytes:0 min_ratio:0 min_ratio_fine:0 grep: power: Is a directory read_ahead_kb:128 stable_pages_required:0 strict_limit:0 This tells the kernel that it can buffer up to 7 GiB of data (max_bytes), and it doesn't need to consider the per-device limit until it's exhausted a global dirty limit (strict_limit). The default kernel settings allow you to complete your write immediately if you've used not more than 10% of the total buffer. If I tell dd to write a gigabyte to the device with the dsync flag set to ensure that it writes data to the device before returning (although not metadata), I can see that the kernel is permitted to buffer a huge amount of data in terms of time taken to write everything out: [sfarnsworth@ USB]$ dd if=/dev/zero of=test bs=$((1024 * 1024)) count=1024 oflag=dsync 1024+0 records in 1024+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 174.692 s, 6.1 MB/s I change the mount options to remove "flush", since this is a FAT32 stick, and the "flush" option causes the kernel to block on file close until the data is fully written: [sfarnsworth@USB]$ dd if=/dev/zero bs=$((1024 * 1024)) count=1024 of=test 1024+0 records in 1024+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 0.664286 s, 1.6 GB/s This means we've buffered (quite happily) 3 minutes worth of writeback, which I'd have to wait for before removing the stick - but dd has already exited, so it's not "obvious" to me that I need to wait a long time. I now change the per-device BDI options for the USB stick, based on what I've found out above: [root@ 8:0]# echo $((10 * 1024 * 1024)) > max_bytes [root@ 8:0]# echo 1 > strict_limit [root@8:0]# pwd && grep . * /sys/devices/virtual/bdi/8:0 max_bytes:10475956 max_ratio:0 max_ratio_fine:1485 min_bytes:0 min_ratio:0 min_ratio_fine:0 grep: power: Is a directory read_ahead_kb:128 stable_pages_required:0 strict_limit:1 grep: subsystem: Is a directory This time, when I repeat the "fast" dd, it doesn't exit until almost everything is written out: [sfarnsworth@ USB]$ dd if=/dev/zero bs=$((1024 * 1024)) count=1024 of=test 1024+0 records in 1024+0 records out 1073741824 bytes (1.1 GB, 1.0 GiB) copied, 163.928 s, 6.6 MB/s -- _______________________________________________ devel mailing list -- devel@xxxxxxxxxxxxxxxxxxxxxxx To unsubscribe send an email to devel-leave@xxxxxxxxxxxxxxxxxxxxxxx Fedora Code of Conduct: https://docs.fedoraproject.org/en-US/project/code-of-conduct/ List Guidelines: https://fedoraproject.org/wiki/Mailing_list_guidelines List Archives: https://lists.fedoraproject.org/archives/list/devel@xxxxxxxxxxxxxxxxxxxxxxx Do not reply to spam, report it: https://pagure.io/fedora-infrastructure/new_issue