Date: Thu, 22 Aug 2013 18:26:45 +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: r254668 - in head/sys: kern sys Message-ID: <201308221826.r7MIQjOS050794@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: kib Date: Thu Aug 22 18:26:45 2013 New Revision: 254668 URL: http://svnweb.freebsd.org/changeset/base/254668 Log: Both cluster_rbuild() and cluster_wbuild() sometimes set the pages shared busy without first draining the hard busy state. Previously it went unnoticed since VPO_BUSY and m->busy fields were distinct, and vm_page_io_start() did not verified that the passed page has VPO_BUSY flag cleared, but such page state is wrong. New implementation is more strict and catched this case. Drain the busy state as needed, before calling vm_page_sbusy(). Tested by: pho, jkim Sponsored by: The FreeBSD Foundation Modified: head/sys/kern/vfs_bio.c head/sys/kern/vfs_cluster.c head/sys/sys/buf.h Modified: head/sys/kern/vfs_bio.c ============================================================================== --- head/sys/kern/vfs_bio.c Thu Aug 22 18:12:24 2013 (r254667) +++ head/sys/kern/vfs_bio.c Thu Aug 22 18:26:45 2013 (r254668) @@ -108,7 +108,6 @@ static void vm_hold_load_pages(struct bu static void vfs_page_set_valid(struct buf *bp, vm_ooffset_t off, vm_page_t m); static void vfs_page_set_validclean(struct buf *bp, vm_ooffset_t off, vm_page_t m); -static void vfs_drain_busy_pages(struct buf *bp); static void vfs_clean_pages_dirty_buf(struct buf *bp); static void vfs_setdirty_locked_object(struct buf *bp); static void vfs_vmio_release(struct buf *bp); @@ -3983,7 +3982,7 @@ vfs_page_set_validclean(struct buf *bp, * Ensure that all buffer pages are not exclusive busied. If any page is * exclusive busy, drain it. */ -static void +void vfs_drain_busy_pages(struct buf *bp) { vm_page_t m; Modified: head/sys/kern/vfs_cluster.c ============================================================================== --- head/sys/kern/vfs_cluster.c Thu Aug 22 18:12:24 2013 (r254667) +++ head/sys/kern/vfs_cluster.c Thu Aug 22 18:26:45 2013 (r254668) @@ -315,7 +315,7 @@ cluster_rbuild(struct vnode *vp, u_quad_ daddr_t bn; off_t off; long tinc, tsize; - int i, inc, j, toff; + int i, inc, j, k, toff; KASSERT(size == vp->v_mount->mnt_stat.f_iosize, ("cluster_rbuild: size %ld != f_iosize %jd\n", @@ -378,7 +378,15 @@ cluster_rbuild(struct vnode *vp, u_quad_ inc = btodb(size); bo = &vp->v_bufobj; for (bn = blkno, i = 0; i < run; ++i, bn += inc) { - if (i != 0) { + if (i == 0) { + VM_OBJECT_WLOCK(tbp->b_bufobj->bo_object); + vfs_drain_busy_pages(tbp); + vm_object_pip_add(tbp->b_bufobj->bo_object, + tbp->b_npages); + for (k = 0; k < tbp->b_npages; k++) + vm_page_sbusy(tbp->b_pages[k]); + VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object); + } else { if ((bp->b_npages * PAGE_SIZE) + round_page(size) > vp->v_mount->mnt_iosize_max) { break; @@ -424,14 +432,23 @@ cluster_rbuild(struct vnode *vp, u_quad_ if ((tbp->b_pages[j]->valid & vm_page_bits(toff, tinc)) != 0) break; + if (vm_page_xbusied(tbp->b_pages[j])) + break; + vm_object_pip_add(tbp->b_bufobj->bo_object, 1); + vm_page_sbusy(tbp->b_pages[j]); off += tinc; tsize -= tinc; } - VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object); if (tsize > 0) { +clean_sbusy: + vm_object_pip_add(tbp->b_bufobj->bo_object, -j); + for (k = 0; k < j; k++) + vm_page_sunbusy(tbp->b_pages[k]); + VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object); bqrelse(tbp); break; } + VM_OBJECT_WUNLOCK(tbp->b_bufobj->bo_object); /* * Set a read-ahead mark as appropriate @@ -451,8 +468,8 @@ cluster_rbuild(struct vnode *vp, u_quad_ if (tbp->b_blkno == tbp->b_lblkno) { tbp->b_blkno = bn; } else if (tbp->b_blkno != bn) { - brelse(tbp); - break; + VM_OBJECT_WLOCK(tbp->b_bufobj->bo_object); + goto clean_sbusy; } } /* @@ -466,10 +483,8 @@ cluster_rbuild(struct vnode *vp, u_quad_ for (j = 0; j < tbp->b_npages; j += 1) { vm_page_t m; m = tbp->b_pages[j]; - vm_page_sbusy(m); - vm_object_pip_add(m->object, 1); if ((bp->b_npages == 0) || - (bp->b_pages[bp->b_npages-1] != m)) { + (bp->b_pages[bp->b_npages-1] != m)) { bp->b_pages[bp->b_npages] = m; bp->b_npages++; } @@ -944,7 +959,9 @@ cluster_wbuild(struct vnode *vp, long si vm_page_t m; VM_OBJECT_WLOCK(tbp->b_bufobj->bo_object); - if (i != 0) { /* if not first buffer */ + if (i == 0) { + vfs_drain_busy_pages(tbp); + } else { /* if not first buffer */ for (j = 0; j < tbp->b_npages; j += 1) { m = tbp->b_pages[j]; if (vm_page_xbusied(m)) { Modified: head/sys/sys/buf.h ============================================================================== --- head/sys/sys/buf.h Thu Aug 22 18:12:24 2013 (r254667) +++ head/sys/sys/buf.h Thu Aug 22 18:26:45 2013 (r254668) @@ -501,6 +501,7 @@ void bufstrategy(struct bufobj *, struct void brelse(struct buf *); void bqrelse(struct buf *); int vfs_bio_awrite(struct buf *); +void vfs_drain_busy_pages(struct buf *bp); struct buf * getpbuf(int *); struct buf *incore(struct bufobj *, daddr_t); struct buf *gbincore(struct bufobj *, daddr_t);
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201308221826.r7MIQjOS050794>