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,
