Author: avg
Date: Sun Nov 25 14:53:26 2012
New Revision: 243517
URL: http://svnweb.freebsd.org/changeset/base/243517

Log:
  zfs_getpages: optimize for large block sizes
  
  MFC after:    6 weeks

Modified:
  head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c

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     Sun Nov 
25 14:25:08 2012        (r243516)
+++ head/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/zfs_vnops.c     Sun Nov 
25 14:53:26 2012        (r243517)
@@ -5556,34 +5556,61 @@ zfs_getpages(struct vnode *vp, vm_page_t
        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);
@@ -5592,30 +5619,66 @@ zfs_getpages(struct vnode *vp, vm_page_t
        }
 
        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);
 
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to