Author: kib
Date: Sun Jul  4 11:26:56 2010
New Revision: 209686
URL: http://svn.freebsd.org/changeset/base/209686

Log:
  Reimplement vm_object_page_clean(), using the fact that vm object memq
  is ordered by page index. This greatly simplifies the implementation,
  since we no longer need to mark the pages with VPO_CLEANCHK to denote
  the progress. It is enough to remember the current position by index
  before dropping the object lock.
  
  Remove VPO_CLEANCHK and VM_PAGER_IGNORE_CLEANCHK as unused.
  Garbage-collect vm.msync_flush_flags sysctl.
  
  Suggested and reviewed by:    alc
  Tested by:    pho

Modified:
  head/sys/vm/vm_object.c
  head/sys/vm/vm_page.h
  head/sys/vm/vm_pager.h

Modified: head/sys/vm/vm_object.c
==============================================================================
--- head/sys/vm/vm_object.c     Sun Jul  4 11:13:33 2010        (r209685)
+++ head/sys/vm/vm_object.c     Sun Jul  4 11:26:56 2010        (r209686)
@@ -101,13 +101,6 @@ __FBSDID("$FreeBSD$");
 #define MSYNC_FLUSH_HARDSEQ    0x01
 #define MSYNC_FLUSH_SOFTSEQ    0x02
 
-/*
- * msync / VM object flushing optimizations
- */
-static int msync_flush_flags = MSYNC_FLUSH_HARDSEQ | MSYNC_FLUSH_SOFTSEQ;
-SYSCTL_INT(_vm, OID_AUTO, msync_flush_flags, CTLFLAG_RW, &msync_flush_flags, 0,
-    "Enable sequential iteration optimization");
-
 static int old_msync;
 SYSCTL_INT(_vm, OID_AUTO, old_msync, CTLFLAG_RW, &old_msync, 0,
     "Use old (insecure) msync behavior");
@@ -762,276 +755,167 @@ vm_object_terminate(vm_object_t object)
  *     The object must be locked.
  */
 void
