[Bug 276002] nfscl: data corruption using both copy_file_range and mmap'd I/O

From: <bugzilla-noreply_at_freebsd.org>
Date: Mon, 01 Jan 2024 22:27:13 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=276002

--- Comment #38 from Konstantin Belousov <kib@FreeBSD.org> ---
(In reply to Rick Macklem from comment #34)
This sounds as an interesting theory, but please note that read-ahead
initiators
in nfs_clbio.c checks that the B_CACHE buffer flag is not set. This should
prevent
a situation where we have constructed buffer with valid (might be dirty) pages
but not valid content recorded at buf cache layer.

But lets recheck the theory anyway, the patch below should prevent RA when
there are writeable mappings:

commit 2234d9d4f7595a78bf10c08b1e6b12d2115799cd
Author: Konstantin Belousov <kib@FreeBSD.org>
Date:   Tue Jan 2 00:22:44 2024 +0200

    nfsclient: do not do (unlocked) read-ahead by nfsiod if there are writeable
mappings

diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c
index e6486af55daf..1f92fe0a4cf3 100644
--- a/sys/fs/nfsclient/nfs_clbio.c
+++ b/sys/fs/nfsclient/nfs_clbio.c
@@ -481,9 +481,13 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int ioflag,
struct ucred *cred)
                on = uio->uio_offset - (lbn * biosize);

                /*
-                * Start the read ahead(s), as required.
+                * Start the read ahead(s), as required.  Do not do
+                * read-ahead if there are writeable mappings, since
+                * unlocked read by nfsiod could obliterate changes
+                * done by userspace.
                 */
-               if (nmp->nm_readahead > 0) {
+               if (nmp->nm_readahead > 0 &&
+                   vp->v_object->un_pager.vnp.writemappings == 0) {
                    for (nra = 0; nra < nmp->nm_readahead && nra < seqcount &&
                        (off_t)(lbn + 1 + nra) * biosize < nsize; nra++) {
                        rabn = lbn + 1 + nra;
@@ -671,6 +675,7 @@ ncl_bioread(struct vnode *vp, struct uio *uio, int ioflag,
struct ucred *cred)
                 */
                NFSLOCKNODE(np);
                if (nmp->nm_readahead > 0 &&
+                   vp->v_object->un_pager.vnp.writemappings == 0 &&
                    (bp->b_flags & B_INVAL) == 0 &&
                    (np->n_direofoffset == 0 ||
                    (lbn + 1) * NFS_DIRBLKSIZ < np->n_direofoffset) &&

-- 
You are receiving this mail because:
You are the assignee for the bug.