diff --git a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c index 2e8758b..a9579db 100644 --- a/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c +++ b/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c @@ -4233,34 +4233,61 @@ zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int reqpage) znode_t *zp = VTOZ(vp); zfsvfs_t *zfsvfs = zp->z_zfsvfs; objset_t *os = zp->z_zfsvfs->z_os; - vm_page_t mreq; + vm_page_t mfirst, mlast, mreq; vm_object_t object; caddr_t va; struct sf_buf *sf; + off_t startoff, endoff; int i, error; - int pcount, size; + vm_pindex_t reqstart, reqend; + int pcount, lsize, reqsize, size; ZFS_ENTER(zfsvfs); ZFS_VERIFY_ZP(zp); - pcount = round_page(count) / PAGE_SIZE; + pcount = OFF_TO_IDX(round_page(count)); mreq = m[reqpage]; object = mreq->object; error = 0; KASSERT(vp->v_object == object, ("mismatching object")); + if (pcount > 1 && zp->z_blksz > PAGESIZE) { + startoff = rounddown(IDX_TO_OFF(mreq->pindex), zp->z_blksz); + reqstart = OFF_TO_IDX(round_page(startoff)); + if (reqstart < m[0]->pindex) + reqstart = 0; + else + reqstart = reqstart - m[0]->pindex; + endoff = roundup(IDX_TO_OFF(mreq->pindex) + PAGE_SIZE, + zp->z_blksz); + reqend = OFF_TO_IDX(trunc_page(endoff)) - 1; + if (reqend > m[pcount - 1]->pindex) + reqend = m[pcount - 1]->pindex; + reqsize = reqend - m[reqstart]->pindex + 1; + KASSERT(reqstart <= reqpage && reqpage < reqstart + reqsize, + ("reqpage beyond [reqstart, reqstart + reqsize[ bounds")); + } else { + reqstart = reqpage; + reqsize = 1; + } + mfirst = m[reqstart]; + mlast = m[reqstart + reqsize - 1]; + VM_OBJECT_LOCK(object); - for (i = 0; i < pcount; i++) { - if (i != reqpage) { - vm_page_lock(m[i]); - vm_page_free(m[i]); - vm_page_unlock(m[i]); - } + for (i = 0; i < reqstart; i++) { + vm_page_lock(m[i]); + vm_page_free(m[i]); + vm_page_unlock(m[i]); + } + for (i = reqstart + reqsize; i < pcount; i++) { + vm_page_lock(m[i]); + vm_page_free(m[i]); + vm_page_unlock(m[i]); } - if (mreq->valid) { + if (mreq->valid && reqsize == 1) { if (mreq->valid != VM_PAGE_BITS_ALL) vm_page_zero_invalid(mreq, TRUE); VM_OBJECT_UNLOCK(object); @@ -4269,32 +4296,66 @@ zfs_getpages(struct vnode *vp, vm_page_t *m, int count, int reqpage) } PCPU_INC(cnt.v_vnodein); - PCPU_INC(cnt.v_vnodepgsin); + PCPU_ADD(cnt.v_vnodepgsin, reqsize); if (IDX_TO_OFF(mreq->pindex) >= object->un_pager.vnp.vnp_size) { + for (i = reqstart; i < reqstart + reqsize; i++) { + if (i != reqpage) { + vm_page_lock(m[i]); + vm_page_free(m[i]); + vm_page_unlock(m[i]); + } + } VM_OBJECT_UNLOCK(object); ZFS_EXIT(zfsvfs); return (VM_PAGER_BAD); } - size = PAGE_SIZE; - if (IDX_TO_OFF(mreq->pindex) + size > object->un_pager.vnp.vnp_size) - size = object->un_pager.vnp.vnp_size - IDX_TO_OFF(mreq->pindex); + lsize = PAGE_SIZE; + if (IDX_TO_OFF(mlast->pindex) + lsize > object->un_pager.vnp.vnp_size) + lsize = object->un_pager.vnp.vnp_size - IDX_TO_OFF(mlast->pindex); VM_OBJECT_UNLOCK(object); - va = zfs_map_page(mreq, &sf); - error = dmu_read(os, zp->z_id, IDX_TO_OFF(mreq->pindex), - size, va, DMU_READ_PREFETCH); - if (size != PAGE_SIZE) - bzero(va + size, PAGE_SIZE - size); - zfs_unmap_page(sf); + for (i = reqstart; i < reqstart + reqsize; i++) { + size = PAGE_SIZE; + if (i == (reqstart + reqsize - 1)) + size = lsize; + va = zfs_map_page(m[i], &sf); + error = dmu_read(os, zp->z_id, IDX_TO_OFF(m[i]->pindex), + size, va, DMU_READ_PREFETCH); + if (size != PAGE_SIZE) + bzero(va + size, PAGE_SIZE - size); + zfs_unmap_page(sf); + if (error != 0) + break; + } VM_OBJECT_LOCK(object); - if (!error) - mreq->valid = VM_PAGE_BITS_ALL; - KASSERT(mreq->dirty == 0, ("zfs_getpages: page %p is dirty", mreq)); + for (i = reqstart; i < reqstart + reqsize; i++) { + m[i]->valid = VM_PAGE_BITS_ALL; + KASSERT(m[i]->dirty == 0, ("zfs_getpages: page %p is dirty", m[i])); + if (i != reqpage) { + if (!error) { + if (m[i]->oflags & VPO_WANTED) { + vm_page_lock(m[i]); + vm_page_activate(m[i]); + vm_page_unlock(m[i]); + } else { + vm_page_lock(m[i]); + vm_page_deactivate(m[i]); + vm_page_unlock(m[i]); + } + vm_page_wakeup(m[i]); + } else { + vm_page_lock(m[i]); + vm_page_free(m[i]); + vm_page_unlock(m[i]); + } + } + + } VM_OBJECT_UNLOCK(object); @@ -4318,6 +4379,30 @@ zfs_freebsd_getpages(ap) } static int +zfs_freebsd_bmap(ap) + struct vop_bmap_args /* { + struct vnode *a_vp; + daddr_t a_bn; + struct bufobj **a_bop; + daddr_t *a_bnp; + int *a_runp; + int *a_runb; + } */ *ap; +{ + + if (ap->a_bop != NULL) + *ap->a_bop = &ap->a_vp->v_bufobj; + if (ap->a_bnp != NULL) + *ap->a_bnp = ap->a_bn; + if (ap->a_runp != NULL) + *ap->a_runp = 0; + if (ap->a_runb != NULL) + *ap->a_runb = 0; + + return (0); +} + +static int zfs_freebsd_open(ap) struct vop_open_args /* { struct vnode *a_vp; @@ -5424,7 +5509,7 @@ struct vop_vector zfs_vnodeops = { .vop_remove = zfs_freebsd_remove, .vop_rename = zfs_freebsd_rename, .vop_pathconf = zfs_freebsd_pathconf, - .vop_bmap = VOP_EOPNOTSUPP, + .vop_bmap = zfs_freebsd_bmap, .vop_fid = zfs_freebsd_fid, .vop_getextattr = zfs_getextattr, .vop_deleteextattr = zfs_deleteextattr,