From owner-svn-src-all@freebsd.org Sun Mar 17 17:34:08 2019 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id ECD9D154473E; Sun, 17 Mar 2019 17:34:07 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) server-signature RSA-PSS (4096 bits) client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "Let's Encrypt Authority X3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 8C49688E5D; Sun, 17 Mar 2019 17:34:07 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id 67FE7D37D; Sun, 17 Mar 2019 17:34:07 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id x2HHY71h004908; Sun, 17 Mar 2019 17:34:07 GMT (envelope-from markj@FreeBSD.org) Received: (from markj@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id x2HHY6FM004905; Sun, 17 Mar 2019 17:34:06 GMT (envelope-from markj@FreeBSD.org) Message-Id: <201903171734.x2HHY6FM004905@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: markj set sender to markj@FreeBSD.org using -f From: Mark Johnston Date: Sun, 17 Mar 2019 17:34:06 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r345244 - head/sys/ufs/ufs X-SVN-Group: head X-SVN-Commit-Author: markj X-SVN-Commit-Paths: head/sys/ufs/ufs X-SVN-Commit-Revision: 345244 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Rspamd-Queue-Id: 8C49688E5D X-Spamd-Bar: -- Authentication-Results: mx1.freebsd.org X-Spamd-Result: default: False [-2.96 / 15.00]; local_wl_from(0.00)[FreeBSD.org]; NEURAL_HAM_MEDIUM(-1.00)[-0.998,0]; NEURAL_HAM_LONG(-1.00)[-1.000,0]; NEURAL_HAM_SHORT(-0.96)[-0.963,0]; ASN(0.00)[asn:11403, ipnet:2610:1c1:1::/48, country:US] X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 17 Mar 2019 17:34:08 -0000 Author: markj Date: Sun Mar 17 17:34:06 2019 New Revision: 345244 URL: https://svnweb.freebsd.org/changeset/base/345244 Log: Optimize lseek(SEEK_DATA) on UFS. The old implementation, at the VFS layer, would map the entire range of logical blocks between the starting offset and the first data block following that offset. With large sparse files this is very inefficient. The VFS currently doesn't provide an interface to improve upon the current implementation in a generic way. Add ufs_bmap_seekdata(), which uses the obvious algorithm of scanning indirect blocks to look for data blocks. Use it instead of vn_bmap_seekhole() to implement SEEK_DATA. Reviewed by: kib, mckusick MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D19598 Modified: head/sys/ufs/ufs/ufs_bmap.c head/sys/ufs/ufs/ufs_extern.h head/sys/ufs/ufs/ufs_vnops.c Modified: head/sys/ufs/ufs/ufs_bmap.c ============================================================================== --- head/sys/ufs/ufs/ufs_bmap.c Sun Mar 17 13:02:24 2019 (r345243) +++ head/sys/ufs/ufs/ufs_bmap.c Sun Mar 17 17:34:06 2019 (r345244) @@ -90,6 +90,51 @@ ufs_bmap(ap) return (error); } +static int +ufs_readindir(vp, lbn, daddr, bpp) + struct vnode *vp; + ufs_lbn_t lbn; + ufs2_daddr_t daddr; + struct buf **bpp; +{ + struct buf *bp; + struct mount *mp; + struct ufsmount *ump; + int error; + + mp = vp->v_mount; + ump = VFSTOUFS(mp); + + bp = getblk(vp, lbn, mp->mnt_stat.f_iosize, 0, 0, 0); + if ((bp->b_flags & B_CACHE) == 0) { + KASSERT(daddr != 0, + ("ufs_readindir: indirect block not in cache")); + + bp->b_blkno = blkptrtodb(ump, daddr); + bp->b_iocmd = BIO_READ; + bp->b_flags &= ~B_INVAL; + bp->b_ioflags &= ~BIO_ERROR; + vfs_busy_pages(bp, 0); + bp->b_iooffset = dbtob(bp->b_blkno); + bstrategy(bp); +#ifdef RACCT + if (racct_enable) { + PROC_LOCK(curproc); + racct_add_buf(curproc, bp, 0); + PROC_UNLOCK(curproc); + } +#endif + curthread->td_ru.ru_inblock++; + error = bufwait(bp); + if (error != 0) { + brelse(bp); + return (error); + } + } + *bpp = bp; + return (0); +} + /* * Indirect blocks are now on the vnode for the file. They are given negative * logical block numbers. Indirect blocks are addressed by the negative @@ -212,35 +257,10 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb) */ if (bp) bqrelse(bp); + error = ufs_readindir(vp, metalbn, daddr, &bp); + if (error != 0) + return (error); - bp = getblk(vp, metalbn, mp->mnt_stat.f_iosize, 0, 0, 0); - if ((bp->b_flags & B_CACHE) == 0) { -#ifdef INVARIANTS - if (!daddr) - panic("ufs_bmaparray: indirect block not in cache"); -#endif - bp->b_blkno = blkptrtodb(ump, daddr); - bp->b_iocmd = BIO_READ; - bp->b_flags &= ~B_INVAL; - bp->b_ioflags &= ~BIO_ERROR; - vfs_busy_pages(bp, 0); - bp->b_iooffset = dbtob(bp->b_blkno); - bstrategy(bp); -#ifdef RACCT - if (racct_enable) { - PROC_LOCK(curproc); - racct_add_buf(curproc, bp, 0); - PROC_UNLOCK(curproc); - } -#endif /* RACCT */ - curthread->td_ru.ru_inblock++; - error = bufwait(bp); - if (error) { - brelse(bp); - return (error); - } - } - if (I_IS_UFS1(ip)) { daddr = ((ufs1_daddr_t *)bp->b_data)[ap->in_off]; if (num == 1 && daddr && runp) { @@ -301,6 +321,93 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb) *bnp = -1; } return (0); +} + +int +ufs_bmap_seekdata(vp, offp) + struct vnode *vp; + off_t *offp; +{ + struct buf *bp; + struct indir a[UFS_NIADDR + 1], *ap; + struct inode *ip; + struct mount *mp; + struct ufsmount *ump; + ufs2_daddr_t blockcnt, bn, daddr; + uint64_t bsize; + off_t numblks; + int error, num, num1; + + bp = NULL; + ip = VTOI(vp); + mp = vp->v_mount; + ump = VFSTOUFS(mp); + + if (vp->v_type != VREG || (ip->i_flags & SF_SNAPSHOT) != 0) + return (EINVAL); + if (*offp < 0) + return (ENXIO); + + bsize = mp->mnt_stat.f_iosize; + for (bn = *offp / bsize, numblks = howmany(ip->i_size, bsize); + bn < numblks;) { + if (bn < UFS_NDADDR) { + daddr = DIP(ip, i_db[bn]); + if (daddr != 0) + break; + bn++; + continue; + } + + ap = a; + error = ufs_getlbns(vp, bn, ap, &num); + if (error != 0) + break; + MPASS(num >= 2); + daddr = DIP(ip, i_ib[ap->in_off]); + ap++, num--; + if (daddr == 0) { + for (blockcnt = 1; num > 0; num--) + blockcnt *= MNINDIR(ump); + bn += blockcnt; + continue; + } + + for (; num > 0 && daddr != 0; ap++, num--) { + if (bp != NULL) + bqrelse(bp); + error = ufs_readindir(vp, ap->in_lbn, daddr, &bp); + if (error != 0) + return (error); + + /* + * Precompute the number of blocks addressed by an entry + * of the current indirect block. + */ + for (blockcnt = 1, num1 = num; num1 > 1; num1--) + blockcnt *= MNINDIR(ump); + + for (; ap->in_off < MNINDIR(ump); ap->in_off++, + bn += blockcnt) { + daddr = I_IS_UFS1(ip) ? + ((ufs1_daddr_t *)bp->b_data)[ap->in_off] : + ((ufs2_daddr_t *)bp->b_data)[ap->in_off]; + if (daddr != 0) + break; + } + } + if (daddr != 0) { + MPASS(num == 0); + break; + } + } + if (bp != NULL) + bqrelse(bp); + if (bn >= numblks) + error = ENXIO; + if (error == 0) + *offp = bn * bsize; + return (error); } /* Modified: head/sys/ufs/ufs/ufs_extern.h ============================================================================== --- head/sys/ufs/ufs/ufs_extern.h Sun Mar 17 13:02:24 2019 (r345243) +++ head/sys/ufs/ufs/ufs_extern.h Sun Mar 17 17:34:06 2019 (r345244) @@ -58,6 +58,7 @@ extern struct vop_vector ufs_vnodeops; int ufs_bmap(struct vop_bmap_args *); int ufs_bmaparray(struct vnode *, ufs2_daddr_t, ufs2_daddr_t *, struct buf *, int *, int *); +int ufs_bmap_seekdata(struct vnode *, off_t *); int ufs_fhtovp(struct mount *, struct ufid *, int, struct vnode **); int ufs_checkpath(ino_t, ino_t, struct inode *, struct ucred *, ino_t *); void ufs_dirbad(struct inode *, doff_t, char *); Modified: head/sys/ufs/ufs/ufs_vnops.c ============================================================================== --- head/sys/ufs/ufs/ufs_vnops.c Sun Mar 17 13:02:24 2019 (r345243) +++ head/sys/ufs/ufs/ufs_vnops.c Sun Mar 17 17:34:06 2019 (r345244) @@ -2701,12 +2701,15 @@ bad: static int ufs_ioctl(struct vop_ioctl_args *ap) { + struct vnode *vp; + vp = ap->a_vp; switch (ap->a_command) { case FIOSEEKDATA: + return (ufs_bmap_seekdata(vp, (off_t *)ap->a_data)); case FIOSEEKHOLE: - return (vn_bmap_seekhole(ap->a_vp, ap->a_command, - (off_t *)ap->a_data, ap->a_cred)); + return (vn_bmap_seekhole(vp, ap->a_command, (off_t *)ap->a_data, + ap->a_cred)); default: return (ENOTTY); }