From owner-svn-src-all@freebsd.org Wed Dec 16 13:56:27 2015 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id AC3AFA49BB2; Wed, 16 Dec 2015 13:56:27 +0000 (UTC) (envelope-from kib@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 mx1.freebsd.org (Postfix) with ESMTPS id 54ACE1A48; Wed, 16 Dec 2015 13:56:27 +0000 (UTC) (envelope-from kib@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id tBG8mblT040702; Wed, 16 Dec 2015 08:48:37 GMT (envelope-from kib@FreeBSD.org) Received: (from kib@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id tBG8mbJX040699; Wed, 16 Dec 2015 08:48:37 GMT (envelope-from kib@FreeBSD.org) Message-Id: <201512160848.tBG8mbJX040699@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: kib set sender to kib@FreeBSD.org using -f From: Konstantin Belousov Date: Wed, 16 Dec 2015 08:48:37 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r292326 - in head/sys: kern sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.20 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: Wed, 16 Dec 2015 13:56:27 -0000 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) \