git: a0895e394d3f - main - tarfs: Implement VOP_BMAP

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Fri, 05 Apr 2024 15:16:21 UTC
The branch main has been updated by markj:

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

commit a0895e394d3fec374e61a207bdfa0245dae86f53
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-04-05 15:14:36 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-04-05 15:14:36 +0000

    tarfs: Implement VOP_BMAP
    
    This lets tarfs provide readahead/behind hints to the VFS, which helps
    memory-mapped I/O performance, important when running faulting in
    executables out of a tarfs mount as one might if tarfs is used to back
    the root filesystem, for example.  The improvement is particularly
    noticeable when the backing tarball is zstd-compressed.
    
    The implementation simply returns the extent of the virtual block
    containing the target offset, clamped by the maximum I/O size.  This is
    perhaps simplistic; it effectively just chooses values that would
    correspond to a single VOP_READ call in tarfs_read_file().
    
    Reviewed by:    des, kib
    MFC after:      1 month
    Sponsored by:   Klara, Inc.
    Differential Revision:  https://reviews.freebsd.org/D44626
---
 sys/fs/tarfs/tarfs_vnops.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 55 insertions(+)

diff --git a/sys/fs/tarfs/tarfs_vnops.c b/sys/fs/tarfs/tarfs_vnops.c
index 7a04f891350e..f2828c60f8a7 100644
--- a/sys/fs/tarfs/tarfs_vnops.c
+++ b/sys/fs/tarfs/tarfs_vnops.c
@@ -125,6 +125,60 @@ tarfs_access(struct vop_access_args *ap)
 	return (error);
 }
 
+static int
+tarfs_bmap(struct vop_bmap_args *ap)
+{
+	struct tarfs_node *tnp;
+	struct vnode *vp;
+	off_t off;
+	uint64_t iosize;
+	int ra, rb, rmax;
+
+	vp = ap->a_vp;
+	iosize = vp->v_mount->mnt_stat.f_iosize;
+
+	if (ap->a_bop != NULL)
+		*ap->a_bop = &vp->v_bufobj;
+	if (ap->a_bnp != NULL)
+		*ap->a_bnp = ap->a_bn * btodb(iosize);
+	if (ap->a_runp == NULL)
+		return (0);
+
+	tnp = VP_TO_TARFS_NODE(vp);
+	off = ap->a_bn * iosize;
+
+	ra = rb = 0;
+	for (u_int i = 0; i < tnp->nblk; i++) {
+		off_t bs, be;
+
+		bs = tnp->blk[i].o;
+		be = tnp->blk[i].o + tnp->blk[i].l;
+		if (off > be)
+			continue;
+		else if (off < bs) {
+			/* We're in a hole. */
+			ra = bs - off < iosize ?
+			    0 : howmany(bs - (off + iosize), iosize);
+			rb = howmany(off - (i == 0 ?
+			    0 : tnp->blk[i - 1].o + tnp->blk[i - 1].l),
+			    iosize);
+			break;
+		} else {
+			/* We'll be reading from the backing file. */
+			ra = be - off < iosize ?
+			    0 : howmany(be - (off + iosize), iosize);
+			rb = howmany(off - bs, iosize);
+			break;
+		}
+	}
+
+	rmax = vp->v_mount->mnt_iosize_max / iosize - 1;
+	*ap->a_runp = imin(ra, rmax);
+	if (ap->a_runb != NULL)
+		*ap->a_runb = imin(rb, rmax);
+	return (0);
+}
+
 static int
 tarfs_getattr(struct vop_getattr_args *ap)
 {
@@ -629,6 +683,7 @@ struct vop_vector tarfs_vnodeops = {
 	.vop_default =		&default_vnodeops,
 
 	.vop_access =		tarfs_access,
+	.vop_bmap =		tarfs_bmap,
 	.vop_cachedlookup =	tarfs_lookup,
 	.vop_close =		tarfs_close,
 	.vop_getattr =		tarfs_getattr,