From owner-svn-src-all@FreeBSD.ORG Fri Nov 29 15:39:40 2013 Return-Path: Delivered-To: svn-src-all@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 829C5FDF; Fri, 29 Nov 2013 15:39:40 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mx1.freebsd.org (Postfix) with ESMTPS id 636D61D8D; Fri, 29 Nov 2013 15:39:40 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.7/8.14.7) with ESMTP id rATFdenv095137; Fri, 29 Nov 2013 15:39:40 GMT (envelope-from avg@svn.freebsd.org) Received: (from avg@localhost) by svn.freebsd.org (8.14.7/8.14.5/Submit) id rATFddap095134; Fri, 29 Nov 2013 15:39:39 GMT (envelope-from avg@svn.freebsd.org) Message-Id: <201311291539.rATFddap095134@svn.freebsd.org> From: Andriy Gapon Date: Fri, 29 Nov 2013 15:39:39 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r258746 - in head/sys/cddl: compat/opensolaris/kern compat/opensolaris/sys contrib/opensolaris/uts/common/fs/zfs 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.16 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: Fri, 29 Nov 2013 15:39:40 -0000 Author: avg Date: Fri Nov 29 15:39:39 2013 New Revision: 258746 URL: http://svnweb.freebsd.org/changeset/base/258746 Log: zfs: add zfs_freebsd_putpages this should be more optimal than writing pages one-by-one via zfs_write -> update_pages in the case of multi-page putpages call MFC after: 16 days Modified: head/sys/cddl/compat/opensolaris/kern/opensolaris_vm.c head/sys/cddl/compat/opensolaris/sys/vm.h head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Modified: head/sys/cddl/compat/opensolaris/kern/opensolaris_vm.c ============================================================================== --- head/sys/cddl/compat/opensolaris/kern/opensolaris_vm.c Fri Nov 29 15:34:43 2013 (r258745) +++ head/sys/cddl/compat/opensolaris/kern/opensolaris_vm.c Fri Nov 29 15:39:39 2013 (r258746) @@ -40,6 +40,8 @@ __FBSDID("$FreeBSD$"); const int zfs_vm_pagerret_bad = VM_PAGER_BAD; const int zfs_vm_pagerret_error = VM_PAGER_ERROR; const int zfs_vm_pagerret_ok = VM_PAGER_OK; +const int zfs_vm_pagerput_sync = VM_PAGER_PUT_SYNC; +const int zfs_vm_pagerput_inval = VM_PAGER_PUT_INVAL; void zfs_vmobject_assert_wlocked(vm_object_t object) Modified: head/sys/cddl/compat/opensolaris/sys/vm.h ============================================================================== --- head/sys/cddl/compat/opensolaris/sys/vm.h Fri Nov 29 15:34:43 2013 (r258745) +++ head/sys/cddl/compat/opensolaris/sys/vm.h Fri Nov 29 15:39:39 2013 (r258746) @@ -36,6 +36,8 @@ extern const int zfs_vm_pagerret_bad; extern const int zfs_vm_pagerret_error; extern const int zfs_vm_pagerret_ok; +extern const int zfs_vm_pagerput_sync; +extern const int zfs_vm_pagerput_inval; void zfs_vmobject_assert_wlocked(vm_object_t object); void zfs_vmobject_wlock(vm_object_t object); Modified: head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c ============================================================================== --- head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Fri Nov 29 15:34:43 2013 (r258745) +++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c Fri Nov 29 15:39:39 2013 (r258746) @@ -467,6 +467,7 @@ update_pages(vnode_t *vp, int64_t start, caddr_t va; int off; + ASSERT(segflg != UIO_NOCOPY); ASSERT(vp->v_mount != NULL); obj = vp->v_object; ASSERT(obj != NULL); @@ -477,27 +478,7 @@ update_pages(vnode_t *vp, int64_t start, vm_page_t pp; int nbytes = imin(PAGESIZE - off, len); - if (segflg == UIO_NOCOPY) { - pp = vm_page_lookup(obj, OFF_TO_IDX(start)); - KASSERT(pp != NULL, - ("zfs update_pages: NULL page in putpages case")); - KASSERT(off == 0, - ("zfs update_pages: unaligned data in putpages case")); - KASSERT(pp->valid == VM_PAGE_BITS_ALL, - ("zfs update_pages: invalid page in putpages case")); - KASSERT(vm_page_sbusied(pp), - ("zfs update_pages: unbusy page in putpages case")); - KASSERT(!pmap_page_is_write_mapped(pp), - ("zfs update_pages: writable page in putpages case")); - zfs_vmobject_wunlock(obj); - - va = zfs_map_page(pp, &sf); - (void) dmu_write(os, oid, start, nbytes, va, tx); - zfs_unmap_page(sf); - - zfs_vmobject_wlock(obj); - vm_page_undirty(pp); - } else if ((pp = page_busy(vp, start, off, nbytes)) != NULL) { + if ((pp = page_busy(vp, start, off, nbytes)) != NULL) { zfs_vmobject_wunlock(obj); va = zfs_map_page(pp, &sf); @@ -511,8 +492,7 @@ update_pages(vnode_t *vp, int64_t start, len -= nbytes; off = 0; } - if (segflg != UIO_NOCOPY) - vm_object_pip_wakeupn(obj, 0); + vm_object_pip_wakeupn(obj, 0); zfs_vmobject_wunlock(obj); } @@ -5804,6 +5784,168 @@ zfs_freebsd_getpages(ap) } static int +zfs_putpages(struct vnode *vp, vm_page_t *ma, size_t len, int flags, + int *rtvals) +{ + znode_t *zp = VTOZ(vp); + zfsvfs_t *zfsvfs = zp->z_zfsvfs; + rl_t *rl; + dmu_tx_t *tx; + struct sf_buf *sf; + vm_object_t object; + vm_page_t m; + caddr_t va; + size_t tocopy; + size_t lo_len; + vm_ooffset_t lo_off; + vm_ooffset_t off; + uint_t blksz; + int ncount; + int pcount; + int err; + int i; + + ZFS_ENTER(zfsvfs); + ZFS_VERIFY_ZP(zp); + + object = vp->v_object; + pcount = btoc(len); + ncount = pcount; + + KASSERT(ma[0]->object == object, ("mismatching object")); + KASSERT(len > 0 && (len & PAGE_MASK) == 0, ("unexpected length")); + + for (i = 0; i < pcount; i++) + rtvals[i] = zfs_vm_pagerret_error; + + off = IDX_TO_OFF(ma[0]->pindex); + blksz = zp->z_blksz; + lo_off = rounddown(off, blksz); + lo_len = roundup(len + (off - lo_off), blksz); + rl = zfs_range_lock(zp, lo_off, lo_len, RL_WRITER); + + zfs_vmobject_wlock(object); + if (len + off > object->un_pager.vnp.vnp_size) { + if (object->un_pager.vnp.vnp_size > off) { + int pgoff; + + len = object->un_pager.vnp.vnp_size - off; + ncount = btoc(len); + if ((pgoff = (int)len & PAGE_MASK) != 0) { + /* + * If the object is locked and the following + * conditions hold, then the page's dirty + * field cannot be concurrently changed by a + * pmap operation. + */ + m = ma[ncount - 1]; + vm_page_assert_sbusied(m); + KASSERT(!pmap_page_is_write_mapped(m), + ("zfs_putpages: page %p is not read-only", m)); + vm_page_clear_dirty(m, pgoff, PAGE_SIZE - + pgoff); + } + } else { + len = 0; + ncount = 0; + } + if (ncount < pcount) { + for (i = ncount; i < pcount; i++) { + rtvals[i] = zfs_vm_pagerret_bad; + } + } + } + zfs_vmobject_wunlock(object); + + if (ncount == 0) + goto out; + + if (zfs_owner_overquota(zfsvfs, zp, B_FALSE) || + zfs_owner_overquota(zfsvfs, zp, B_TRUE)) { + goto out; + } + +top: + tx = dmu_tx_create(zfsvfs->z_os); + dmu_tx_hold_write(tx, zp->z_id, off, len); + + dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE); + zfs_sa_upgrade_txholds(tx, zp); + err = dmu_tx_assign(tx, TXG_NOWAIT); + if (err != 0) { + if (err == ERESTART) { + dmu_tx_wait(tx); + dmu_tx_abort(tx); + goto top; + } + dmu_tx_abort(tx); + goto out; + } + + if (zp->z_blksz < PAGE_SIZE) { + i = 0; + for (i = 0; len > 0; off += tocopy, len -= tocopy, i++) { + tocopy = len > PAGE_SIZE ? PAGE_SIZE : len; + va = zfs_map_page(ma[i], &sf); + dmu_write(zfsvfs->z_os, zp->z_id, off, tocopy, va, tx); + zfs_unmap_page(sf); + } + } else { + err = dmu_write_pages(zfsvfs->z_os, zp->z_id, off, len, ma, tx); + } + + if (err == 0) { + uint64_t mtime[2], ctime[2]; + sa_bulk_attr_t bulk[3]; + int count = 0; + + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_MTIME(zfsvfs), NULL, + &mtime, 16); + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_CTIME(zfsvfs), NULL, + &ctime, 16); + SA_ADD_BULK_ATTR(bulk, count, SA_ZPL_FLAGS(zfsvfs), NULL, + &zp->z_pflags, 8); + zfs_tstamp_update_setup(zp, CONTENT_MODIFIED, mtime, ctime, + B_TRUE); + zfs_log_write(zfsvfs->z_log, tx, TX_WRITE, zp, off, len, 0); + + zfs_vmobject_wlock(object); + for (i = 0; i < ncount; i++) { + rtvals[i] = zfs_vm_pagerret_ok; + vm_page_undirty(ma[i]); + } + zfs_vmobject_wunlock(object); + PCPU_INC(cnt.v_vnodeout); + PCPU_ADD(cnt.v_vnodepgsout, ncount); + } + dmu_tx_commit(tx); + +out: + zfs_range_unlock(rl); + if ((flags & (zfs_vm_pagerput_sync | zfs_vm_pagerput_inval)) != 0 || + zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS) + zil_commit(zfsvfs->z_log, zp->z_id); + ZFS_EXIT(zfsvfs); + return (rtvals[0]); +} + +int +zfs_freebsd_putpages(ap) + struct vop_putpages_args /* { + struct vnode *a_vp; + vm_page_t *a_m; + int a_count; + int a_sync; + int *a_rtvals; + vm_ooffset_t a_offset; + } */ *ap; +{ + + return (zfs_putpages(ap->a_vp, ap->a_m, ap->a_count, ap->a_sync, + ap->a_rtvals)); +} + +static int zfs_freebsd_bmap(ap) struct vop_bmap_args /* { struct vnode *a_vp; @@ -6949,6 +7091,7 @@ struct vop_vector zfs_vnodeops = { .vop_setacl = zfs_freebsd_setacl, .vop_aclcheck = zfs_freebsd_aclcheck, .vop_getpages = zfs_freebsd_getpages, + .vop_putpages = zfs_freebsd_putpages, }; struct vop_vector zfs_fifoops = {