mirror of
https://github.com/uutils/coreutils.git
synced 2026-10-16 02:48:27 -07:00
The read scratch had no alignment guarantee beyond `align_of::<u8>() == 1`. Block devices that enforce a strict `dma_alignment` (e.g. `sd`, `loop`, `virtio_blk`, `nbd`, `zram`, which all default to 511) reject O_DIRECT reads whose user buffer is below that alignment with EINVAL. Wrap the read scratch in `AlignedBuf`, which over-allocates the zeroed buffer from `alloc_copy_buffer` by one 4 KiB alignment unit and slices at the first aligned byte, so the pages still arrive zeroed from the kernel and are not faulted in before the first read. No `unsafe` involved. `fill_consecutive` and `fill_blocks` now take `&mut [u8]` and report the buffer length (read bytes for the former; reads + padding for the latter) so the caller can slice without `Vec::truncate`. `read_helper` returns the data slice directly: into `read_buf` for the common path, or into a separate `Vec` scratch for `conv=block` / `conv=unblock`, which can change the byte count and so cannot be done in place. This also removes the truncate-and-regrow cycle that used to re-fault the buffer after a short read. Taken over from #12143 by Christoph Böhmwalder: rebased, storage switched from `#[repr(align)]` pages to over-allocate-and-offset on top of `alloc_copy_buffer`, and unit tests for `AlignedBuf` plus an integration test reading a regular file with `iflag=direct` added. Closes #12143. Closes #12085. Fixes https://bugs.launchpad.net/ubuntu/+source/rust-coreutils/+bug/2125968