Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 16 Dec 2015 08:48:37 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r292326 - in head/sys: kern sys
Message-ID:  <201512160848.tBG8mbJX040699@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Wed Dec 16 08:48:37 2015
New Revision: 292326
URL: https://svnweb.freebsd.org/changeset/base/292326

Log:
  Optimize vop_stdadvise(POSIX_FADV_DONTNEED).  Instead of looking up a
  buffer for each block number in the range with gbincore(), look up the
  next instantiated buffer with the logical block number which is
  greater or equal to the next lblkno.  This significantly speeds up the
  iteration for sparce-populated range.
  
  Move the iteration into new helper bnoreuselist(), which is structured
  similarly to flushbuflist().
  
  Reported and tested by:	pho
  Reviewed by:	markj
  Sponsored by:	The FreeBSD Foundation

Modified:
  head/sys/kern/vfs_default.c
  head/sys/kern/vfs_subr.c
  head/sys/sys/vnode.h

Modified: head/sys/kern/vfs_default.c
==============================================================================
--- head/sys/kern/vfs_default.c	Wed Dec 16 08:39:51 2015	(r292325)
+++ head/sys/kern/vfs_default.c	Wed Dec 16 08:48:37 2015	(r292326)
@@ -1034,10 +1034,9 @@ vop_stdallocate(struct vop_allocate_args
 int
 vop_stdadvise(struct vop_advise_args *ap)
 {
-	struct buf *bp;
-	struct buflists *bl;
 	struct vnode *vp;
-	daddr_t bn, startn, endn;
+	struct bufobj *bo;
+	daddr_t startn, endn;
 	off_t start, end;
 	int bsize, error;
 
@@ -1074,36 +1073,21 @@ vop_stdadvise(struct vop_advise_args *ap
 			VM_OBJECT_WUNLOCK(vp->v_object);
 		}
 
-		BO_RLOCK(&vp->v_bufobj);
+		bo = &vp->v_bufobj;
+		BO_RLOCK(bo);
 		bsize = vp->v_bufobj.bo_bsize;
 		startn = ap->a_start / bsize;
-		endn = -1;
-		bl = &vp->v_bufobj.bo_clean.bv_hd;
-		if (!TAILQ_EMPTY(bl))
-			endn = TAILQ_LAST(bl, buflists)->b_lblkno;
-		bl = &vp->v_bufobj.bo_dirty.bv_hd;
-		if (!TAILQ_EMPTY(bl) &&
-		    endn < TAILQ_LAST(bl, buflists)->b_lblkno)
-			endn = TAILQ_LAST(bl, buflists)->b_lblkno;
-		if (ap->a_end != OFF_MAX && endn != -1)
-			endn = ap->a_end / bsize;
-		BO_RUNLOCK(&vp->v_bufobj);
-		/*
-		 * In the VMIO case, use the B_NOREUSE flag to hint that the
-		 * pages backing each buffer in the range are unlikely to be
-		 * reused.  Dirty buffers will have the hint applied once
-		 * they've been written.
-		 */
-		for (bn = startn; bn <= endn; bn++) {
-			bp = getblk(vp, bn, bsize, 0, 0, GB_NOCREAT |
-			    GB_UNMAPPED);
-			if (bp == NULL)
+		endn = ap->a_end / bsize;
+		for (;;) {
+			error = bnoreuselist(&bo->bo_clean, bo, startn, endn);
+			if (error == EAGAIN)
 				continue;
-			bp->b_flags |= B_RELBUF;
-			if (vp->v_object != NULL)
-				bp->b_flags |= B_NOREUSE;
-			brelse(bp);
+			error = bnoreuselist(&bo->bo_dirty, bo, startn, endn);
+			if (error == EAGAIN)
+				continue;
+			break;
 		}
+		BO_RUNLOCK(bo);
 		VOP_UNLOCK(vp, 0);
 		break;
 	default:

Modified: head/sys/kern/vfs_subr.c
==============================================================================
--- head/sys/kern/vfs_subr.c	Wed Dec 16 08:39:51 2015	(r292325)
+++ head/sys/kern/vfs_subr.c	Wed Dec 16 08:48:37 2015	(r292326)
@@ -1660,6 +1660,45 @@ flushbuflist(struct bufv *bufv, int flag
 	return (retval);
 }
 
+int
+bnoreuselist(struct bufv *bufv, struct bufobj *bo, daddr_t startn, daddr_t endn)
+{
+	struct buf *bp;
+	int error;
+	daddr_t lblkno;
+
+	ASSERT_BO_LOCKED(bo);
+
+	for (lblkno = startn;; lblkno++) {
+		bp = BUF_PCTRIE_LOOKUP_GE(&bufv->bv_root, lblkno);
+		if (bp == NULL || bp->b_lblkno >= endn)
+			break;
+		error = BUF_TIMELOCK(bp, LK_EXCLUSIVE | LK_SLEEPFAIL |
+		    LK_INTERLOCK, BO_LOCKPTR(bo), "brlsfl", 0, 0);
+		if (error != 0) {
+			BO_RLOCK(bo);
+			return (error != ENOLCK ? error : EAGAIN);
+		}
+		KASSERT(bp->b_bufobj == bo,
+		    ("bp %p wrong b_bufobj %p should be %p",
+		    bp, bp->b_bufobj, bo));
+		if ((bp->b_flags & B_MANAGED) == 0)
+			bremfree(bp);
+		bp->b_flags |= B_RELBUF;
+		/*
+		 * In the VMIO case, use the B_NOREUSE flag to hint that the
+		 * pages backing each buffer in the range are unlikely to be
+		 * reused.  Dirty buffers will have the hint applied once
+		 * they've been written.
+		 */
+		if (bp->b_vp->v_object != NULL)
+			bp->b_flags |= B_NOREUSE;
+		brelse(bp);
+		BO_RLOCK(bo);
+	}
+	return (0);
+}
+
 /*
  * Truncate a file's buffer and pages to a specified length.  This
  * is in lieu of the old vinvalbuf mechanism, which performed unneeded

Modified: head/sys/sys/vnode.h
==============================================================================
--- head/sys/sys/vnode.h	Wed Dec 16 08:39:51 2015	(r292325)
+++ head/sys/sys/vnode.h	Wed Dec 16 08:48:37 2015	(r292326)
@@ -605,6 +605,8 @@ struct vnode;
 
 typedef int (*vn_get_ino_t)(struct mount *, void *, int, struct vnode **);
 
+int	bnoreuselist(struct bufv *bufv, struct bufobj *bo, daddr_t startn,
+	    daddr_t endn);
 /* cache_* may belong in namei.h. */
 void	cache_changesize(int newhashsize);
 #define	cache_enter(dvp, vp, cnp)					\



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