-vm_object_page_clean(vm_object_t object, vm_pindex_t start, vm_pindex_t end, 
int flags)
+vm_object_page_clean(vm_object_t object, vm_pindex_t start, vm_pindex_t end,
+    int flags)
 {
-       vm_page_t p, np;
-       vm_pindex_t tstart, tend;
-       vm_pindex_t pi;
-       int clearobjflags;
-       int pagerflags;
-       int curgeneration;
+       vm_page_t np, p;
+       vm_pindex_t pi, tend;
+       int clearobjflags, curgeneration, n, pagerflags;
 
        mtx_assert(&vm_page_queue_mtx, MA_NOTOWNED);
        VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
-       if ((object->flags & OBJ_MIGHTBEDIRTY) == 0)
+       if ((object->flags & OBJ_MIGHTBEDIRTY) == 0 ||
+           object->resident_page_count == 0)
                return;
        KASSERT(object->type == OBJT_VNODE, ("Not a vnode object"));
 
-       pagerflags = (flags & (OBJPC_SYNC | OBJPC_INVAL)) ? VM_PAGER_PUT_SYNC : 
VM_PAGER_CLUSTER_OK;
-       pagerflags |= (flags & OBJPC_INVAL) ? VM_PAGER_PUT_INVAL : 0;
+       pagerflags = (flags & (OBJPC_SYNC | OBJPC_INVAL)) != 0 ?
+           VM_PAGER_PUT_SYNC : VM_PAGER_CLUSTER_OK;
+       pagerflags |= (flags & OBJPC_INVAL) != 0 ? VM_PAGER_PUT_INVAL : 0;
 
-       vm_object_set_flag(object, OBJ_CLEANING);
-
-       tstart = start;
-       if (end == 0) {
-               tend = object->size;
-       } else {
-               tend = end;
-       }
-
-       /*
-        * If the caller is smart and only msync()s a range he knows is
-        * dirty, we may be able to avoid an object scan.  This results in
-        * a phenominal improvement in performance.  We cannot do this
-        * as a matter of course because the object may be huge - e.g.
-        * the size might be in the gigabytes or terrabytes.
-        */
-       if (msync_flush_flags & MSYNC_FLUSH_HARDSEQ) {
-               vm_pindex_t tscan;
-               int scanlimit;
-               int scanreset;
-
-               scanreset = object->resident_page_count / EASY_SCAN_FACTOR;
-               if (scanreset < 16)
-                       scanreset = 16;
-               pagerflags |= VM_PAGER_IGNORE_CLEANCHK;
-
-               scanlimit = scanreset;
-               tscan = tstart;
-               while (tscan < tend) {
-                       curgeneration = object->generation;
-                       p = vm_page_lookup(object, tscan);
-                       if (p == NULL || p->valid == 0) {
-                               if (--scanlimit == 0)
-                                       break;
-                               ++tscan;
-                               continue;
-                       }
-                       vm_page_test_dirty(p);
-                       if (p->dirty == 0) {
-                               if (--scanlimit == 0)
-                                       break;
-                               ++tscan;
-                               continue;
-                       }
-                       /*
-                        * If we have been asked to skip nosync pages and 
-                        * this is a nosync page, we can't continue.
-                        */
-                       if ((flags & OBJPC_NOSYNC) && (p->oflags & VPO_NOSYNC)) 
{
-                               if (--scanlimit == 0)
-                                       break;
-                               ++tscan;
-                               continue;
-                       }
-                       scanlimit = scanreset;
+       tend = (end == 0) ? object->size : end;
 
-                       /*
-                        * This returns 0 if it was unable to busy the first
-                        * page (i.e. had to sleep).
-                        */
-                       tscan += vm_object_page_collect_flush(object, p, 
curgeneration, pagerflags);
-
-               }
-
-               /*
-                * If everything was dirty and we flushed it successfully,
-                * and the requested range is not the entire object, we
-                * don't have to mess with CLEANCHK or MIGHTBEDIRTY and can
-                * return immediately.
-                */
-               if (tscan >= tend && (tstart || tend < object->size)) {
-                       vm_object_clear_flag(object, OBJ_CLEANING);
-                       return;
-               }
-               pagerflags &= ~VM_PAGER_IGNORE_CLEANCHK;
-       }
+       vm_object_set_flag(object, OBJ_CLEANING);
 
        /*
-        * Generally set CLEANCHK interlock and make the page read-only so
-        * we can then clear the object flags.
+        * Make the page read-only so we can then clear the object flags.
         *
         * However, if this is a nosync mmap then the object is likely to 
         * stay dirty so do not mess with the page and do not clear the
         * object flags.
         */
        clearobjflags = 1;
-       TAILQ_FOREACH(p, &object->memq, listq) {
-               p->oflags |= VPO_CLEANCHK;
-               if ((flags & OBJPC_NOSYNC) && (p->oflags & VPO_NOSYNC))
+       for (p = vm_page_find_least(object, start);
+           p != NULL && p->pindex < tend; p = TAILQ_NEXT(p, listq)) {
+               if ((flags & OBJPC_NOSYNC) != 0 &&
+                   (p->oflags & VPO_NOSYNC) != 0)
                        clearobjflags = 0;
                else
                        pmap_remove_write(p);
        }
 
-       if (clearobjflags && (tstart == 0) && (tend == object->size))
+       if (clearobjflags && (start == 0) && (tend == object->size))
                vm_object_clear_flag(object, OBJ_MIGHTBEDIRTY);
 
 rescan:
+       p = vm_page_find_least(object, start);
        curgeneration = object->generation;
 
-       for (p = TAILQ_FIRST(&object->memq); p; p = np) {
-               int n;
-
-               np = TAILQ_NEXT(p, listq);
-
-again:
+       for (; p != NULL; p = np) {
                pi = p->pindex;
-               if ((p->oflags & VPO_CLEANCHK) == 0 ||
-                       (pi < tstart) || (pi >= tend) ||
-                   p->valid == 0) {
-                       p->oflags &= ~VPO_CLEANCHK;
+               if (pi >= tend)
+                       break;
+               np = TAILQ_NEXT(p, listq);
+               if (p->valid == 0)
                        continue;
+               while (vm_page_sleep_if_busy(p, TRUE, "vpcwai")) {
+                       if (object->generation != curgeneration)
+                               goto rescan;
                }
-
                vm_page_test_dirty(p);
-               if (p->dirty == 0) {
-                       p->oflags &= ~VPO_CLEANCHK;
+               if (p->dirty == 0)
                        continue;
-               }
+
                /*
                 * If we have been asked to skip nosync pages and this is a
                 * nosync page, skip it.  Note that the object flags were
                 * not cleared in this case so we do not have to set them.
                 */
-               if ((flags & OBJPC_NOSYNC) && (p->oflags & VPO_NOSYNC)) {
-                       p->oflags &= ~VPO_CLEANCHK;
+               if ((flags & OBJPC_NOSYNC) != 0 &&
+                   (p->oflags & VPO_NOSYNC) != 0)
                        continue;
-               }
 
                n = vm_object_page_collect_flush(object, p,
-                       curgeneration, pagerflags);
-               if (n == 0)
-                       goto rescan;
-
+                   curgeneration, pagerflags);
+               KASSERT(n > 0, ("vm_object_page_collect_flush failed"));
                if (object->generation != curgeneration)
                        goto rescan;
-
-               /*
-                * Try to optimize the next page.  If we can't we pick up
-                * our (random) scan where we left off.
-                */
-               if (msync_flush_flags & MSYNC_FLUSH_SOFTSEQ)
-                       if ((p = vm_page_lookup(object, pi + n)) != NULL)
-                               goto again;
+               np = vm_page_find_least(object, pi + n);
        }
 #if 0
-       VOP_FSYNC(vp, (pagerflags & VM_PAGER_PUT_SYNC)?MNT_WAIT:0, curproc);
+       VOP_FSYNC(vp, (pagerflags & VM_PAGER_PUT_SYNC) ? MNT_WAIT : 0);
 #endif
 
        vm_object_clear_flag(object, OBJ_CLEANING);
-       return;
 }
 
 static int
-vm_object_page_collect_flush(vm_object_t object, vm_page_t p, int 
curgeneration, int pagerflags)
+vm_object_page_collect_flush(vm_object_t object, vm_page_t p, int 
curgeneration,
+    int pagerflags)
 {
        int runlen;
        int maxf;
        int chkb;
        int maxb;
-       int i;
+       int i, index;
        vm_pindex_t pi;
        vm_page_t maf[vm_pageout_page_count];
        vm_page_t mab[vm_pageout_page_count];
        vm_page_t ma[vm_pageout_page_count];
+       vm_page_t tp, p1;
 
        mtx_assert(&vm_page_queue_mtx, MA_NOTOWNED);
        vm_page_lock_assert(p, MA_NOTOWNED);
        VM_OBJECT_LOCK_ASSERT(object, MA_OWNED);
        pi = p->pindex;
-       while (vm_page_sleep_if_busy(p, TRUE, "vpcwai")) {
-               if (object->generation != curgeneration) {
-                       return(0);
-               }
-       }
        maxf = 0;
-       for(i = 1; i < vm_pageout_page_count; i++) {
-               vm_page_t tp;
-
-               if ((tp = vm_page_lookup(object, pi + i)) != NULL) {
-                       if ((tp->oflags & VPO_BUSY) ||
-                               ((pagerflags & VM_PAGER_IGNORE_CLEANCHK) == 0 &&
-                                (tp->oflags & VPO_CLEANCHK) == 0) ||
-                               (tp->busy != 0))
-                               break;
-                       vm_page_test_dirty(tp);
-                       if (tp->dirty == 0) {
-                               tp->oflags &= ~VPO_CLEANCHK;
-                               break;
-                       }
-                       maf[ i - 1 ] = tp;
-                       maxf++;
-                       continue;
-               }
-               break;
+       for (i = 1, p1 = p; i < vm_pageout_page_count; i++) {
+               tp = vm_page_next(p1);
+               if (tp == NULL || tp->busy != 0 || (tp->oflags & VPO_BUSY) != 0)
+                       break;
+               vm_page_test_dirty(tp);
+               if (tp->dirty == 0)
+                       break;
+               maf[i - 1] = p1 = tp;
+               maxf++;
        }
 
        maxb = 0;
        chkb = vm_pageout_page_count -  maxf;
-       if (chkb) {
-               for(i = 1; i < chkb;i++) {
-                       vm_page_t tp;
-
-                       if ((tp = vm_page_lookup(object, pi - i)) != NULL) {
-                               if ((tp->oflags & VPO_BUSY) ||
-                                       ((pagerflags & 
VM_PAGER_IGNORE_CLEANCHK) == 0 &&
-                                        (tp->oflags & VPO_CLEANCHK) == 0) ||
-                                       (tp->busy != 0))
-                                       break;
-                               vm_page_test_dirty(tp);
-                               if (tp->dirty == 0) {
-                                       tp->oflags &= ~VPO_CLEANCHK;
-                                       break;
-                               }
-                               mab[ i - 1 ] = tp;
-                               maxb++;
-                               continue;
-                       }
+       for (i = 1, p1 = p; i < chkb; i++) {
+               tp = vm_page_prev(p1);
+               if (tp == NULL || tp->busy != 0 || (tp->oflags & VPO_BUSY) != 0)
                        break;
-               }
+               vm_page_test_dirty(tp);
+               if (tp->dirty == 0)
+                       break;
+               mab[i - 1] = p1 = tp;
+               maxb++;
        }
 
-       for(i = 0; i < maxb; i++) {
-               int index = (maxb - i) - 1;
+       for (i = 0; i < maxb; i++) {
+               index = (maxb - i) - 1;
                ma[index] = mab[i];
-               ma[index]->oflags &= ~VPO_CLEANCHK;
        }
-       p->oflags &= ~VPO_CLEANCHK;
        ma[maxb] = p;
-       for(i = 0; i < maxf; i++) {
-               int index = (maxb + i) + 1;
+       for (i = 0; i < maxf; i++) {
+               index = (maxb + i) + 1;
                ma[index] = maf[i];
-               ma[index]->oflags &= ~VPO_CLEANCHK;
        }
        runlen = maxb + maxf + 1;
 
        vm_pageout_flush(ma, runlen, pagerflags);
        for (i = 0; i < runlen; i++) {
-               if (ma[i]->dirty) {
-                       pmap_remove_write(ma[i]);
-                       ma[i]->oflags |= VPO_CLEANCHK;
-
+               if (ma[i]->dirty != 0) {
+                       KASSERT((ma[i]->flags & PG_WRITEABLE) == 0,
+       ("vm_object_page_collect_flush: page %p is not write protected",
+                           ma[i]));
+               }
+       }
+       for (i = 0; i < maxf; i++) {
+               if (ma[i + maxb + 1]->dirty != 0) {
                        /*
                         * maxf will end up being the actual number of pages
                         * we wrote out contiguously, non-inclusive of the
                         * first page.  We do not count look-behind pages.
                         */
-                       if (i >= maxb + 1 && (maxf > i - maxb - 1))
-                               maxf = i - maxb - 1;
+                       if (maxf > i) {
+                               maxf = i;
+                               break;
+                       }
                }
        }
-       return(maxf + 1);
+       return (maxf + 1);
 }
 
 /*

Modified: head/sys/vm/vm_page.h
==============================================================================
--- head/sys/vm/vm_page.h       Sun Jul  4 11:13:33 2010        (r209685)
+++ head/sys/vm/vm_page.h       Sun Jul  4 11:26:56 2010        (r209686)
@@ -143,7 +143,6 @@ struct vm_page {
  */
 #define        VPO_BUSY        0x0001  /* page is in transit */
 #define        VPO_WANTED      0x0002  /* someone is waiting for page */
-#define        VPO_CLEANCHK    0x0100  /* page will be checked for cleaning */
 #define        VPO_SWAPINPROG  0x0200  /* swap I/O in progress on page */
 #define        VPO_NOSYNC      0x0400  /* do not collect for syncer */
 

Modified: head/sys/vm/vm_pager.h
==============================================================================
--- head/sys/vm/vm_pager.h      Sun Jul  4 11:13:33 2010        (r209685)
+++ head/sys/vm/vm_pager.h      Sun Jul  4 11:26:56 2010        (r209686)
@@ -90,7 +90,6 @@ extern struct pagerops sgpagerops;
 
 #define        VM_PAGER_PUT_SYNC               0x0001
 #define        VM_PAGER_PUT_INVAL              0x0002
-#define VM_PAGER_IGNORE_CLEANCHK       0x0004
 #define VM_PAGER_CLUSTER_OK            0x0008
 
 #ifdef _KERNEL
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to