mirror_zfs/module
Jean-Sébastien Pédron 6f6e1c90ae FreeBSD: zfs_getpages: Don't zero freshly allocated pages
Initially, `zfs_getpages()` is provided with an array of busy pages by
the vnode pager. It then tries to acquire the range lock, but if there
is a concurrent `zfs_write()` running and fails to acquire that range
lock, it "unbusies" the pages to avoid a deadlock with `zfs_write()`.
After that, it grabs the pages again and retries to acquire the range
lock, and so on.

Once it got the range lock, it filters out valid pages, then copy DMU
data to the remaining invalid pages.

The problem is that freshly allocated zero'd pages it grabbed itself are
marked as valid. Therefore they are skipped by the second part of the
function and DMU data is never copied to these pages. This causes mapped
pages to contain zeros instead of the expected file content.

This was discovered while working on RabbitMQ on FreeBSD. I could
reproduce the problem easily with the following commands:

    git clone https://github.com/rabbitmq/rabbitmq-server.git
    cd rabbitmq-server/deps/rabbit

    gmake distclean-ct RABBITMQ_METADATA_STORE=mnesia \
      ct-amqp_client t=cluster_size_3:leader_transfer_stream_send

The testsuite fails because there is a sendfile(2) that can happen
concurrently to a write(2) on the same file. This leads to sendfile(2)
or read(2) (after the sendfile) sending/returning data with zeros, which
causes a function to crash.

The patch consists of not setting the `VM_ALLOC_ZERO` flag when
`zfs_getpages()` grabs pages again. Then, the last page is zero'd if it
is invalid, in case it would be partially filled with the end of the
file content. Other pages are either valid (and will be skipped) or they
will be entirely overwritten by the file content.

Reviewed-by: Alexander Motin <mav@FreeBSD.org>
Reviewed-by: Mark Johnston <markj@FreeBSD.org>
Signed-off-by: Jean-Sébastien Pédron <dumbbell@FreeBSD.org>
Closes #17851
2025-10-21 09:50:43 -07:00
..
avl Prefer VERIFY0P(n) over VERIFY(n == NULL) 2025-08-07 11:41:37 -07:00
icp sha256_generic: make internal functions a little more private 2025-10-21 09:50:43 -07:00
lua SPDX: license tags: MIT 2025-03-13 17:56:54 -07:00
nvpair Prefer VERIFY0P(n) over VERIFY3P(n, ==, NULL) 2025-08-07 11:41:42 -07:00
os FreeBSD: zfs_getpages: Don't zero freshly allocated pages 2025-10-21 09:50:43 -07:00
unicode SPDX: license tags: CDDL-1.0 2025-03-13 17:56:27 -07:00
zcommon Fix display of default xattr to show 'sa' 2025-10-21 09:50:43 -07:00
zfs Fix return value for setting zvol threading 2025-10-21 09:50:43 -07:00
zstd Silence zstd large allocation warning 2025-08-12 13:38:08 -07:00
.gitignore FreeBSD: Ignore symlink to i386 includes 2022-08-02 16:34:23 -07:00
Kbuild.in config: add and use KERNEL_CC check for -Wno-format-zero-length 2025-09-09 17:03:49 -07:00
Makefile.bsd Add TXG timestamp database 2025-08-06 10:31:21 -07:00
Makefile.in objtool wrapper: use absolute path to call the wrapper 2025-07-14 15:10:02 -07:00