Hi folks,

hereby an adjusted version that re-applies after the latest changes in
uvm_swap.c made recently.

With regards,
Reinoud

? sys/uvm/uvm_swap.c.1st
? sys/uvm/uvm_swap.c.2nd
? sys/uvm/uvm_swap.c.3rd
Index: sys/uvm/uvm_pager.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_pager.c,v
retrieving revision 1.136
diff -u -p -r1.136 uvm_pager.c
--- sys/uvm/uvm_pager.c 3 May 2026 16:02:37 -0000       1.136
+++ sys/uvm/uvm_pager.c 6 Jul 2026 09:26:05 -0000
@@ -547,16 +547,6 @@ uvm_aio_aiodone(struct buf *bp)
                    (uintptr_t)pgs[i], 0, 0);
        }
 
-#if defined(VMSWAP)
-       if (__predict_false(error != 0) &&
-           ((pgs[0]->flags & PG_SWAPBACKED) != 0)) {
-               int swslot = uvm_page_swapslot(pgs[0]);
-
-               KASSERT(swslot > 0);
-               uvm_swap_decrypt_pages(swslot, bp->b_data, npages);
-       }
-#endif
-
        uvm_pagermapout((vaddr_t)bp->b_data, npages);
 
        uvm_aio_aiodone_pages(pgs, npages, write, error);
Index: sys/uvm/uvm_swap.c
===================================================================
RCS file: /cvsroot/src/sys/uvm/uvm_swap.c,v
retrieving revision 1.234
diff -u -p -r1.234 uvm_swap.c
--- sys/uvm/uvm_swap.c  27 Jun 2026 14:56:29 -0000      1.234
+++ sys/uvm/uvm_swap.c  6 Jul 2026 09:26:06 -0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: uvm_swap.c,v 1.234 2026/06/27 14:56:29 riastradh Exp $ */
+/*     $NetBSD: uvm_swap.c,v 1.233 2026/06/03 15:00:06 yamt Exp $      */
 
 /*
  * Copyright (c) 1995, 1996, 1997, 2009 Matthew R. Green
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.234 2026/06/27 14:56:29 riastradh 
Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_swap.c,v 1.233 2026/06/03 15:00:06 yamt Exp 
$");
 
 #include "opt_uvmhist.h"
 #include "opt_compat_netbsd.h"
@@ -218,6 +218,7 @@ static int uvm_swap_io(struct vm_page **
 static void uvm_swap_genkey(struct swapdev *);
 static void uvm_swap_encryptpage(struct swapdev *, void *, int);
 static void uvm_swap_decryptpage(struct swapdev *, void *, int);
+static void uvm_swap_encrypt_pages(int startslot, void *p, int npages);
 
 /*
  * uvm_swap_init: init the swap system data structures and locks
@@ -1328,40 +1329,45 @@ iobuf_redirect(struct buf *bp, struct vn
        bp->b_objlock = vp->v_interlock;
 }
 
-struct sw_physio_decrypt_context {
-       void *orig_buf;
-       void *orig_private;
-       void (*orig_iodone)(struct buf *);
-       int swslot;
-};
 
+/* handle the nestio buffer */
 static void
