The branch main has been updated by kib:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=bab04ddf1fd4b7a77d1cfae4a67ededf1f35ee0d

commit bab04ddf1fd4b7a77d1cfae4a67ededf1f35ee0d
Author:     Chuck Silvers <[email protected]>
AuthorDate: 2026-05-07 12:43:53 +0000
Commit:     Konstantin Belousov <[email protected]>
CommitDate: 2026-05-13 19:46:00 +0000

    ufs: support unmapped bufs for indirect blocks in bmap
    
    Use unmapped bufs for indirect block buffers in bmap, and use sf_bufs
    for transient mapping them when we need to read the specific pointer.
    
    [kib note: I changed the original patch to use sf_buf instead of
    explicit DMAP utilization, making the change MI].
    
    Tested by:      pho
    Reviewed by:    kib
    MFC after:      1 week
    Differential revision:  https://reviews.freebsd.org/D53424
---
 sys/ufs/ufs/ufs_bmap.c | 143 +++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 134 insertions(+), 9 deletions(-)

diff --git a/sys/ufs/ufs/ufs_bmap.c b/sys/ufs/ufs/ufs_bmap.c
index 9d21eaa0cb56..edfcabb1a607 100644
--- a/sys/ufs/ufs/ufs_bmap.c
+++ b/sys/ufs/ufs/ufs_bmap.c
@@ -34,7 +34,6 @@
  * SUCH DAMAGE.
  */
 
-#include <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bio.h>
 #include <sys/buf.h>
@@ -44,10 +43,13 @@
 #include <sys/mount.h>
 #include <sys/racct.h>
 #include <sys/resourcevar.h>
+#include <sys/sched.h>
+#include <sys/sf_buf.h>
 #include <sys/stat.h>
 
 #include <vm/vm.h>
 #include <vm/vm_object.h>
+#include <vm/vm_page.h>
 #include <vm/vnode_pager.h>
 
 #include <ufs/ufs/extattr.h>
@@ -59,6 +61,11 @@
 static ufs_lbn_t lbn_count(struct ufsmount *, int);
 static int readindir(struct vnode *, ufs_lbn_t, ufs2_daddr_t, struct buf **);
 
+static int ufs_bmap_use_unmapped = 1;
+
+SYSCTL_INT(_vfs_ufs, OID_AUTO, bmap_use_unmapped, CTLFLAG_RWTUN,
+    &ufs_bmap_use_unmapped, 0, "UFS bmap uses unmapped bufs");
+
 /*
  * Bmap converts the logical block number of a file to its physical block
  * number on the disk. The conversion is done by using the logical block
@@ -102,12 +109,15 @@ readindir(struct vnode *vp,
        struct buf *bp;
        struct mount *mp;
        struct ufsmount *ump;
-       int error;
+       struct inode *ip;
+       int error, gbflags;
 
        mp = vp->v_mount;
        ump = VFSTOUFS(mp);
+       ip = VTOI(vp);
 
-       bp = getblk(vp, lbn, mp->mnt_stat.f_iosize, 0, 0, 0);
+       gbflags = !I_IS_UFS1(ip) && ufs_bmap_use_unmapped ? GB_UNMAPPED : 0;
+       bp = getblk(vp, lbn, mp->mnt_stat.f_iosize, 0, 0, gbflags);
        if ((bp->b_flags & B_CACHE) == 0) {
                KASSERT(daddr != 0,
                    ("readindir: indirect block not in cache"));
@@ -151,6 +161,24 @@ readindir(struct vnode *vp,
  * next block and the disk address of the block (if it is assigned).
  */
 
