FBSD: Invalidate pages after non-VM write 66/14166/6
authorAndrew Deason <adeason@dson.org>
Mon, 27 Apr 2020 19:47:08 +0000 (14:47 -0500)
committerBenjamin Kaduk <kaduk@mit.edu>
Sun, 19 Sep 2021 01:41:21 +0000 (21:41 -0400)
Our VOP_WRITE implementation causes the given data to be written to
the libafs cache, and potentially to the fileserver, but does not
update pages mapped to our vnode. This can cause file data to appear
out-of-date if otherwise valid pages exist for that range.

As a practical example of this, when running 'make buildworld' in
/afs, we run:

cc -nostdlib -Wl,-dc -r -o ipf.lo ipf_stub.o [...]
    crunchide -k _crunched_ipf_stub ipf.lo

The first 'cc' command generates ipf.lo by writing to an mmap'd
region, and the second 'crunchide' command rewrites that file using
write() syscalls.

Afterwards, anything that reads from ipf.lo using mmap'd memory will
see the ipf.lo that 'cc' generated; anything that reads using read()
syscalls will see the updated version from 'crunchide'. And of course
if the pages are evicted for any other reason (such as memory
pressure), everything will see the updated version from 'crunchide'.

The eventual error seen during 'make buildworld' involves duplicate
symbols during linking, since 'crunchide' modifies most symbols to be
hidden. For example:

cc [...] -static -o rescue rescue.o cat.lo [...] ipf.lo [...]
    ld: error: duplicate symbol: main
    >>> defined at rescue.c
    >>>            rescue.o:(main)
    >>> defined at count4bits.c
    >>>            ipf.lo:(.text+0x10)

    ld: error: duplicate symbol: main
    >>> defined at rescue.c
    >>>            rescue.o:(main)
    >>> defined at trace.c
    >>>            routed.lo:(.text+0x3DE0)
    [...]

To fix this, call vn_pages_remove() to invalidate the pages in the
given range after the write has gone through (successfully or not, in
case of partial writes or other edge cases). We don't do this lower in
afs_write(), since that is also called from our VOP_PUTPAGES()
implementation, and we'd be invalidating pages that we were just given
to write out.

Change-Id: I67708ae994da4a4c26edf32e545606a5238da4d0
Reviewed-on: https://gerrit.openafs.org/14166
Tested-by: BuildBot <buildbot@rampaginggeek.com>
Reviewed-by: Benjamin Kaduk <kaduk@mit.edu>

src/afs/FBSD/osi_vnodeops.c

index 5c301d8..dce4e1c 100644 (file)
@@ -670,11 +670,19 @@ afs_vop_write(ap)
 {
     int code;
     struct vcache *avc = VTOAFS(ap->a_vp);
+    off_t start, end;
+    start = AFS_UIO_OFFSET(ap->a_uio);
+    end = start + AFS_UIO_RESID(ap->a_uio);
+
     AFS_GLOCK();
     osi_FlushPages(avc, ap->a_cred);   /* hold GLOCK, but not basic vnode lock */
     code =
        afs_write(VTOAFS(ap->a_vp), ap->a_uio, ap->a_ioflag, ap->a_cred, 0);
     AFS_GUNLOCK();
+
+    /* Invalidate any pages in the written area. */
+    vn_pages_remove(ap->a_vp, OFF_TO_IDX(start), OFF_TO_IDX(end));
+
     return code;
 }