-sw_physio_decrypt_iodone(struct buf *bp)
+sw_physio_decrypt_iodone(struct buf *nbp)
 {
-       struct sw_physio_decrypt_context *ctx = bp->b_private;
-       void (*cb)(struct buf *bp) = ctx->orig_iodone;
-       size_t npages = bp->b_bcount >> PAGE_SHIFT;
-
-       KASSERT(ctx->swslot > 0);
-       KASSERT(npages << PAGE_SHIFT == bp->b_bcount);
-       if (bp->b_error == 0) {
-               if (bp->b_resid == 0) {
-                       uvm_swap_decrypt_pages(ctx->swslot, bp->b_data,
-                           npages);
-                       memcpy(ctx->orig_buf, (uint8_t *)bp->b_data,
-                           bp->b_bcount);
+       struct buf *bp = nbp->b_private;        /* parent buffer */
+       size_t npages  = nbp->b_bcount >> PAGE_SHIFT;
+       int swslot = (intptr_t) nbp->b_private2;
+
+       KASSERT(swslot > 0);
+       KASSERT(npages << PAGE_SHIFT == nbp->b_bcount);
+
+       /*
+        * always decrypt even after we wrote as its backing page(s) could
+        * still be in use after the write.
+        */
+       uvm_swap_decrypt_pages(swslot, nbp->b_data, npages);
+
+       /* copy data if we used a bounce buffer */
+       if (nbp->b_error == 0) {
+               if (nbp->b_resid == 0) {
+                       if (nbp->b_data != bp->b_data)
+                               memcpy(bp->b_data, (uint8_t *)nbp->b_data,
+                                      nbp->b_bcount);
                } else {
-                       bp->b_error = EIO;
+                       /* XXX we could zero the buffer */
+                       nbp->b_error = EIO;
                }
        }
-       kmem_intr_free(bp->b_data, bp->b_bcount);
-       bp->b_data = ctx->orig_buf;
-       if (bp->b_error != 0) {
-               bp->b_resid = bp->b_bcount;
+       /* free optional bounce buffer */
+       if (nbp->b_data != bp->b_data)
+               kmem_intr_free(nbp->b_data, nbp->b_bcount);
+
+       if (nbp->b_error != 0) {
+               bp->b_error = nbp->b_error;
+               bp->b_resid = nbp->b_bcount;
        }
-       bp->b_private = ctx->orig_private;
-       kmem_intr_free(ctx, sizeof(*ctx));
-       (cb)(bp);       /* call the original b_iodone callback */
+
+       nestiobuf_iodone(nbp);
 }
 
 /*
@@ -1374,19 +1380,23 @@ swstrategy(struct buf *bp)
 {
        struct swapdev *sdp;
        struct vnode *vp;
+       struct buf *nbp;
+       int npages = bp->b_bufsize >> PAGE_SHIFT;
        int pageno, bn;
        UVMHIST_FUNC(__func__); UVMHIST_CALLED(pdhist);
 
        KASSERT((bp->b_flags & B_RAW) == 0 ||
            rw_read_held(&swap_syscall_lock));
 
+       /* set residual to all bytes */
+       bp->b_resid = bp->b_bcount;
+
        /*
         * reject non page aligned i/o.
         */
        if ((dbtob((int64_t)bp->b_blkno) & PAGE_MASK) != 0 ||
            (bp->b_bcount & PAGE_MASK) != 0) {
                bp->b_error = ENOTSUP;
-               bp->b_resid = bp->b_bcount;
                biodone(bp);
                return;
        }
@@ -1405,48 +1415,60 @@ swstrategy(struct buf *bp)
        mutex_exit(&uvm_swap_data_lock);
        if (sdp == NULL) {
                bp->b_error = EINVAL;
-               bp->b_resid = bp->b_bcount;
                biodone(bp);
                UVMHIST_LOG(pdhist, "  failed to get swap device", 0, 0, 0, 0);
                return;
        }
 
        /*
-        * B_RAW here implies user i/o on /dev/drum, for which we need
-        * to handle encryption/decryption here.
-        * for swap in/out, it's handled by the caller.
+        * if the swap is encrypted, we encrypt before we write. in the
+        * callback we ensure its always decrypted (again).
         */
-       if ((bp->b_flags & B_RAW) != 0 &&
-           atomic_load_relaxed(&uvm_swap_encrypt)) {
-               struct sw_physio_decrypt_context *ctx;
+       if (atomic_load_relaxed(&uvm_swap_encrypt)) {
+               int swslot;
 
-               /*
-                * we only implement B_READ for now.
-                *
-                * REVISIT: what kind of apps needs to write to /dev/drum?
-                */
-               if ((bp->b_flags & B_READ) == 0) {
-                       bp->b_error = ENOTSUP;
-                       bp->b_resid = bp->b_bcount;
+               /* get iobuf for our decryption nestio setup */
+               nbp = getiobuf(bp->b_vp, !uvm_lwp_is_pagedaemon(curlwp));
+               if (nbp == NULL) {
+                       bp->b_error = ENOMEM;
                        biodone(bp);
+                       UVMHIST_LOG(pdhist, "  failed to get iobuf",
+                               0, 0, 0, 0);
                        return;
                }
+               nestiobuf_setup(bp, nbp, 0, bp->b_bcount);
+               KASSERT(nbp->b_private == bp);
+               KASSERT(nbp->b_iodone == nestiobuf_iodone);
+
+               nbp->b_blkno = bp->b_blkno;
+
+               /* pass on swslot around for callback */
+               swslot = dbtob((int64_t)bp->b_blkno) >> PAGE_SHIFT;
+               KASSERT(swslot > 0);
+               nbp->b_private2 = (void *) (intptr_t) swslot;
+
+               /* redirect our iodone to the decrypt iodone */
+               nbp->b_iodone = sw_physio_decrypt_iodone;
+
+               /*
+                * in-place decryption in the userland buffer might
+                * have non-trivial implications. for simplicity,
+                * we use a bounce buffer. B_RAW here implies user i/o on
+                * /dev/drum. It gets freed in the callback.
+                */
+               if (BUF_ISREAD(bp) && (bp->b_flags & B_RAW))
+                       nbp->b_data = kmem_intr_alloc(nbp->b_bcount, KM_SLEEP);
 
                /*
-                * In-place decryption in the userland buffer might
-                * have non-trivial implications, since the original
-                * bp->b_data is backed by pages shared with userland.
-                * For simplicity, we use a bounce buffer.
-                */
-               ctx = kmem_intr_alloc(sizeof(*ctx), KM_SLEEP);
-               ctx->swslot = dbtob((int64_t)bp->b_blkno) >> PAGE_SHIFT;
-               KASSERT(ctx->swslot > 0);
-               ctx->orig_buf = bp->b_data;
-               ctx->orig_private = bp->b_private;
-               ctx->orig_iodone = bp->b_iodone;
-               bp->b_data = kmem_intr_alloc(bp->b_bcount, KM_SLEEP);
-               bp->b_private = ctx;
-               bp->b_iodone = sw_physio_decrypt_iodone;
+                * encrypt in-place when writing as we can't claim a bounce
+                * buffer as it could be a writeout due to memory pressure.
+                * its later decrypted in the callback as the pages could
+                * still be in use.
+                */
+               if (BUF_ISWRITE(bp))
+                       uvm_swap_encrypt_pages(pageno, bp->b_data, npages);
+       } else {
+               nbp = bp;
        }
 
        /*
@@ -1478,16 +1500,16 @@ swstrategy(struct buf *bp)
                 * if we are doing a write, we have to redirect the i/o on
                 * drum's v_numoutput counter to the swapdev's.
                 */
-               iobuf_redirect(bp, vp);
-               bp->b_blkno = bn;               /* swapdev block number */
-               VOP_STRATEGY(vp, bp);
+               iobuf_redirect(nbp, vp);
+               nbp->b_blkno = bn;              /* swapdev block number */
+               VOP_STRATEGY(vp, nbp);
                return;
 
        case VREG:
                /*
                 * delegate to sw_reg_strategy function.
                 */
-               sw_reg_strategy(sdp, bp, bn);
+               sw_reg_strategy(sdp, nbp, bn);
                return;
        }
        /* NOTREACHED */
@@ -2083,13 +2105,6 @@ uvm_swap_io(struct vm_page **pps, int st
        kva = uvm_pagermapin(pps, npages, mapinflags);
 
        /*
-        * encrypt writes in place if requested
-        */
-       if (write) {
-               uvm_swap_encrypt_pages(startslot, (void *)kva, npages);
-       }
-
-       /*
         * fill in the bp/sbp.   we currently route our i/o through
         * /dev/drum's vnode [swapdev_vp].
         */
@@ -2099,7 +2114,7 @@ uvm_swap_io(struct vm_page **pps, int st
        bp->b_vnbufs.le_next = NOLIST;
        bp->b_data = (void *)kva;
        bp->b_blkno = startblk;
-       bp->b_bufsize = bp->b_bcount = npages << PAGE_SHIFT;
+       bp->b_bufsize = bp->b_bcount = bp->b_resid = npages << PAGE_SHIFT;
 
        /*
         * bump v_numoutput (counter of number of active outputs).
@@ -2148,12 +2163,6 @@ uvm_swap_io(struct vm_page **pps, int st
        if (error)
                goto out;
 
-       /*
-        * decrypt reads in place if needed
-        */
-       if (!write) {
-               uvm_swap_decrypt_pages(startslot, (void *)kva, npages);
-       }
 out:
        /*
         * kill the pager mapping

Reply via email to