+static void *
+ufs_bm_sf_get(struct buf *bp, int32_t pgidx, struct sf_buf **sfp)
+{
+       struct sf_buf *sf;
+
+       sched_pin();
+       sf = sf_buf_alloc(bp->b_pages[pgidx], SFB_CPUPRIVATE);
+       *sfp = sf;
+       return (sf_buf_kva(sf));
+}
+
+static void
+ufs_bm_sf_put(struct sf_buf *sf)
+{
+       sf_buf_free(sf);
+       sched_unpin();
+}
+
 int
 ufs_bmaparray(struct vnode *vp,
        ufs2_daddr_t bn,
@@ -164,10 +192,16 @@ ufs_bmaparray(struct vnode *vp,
        struct ufsmount *ump;
        struct mount *mp;
        struct indir a[UFS_NIADDR+1], *ap;
+       struct sf_buf *sf;
        ufs2_daddr_t daddr;
        ufs_lbn_t metalbn;
        int error, num, maxrun = 0;
        int *nump;
+       ufs1_daddr_t *daddr1p;
+       ufs2_daddr_t pgbn, daddrppg, prevdaddr, *daddr2p;
+       int32_t daddrsz, boff, pgidx, pgoff;
+       void *pgaddr;
+       bool isseq;
 
        ap = NULL;
        ip = VTOI(vp);
@@ -261,17 +295,71 @@ ufs_bmaparray(struct vnode *vp,
                if (error != 0)
                        return (error);
 
-               if (I_IS_UFS1(ip))
-                       daddr = ((ufs1_daddr_t *)bp->b_data)[ap->in_off];
-               else
-                       daddr = ((ufs2_daddr_t *)bp->b_data)[ap->in_off];
+               daddrsz = I_IS_UFS1(ip) ? sizeof(ufs1_daddr_t) : 
sizeof(ufs2_daddr_t);
+               if (!buf_mapped(bp)) {
+                       boff = ap->in_off * daddrsz;
+                       pgidx = boff / PAGE_SIZE;
+                       pgoff = (boff & PAGE_MASK) / daddrsz;
+                       pgaddr = ufs_bm_sf_get(bp, pgidx, &sf);
+                       if (I_IS_UFS1(ip))
+                               daddr = ((ufs1_daddr_t *)pgaddr)[pgoff];
+                       else
+                               daddr = ((ufs2_daddr_t *)pgaddr)[pgoff];
+                       ufs_bm_sf_put(sf);
+               } else {
+                       if (I_IS_UFS1(ip))
+                               daddr = ((ufs1_daddr_t 
*)bp->b_data)[ap->in_off];
+                       else
+                               daddr = ((ufs2_daddr_t 
*)bp->b_data)[ap->in_off];
+               }
+
                if ((error = UFS_CHECK_BLKNO(mp, ip->i_number, daddr,
                     mp->mnt_stat.f_iosize)) != 0) {
                        bqrelse(bp);
                        return (error);
                }
+               if (num > 1 || daddr == 0 || runp == NULL)
+                       continue;
+
+               daddrppg = PAGE_SIZE / daddrsz;
                if (I_IS_UFS1(ip)) {
-                       if (num == 1 && daddr && runp) {
+                       if (!buf_mapped(bp)) {
+                               prevdaddr = daddr;
+                               isseq = true;
+                               for (bn = ap->in_off + 1;
+                                   bn < MNINDIR(ump) && *runp < maxrun && 
isseq; ) {
+                                       boff = bn * daddrsz;
+                                       pgidx = boff / PAGE_SIZE;
+                                       pgoff = (boff & PAGE_MASK) / daddrsz;
+                                       KASSERT(pgidx >= 0 && pgidx < 
bp->b_npages,
+                                               ("pgidx %d vs b_npages %d", 
pgidx, bp->b_npages));
+                                       pgaddr = ufs_bm_sf_get(bp, pgidx, &sf);
+                                       daddr1p = (ufs1_daddr_t *)pgaddr;
+                                       for (pgbn = pgoff;
+                                            pgbn < daddrppg && *runp < maxrun 
&&
+                                            (isseq = is_sequential(ump, 
prevdaddr, daddr1p[pgbn]));
+                                            prevdaddr = daddr1p[pgbn], ++pgbn, 
++bn, ++*runp);
+                                       ufs_bm_sf_put(sf);
+                               }
+                               prevdaddr = daddr;
+                               bn = ap->in_off;
+                               if (runb && bn) {
+                                       isseq = true;
+                                       for (--bn; bn >= 0 && *runb < maxrun && 
isseq; ) {
+                                               boff = bn * daddrsz;
+                                               pgidx = boff / PAGE_SIZE;
+                                               pgoff = (boff & PAGE_MASK) / 
daddrsz;
+                                               KASSERT(pgidx >= 0 && pgidx < 
bp->b_npages,
+                                                       ("pgidx %d vs b_npages 
%d", pgidx, bp->b_npages));
+                                               pgaddr = ufs_bm_sf_get(bp, 
pgidx, &sf);
+                                               daddr1p = (ufs1_daddr_t 
*)pgaddr;
+                                               for (pgbn = pgoff; pgbn >= 0 && 
*runb < maxrun &&
+                                                    (isseq = 
is_sequential(ump, daddr1p[pgbn], prevdaddr));
+                                                    prevdaddr = daddr1p[pgbn], 
--pgbn, --bn, ++*runb);
+                                               ufs_bm_sf_put(sf);
+                                       }
+                               }
+                       } else {
                                for (bn = ap->in_off + 1;
                                    bn < MNINDIR(ump) && *runp < maxrun &&
                                    is_sequential(ump,
@@ -289,7 +377,44 @@ ufs_bmaparray(struct vnode *vp,
                        }
                        continue;
                }
-               if (num == 1 && daddr && runp) {
+
+               if (!buf_mapped(bp)) {
+                       prevdaddr = daddr;
+                       isseq = true;
+                       for (bn = ap->in_off + 1;
+                           bn < MNINDIR(ump) && *runp < maxrun && isseq; ) {
+                               boff = bn * daddrsz;
+                               pgidx = boff / PAGE_SIZE;
+                               pgoff = (boff & PAGE_MASK) / daddrsz;
+                               KASSERT(pgidx >= 0 && pgidx < bp->b_npages,
+                                       ("pgidx %d vs b_npages %d", pgidx, 
bp->b_npages));
+                               pgaddr = ufs_bm_sf_get(bp, pgidx, &sf);
+                               daddr2p = (ufs2_daddr_t *)pgaddr;
+                               for (pgbn = pgoff;
+                                    pgbn < daddrppg && *runp < maxrun &&
+                                    (isseq = is_sequential(ump, prevdaddr, 
daddr2p[pgbn]));
+                                    prevdaddr = daddr2p[pgbn], ++pgbn, ++bn, 
++*runp);
+                               ufs_bm_sf_put(sf);
+                       }
+                       prevdaddr = daddr;
+                       bn = ap->in_off;
+                       if (runb && bn) {
+                               isseq = true;
+                               for (--bn; bn >= 0 && *runb < maxrun && isseq; 
) {
+                                       boff = bn * daddrsz;
+                                       pgidx = boff / PAGE_SIZE;
+                                       pgoff = (boff & PAGE_MASK) / daddrsz;
+                                       KASSERT(pgidx >= 0 && pgidx < 
bp->b_npages,
+                                               ("pgidx %d vs b_npages %d", 
pgidx, bp->b_npages));
+                                       pgaddr = ufs_bm_sf_get(bp, pgidx, &sf);
+                                       daddr2p = (ufs2_daddr_t *)pgaddr;
+                                       for (pgbn = pgoff; pgbn >= 0 && *runb < 
maxrun &&
+                                            (isseq = is_sequential(ump, 
daddr2p[pgbn], prevdaddr));
+                                            prevdaddr = daddr2p[pgbn], --pgbn, 
--bn, ++*runb);
+                                       ufs_bm_sf_put(sf);
+                               }
+                       }
+               } else {
                        for (bn = ap->in_off + 1;
                            bn < MNINDIR(ump) && *runp < maxrun &&
                            is_sequential(ump,

Reply via email to