Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 29 Apr 2019 22:05:26 +0000 (UTC)
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r346932 - head/sys/ufs/ufs
Message-ID:  <201904292205.x3TM5Q7Z058461@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: markj
Date: Mon Apr 29 22:05:26 2019
New Revision: 346932
URL: https://svnweb.freebsd.org/changeset/base/346932

Log:
  Optimize lseek(SEEK_DATA) on UFS.
  
  This version fixes the problems identified in r345244.
  
  Reviewed by:	kib
  MFC after:	1 month
  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	Mon Apr 29 22:00:45 2019	(r346931)
+++ head/sys/ufs/ufs/ufs_bmap.c	Mon Apr 29 22:05:26 2019	(r346932)
@@ -56,6 +56,9 @@ __FBSDID("$FreeBSD$");
 #include <ufs/ufs/ufsmount.h>
 #include <ufs/ufs/ufs_extern.h>
 
+static ufs_lbn_t lbn_count(struct ufsmount *, int);
+static int readindir(struct vnode *, ufs_lbn_t, ufs2_daddr_t, struct buf **);
+
 /*
  * 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
@@ -90,6 +93,51 @@ ufs_bmap(ap)
 	return (error);
 }
 
+static int
+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,
+		    ("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 +260,10 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb)
 		 */
 		if (bp)
 			bqrelse(bp);
+		error = 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 +324,111 @@ ufs_bmaparray(vp, bn, bnp, nbp, runp, runb)
 			*bnp = -1;
 	}
 	return (0);
+}
+
+static ufs_lbn_t
+lbn_count(ump, level)
+	struct ufsmount *ump;
+	int level;
+{
+	ufs_lbn_t blockcnt;
+
+	for (blockcnt = 1; level > 0; level--)
+		blockcnt *= MNINDIR(ump);
+	return (blockcnt);
+}
+
+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 bn, daddr, nextbn;
+	uint64_t bsize;
+	off_t numblks;
+	int error, num, num1, off;
+
+	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 || *offp >= ip->i_size)
+		return (ENXIO);
+
+	bsize = mp->mnt_stat.f_iosize;
+	for (bn = *offp / bsize, numblks = howmany(ip->i_size, bsize);
+	    bn < numblks; bn = nextbn) {
+		if (bn < UFS_NDADDR) {
+			daddr = DIP(ip, i_db[bn]);
+			if (daddr != 0)
+				break;
+			nextbn = bn + 1;
+			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--;
+		for (nextbn = UFS_NDADDR, num1 = num - 1; num1 > 0; num1--)
+			nextbn += lbn_count(ump, num1);
+		if (daddr == 0) {
+			nextbn += lbn_count(ump, num);
+			continue;
+		}
+
+		for (; daddr != 0 && num > 0; ap++, num--) {
+			if (bp != NULL)
+				bqrelse(bp);
+			error = readindir(vp, ap->in_lbn, daddr, &bp);
+			if (error != 0)
+				return (error);
+
+			/*
+			 * Scan the indirect block until we find a non-zero
+			 * pointer.
+			 */
+			off = ap->in_off;
+			do {
+				daddr = I_IS_UFS1(ip) ?
+				    ((ufs1_daddr_t *)bp->b_data)[off] :
+				    ((ufs2_daddr_t *)bp->b_data)[off];
+			} while (daddr == 0 && ++off < MNINDIR(ump));
+			nextbn += off * lbn_count(ump, num - 1);
+
+			/*
+			 * We need to recompute the LBNs of indirect
+			 * blocks, so restart with the updated block offset.
+			 */
+			if (off != ap->in_off)
+				break;
+		}
+		if (num == 0) {
+			/*
+			 * We found a data block.
+			 */
+			bn = nextbn;
+			break;
+		}
+	}
+	if (bp != NULL)
+		bqrelse(bp);
+	if (bn >= numblks)
+		error = ENXIO;
+	if (error == 0 && *offp < bn * bsize)
+		*offp = bn * bsize;
+	return (error);
 }
 
 /*

Modified: head/sys/ufs/ufs/ufs_extern.h
==============================================================================
--- head/sys/ufs/ufs/ufs_extern.h	Mon Apr 29 22:00:45 2019	(r346931)
+++ head/sys/ufs/ufs/ufs_extern.h	Mon Apr 29 22:05:26 2019	(r346932)
@@ -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	Mon Apr 29 22:00:45 2019	(r346931)
+++ head/sys/ufs/ufs/ufs_vnops.c	Mon Apr 29 22:05:26 2019	(r346932)
@@ -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);
 	}



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904292205.x3TM5Q7Z058461>