BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / vm / swap_pager.c
index 6583c86..330e250 100644 (file)
@@ -7,9 +7,37 @@
  * the Systems Programming Group of the University of Utah Computer
  * Science Department.
  *
  * the Systems Programming Group of the University of Utah Computer
  * Science Department.
  *
- * %sccs.include.redist.c%
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)swap_pager.c        7.2 (Berkeley) %G%
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * from: Utah $Hdr: swap_pager.c 1.4 91/04/30$
+ *
+ *     @(#)swap_pager.c        7.4 (Berkeley) 5/7/91
  */
 
 /*
  */
 
 /*
@@ -23,7 +51,6 @@
 #if NSWAPPAGER > 0
 
 #include "param.h"
 #if NSWAPPAGER > 0
 
 #include "param.h"
-#include "user.h"
 #include "proc.h"
 #include "buf.h"
 #include "map.h"
 #include "proc.h"
 #include "buf.h"
 #include "map.h"
 #include "malloc.h"
 #include "queue.h"
 
 #include "malloc.h"
 #include "queue.h"
 
-#include "../vm/vm_param.h"
-#include "../vm/vm_pager.h"
-#include "../vm/vm_page.h"
-#include "../vm/vm_pageout.h"
-#include "../vm/swap_pager.h"
+#include "vm_param.h"
+#include "queue.h"
+#include "lock.h"
+#include "vm_prot.h"
+#include "vm_object.h"
+#include "vm_page.h"
+#include "vm_pageout.h"
+#include "swap_pager.h"
 
 #define NSWSIZES       16      /* size of swtab */
 #define NPENDINGIO     64      /* max # of pending cleans */
 
 #define NSWSIZES       16      /* size of swtab */
 #define NPENDINGIO     64      /* max # of pending cleans */
@@ -67,8 +97,6 @@ struct swpagerclean {
 } swcleanlist[NPENDINGIO];
 typedef        struct swpagerclean     *swp_clean_t;
 
 } swcleanlist[NPENDINGIO];
 typedef        struct swpagerclean     *swp_clean_t;
 
-#define SWP_CLEAN_NULL         ((swp_clean_t)0)
-
 /* spc_flags values */
 #define SPC_FREE       0x00
 #define SPC_BUSY       0x01
 /* spc_flags values */
 #define SPC_FREE       0x00
 #define SPC_BUSY       0x01
@@ -182,13 +210,13 @@ swap_pager_alloc(handle, size, prot)
         */
        if (handle) {
                pager = vm_pager_lookup(&swap_pager_list, handle);
         */
        if (handle) {
                pager = vm_pager_lookup(&swap_pager_list, handle);
-               if (pager != VM_PAGER_NULL) {
+               if (pager != NULL) {
                        /*
                         * Use vm_object_lookup to gain a reference
                         * to the object and also to remove from the
                         * object cache.
                         */
                        /*
                         * Use vm_object_lookup to gain a reference
                         * to the object and also to remove from the
                         * object cache.
                         */
-                       if (vm_object_lookup(pager) == VM_OBJECT_NULL)
+                       if (vm_object_lookup(pager) == NULL)
                                panic("swap_pager_alloc: bad object");
                        return(pager);
                }
                                panic("swap_pager_alloc: bad object");
                        return(pager);
                }
@@ -199,8 +227,8 @@ swap_pager_alloc(handle, size, prot)
         */
        waitok = handle ? M_WAITOK : M_NOWAIT;
        pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
         */
        waitok = handle ? M_WAITOK : M_NOWAIT;
        pager = (vm_pager_t)malloc(sizeof *pager, M_VMPAGER, waitok);
-       if (pager == VM_PAGER_NULL)
-               return(VM_PAGER_NULL);
+       if (pager == NULL)
+               return(NULL);
        swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
        if (swp == NULL) {
 #ifdef DEBUG
        swp = (sw_pager_t)malloc(sizeof *swp, M_VMPGDATA, waitok);
        if (swp == NULL) {
 #ifdef DEBUG
@@ -208,7 +236,7 @@ swap_pager_alloc(handle, size, prot)
                        printf("swpg_alloc: swpager malloc failed\n");
 #endif
                free((caddr_t)pager, M_VMPAGER);
                        printf("swpg_alloc: swpager malloc failed\n");
 #endif
                free((caddr_t)pager, M_VMPAGER);
-               return(VM_PAGER_NULL);
+               return(NULL);
        }
        size = round_page(size);
        for (swt = swtab; swt->st_osize; swt++)
        }
        size = round_page(size);
        for (swt = swtab; swt->st_osize; swt++)
@@ -312,7 +340,7 @@ swap_pager_dealloc(pager)
                thread_block();
        }
        splx(s);
                thread_block();
        }
        splx(s);
-       (void) swap_pager_clean(VM_PAGE_NULL, B_WRITE);
+       (void) swap_pager_clean(NULL, B_WRITE);
 
        /*
         * Free left over swap blocks
 
        /*
         * Free left over swap blocks
@@ -357,8 +385,8 @@ swap_pager_putpage(pager, m, sync)
        if (swpagerdebug & SDB_FOLLOW)
                printf("swpg_putpage(%x, %x, %d)\n", pager, m, sync);
 #endif
        if (swpagerdebug & SDB_FOLLOW)
                printf("swpg_putpage(%x, %x, %d)\n", pager, m, sync);
 #endif
-       if (pager == VM_PAGER_NULL) {
-               (void) swap_pager_clean(VM_PAGE_NULL, B_WRITE);
+       if (pager == NULL) {
+               (void) swap_pager_clean(NULL, B_WRITE);
                return;
        }
        flags = B_WRITE;
                return;
        }
        flags = B_WRITE;
@@ -434,17 +462,27 @@ swap_pager_io(swp, m, flags)
 
        /*
         * For reads (pageins) and synchronous writes, we clean up
 
        /*
         * For reads (pageins) and synchronous writes, we clean up
-        * all completed async pageouts and check to see if this
-        * page is currently being cleaned.  If it is, we just wait
-        * til the operation is done before continuing.
+        * all completed async pageouts.
         */
        if ((flags & B_ASYNC) == 0) {
                s = splbio();
         */
        if ((flags & B_ASYNC) == 0) {
                s = splbio();
+#ifdef DEBUG
+               /*
+                * Check to see if this page is currently being cleaned.
+                * If it is, we just wait til the operation is done before
+                * continuing.
+                */
                while (swap_pager_clean(m, flags&B_READ)) {
                while (swap_pager_clean(m, flags&B_READ)) {
+                       if (swpagerdebug & SDB_ANOM)
+                               printf("swap_pager_io: page %x cleaning\n", m);
+
                        swp->sw_flags |= SW_WANTED;
                        assert_wait((int)swp);
                        thread_block();
                }
                        swp->sw_flags |= SW_WANTED;
                        assert_wait((int)swp);
                        thread_block();
                }
+#else
+               (void) swap_pager_clean(m, flags&B_READ);
+#endif
                splx(s);
        }
        /*
                splx(s);
        }
        /*
@@ -453,8 +491,15 @@ swap_pager_io(swp, m, flags)
         * page is already being cleaned.  If it is, or no resources
         * are available, we try again later.
         */
         * page is already being cleaned.  If it is, or no resources
         * are available, we try again later.
         */
-       else if (swap_pager_clean(m, B_WRITE) || queue_empty(&swap_pager_free))
+       else if (swap_pager_clean(m, B_WRITE) ||
+                queue_empty(&swap_pager_free)) {
+#ifdef DEBUG
+               if ((swpagerdebug & SDB_ANOM) &&
+                   !queue_empty(&swap_pager_free))
+                       printf("swap_pager_io: page %x already cleaning\n", m);
+#endif
                return(VM_PAGER_FAIL);
                return(VM_PAGER_FAIL);
+       }
 
        /*
         * Determine swap block and allocate as necessary.
 
        /*
         * Determine swap block and allocate as necessary.
@@ -516,7 +561,7 @@ swap_pager_io(swp, m, flags)
        while (bswlist.av_forw == NULL) {
 #ifdef DEBUG
                if (swpagerdebug & SDB_ANOM)
        while (bswlist.av_forw == NULL) {
 #ifdef DEBUG
                if (swpagerdebug & SDB_ANOM)
-                       printf("swpg_io: wait on swbuf for %x (%d)\n",
+                       printf("swap_pager_io: wait on swbuf for %x (%d)\n",
                               m, flags);
 #endif
                bswlist.b_flags |= B_WANTED;
                               m, flags);
 #endif
                bswlist.b_flags |= B_WANTED;
@@ -526,7 +571,7 @@ swap_pager_io(swp, m, flags)
        bswlist.av_forw = bp->av_forw;
        splx(s);
        bp->b_flags = B_BUSY | (flags & B_READ);
        bswlist.av_forw = bp->av_forw;
        splx(s);
        bp->b_flags = B_BUSY | (flags & B_READ);
-       bp->b_proc = &proc[0];  /* XXX (but without B_PHYS set this is ok) */
+       bp->b_proc = &proc0;    /* XXX (but without B_PHYS set this is ok) */
        bp->b_un.b_addr = (caddr_t)kva;
        bp->b_blkno = swb->swb_block + btodb(off);
        VHOLD(swapdev_vp);
        bp->b_un.b_addr = (caddr_t)kva;
        bp->b_blkno = swb->swb_block + btodb(off);
        VHOLD(swapdev_vp);
@@ -557,9 +602,6 @@ swap_pager_io(swp, m, flags)
                spc->spc_swp = swp;
                spc->spc_kva = kva;
                spc->spc_m = m;
                spc->spc_swp = swp;
                spc->spc_kva = kva;
                spc->spc_m = m;
-#ifdef DEBUG
-               m->pagerowned = 1;
-#endif
                bp->b_flags |= B_CALL;
                bp->b_iodone = swap_pager_iodone;
                s = splbio();
                bp->b_flags |= B_CALL;
                bp->b_iodone = swap_pager_iodone;
                s = splbio();
@@ -577,12 +619,6 @@ swap_pager_io(swp, m, flags)
                               swp->sw_blocks, swb->swb_block, atop(off));
 #endif
                swb->swb_mask |= (1 << atop(off));
                               swp->sw_blocks, swb->swb_block, atop(off));
 #endif
                swb->swb_mask |= (1 << atop(off));
-               /*
-                * XXX: Block write faults til we are done.
-                */
-               m->page_lock = VM_PROT_WRITE;
-               m->unlock_request = VM_PROT_ALL;
-               pmap_copy_on_write(VM_PAGE_TO_PHYS(m));
                splx(s);
        }
 #ifdef DEBUG
                splx(s);
        }
 #ifdef DEBUG
@@ -626,7 +662,7 @@ swap_pager_io(swp, m, flags)
                thread_wakeup((int)&bswlist);
        }
        if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
                thread_wakeup((int)&bswlist);
        }
        if ((flags & B_READ) == 0 && rv == VM_PAGER_OK) {
-               m->clean = 1;
+               m->clean = TRUE;
                pmap_clear_modify(VM_PAGE_TO_PHYS(m));
        }
        splx(s);
                pmap_clear_modify(VM_PAGE_TO_PHYS(m));
        }
        splx(s);
@@ -655,7 +691,7 @@ swap_pager_clean(m, rw)
        if (swpagerdebug & SDB_FOLLOW)
                printf("swpg_clean(%x, %d)\n", m, rw);
 #endif
        if (swpagerdebug & SDB_FOLLOW)
                printf("swpg_clean(%x, %d)\n", m, rw);
 #endif
-       tspc = SWP_CLEAN_NULL;
+       tspc = NULL;
        for (;;) {
                /*
                 * Look up and removal from inuse list must be done
        for (;;) {
                /*
                 * Look up and removal from inuse list must be done
@@ -673,7 +709,7 @@ swap_pager_clean(m, rw)
                        if (m && m == spc->spc_m) {
 #ifdef DEBUG
                                if (swpagerdebug & SDB_ANOM)
                        if (m && m == spc->spc_m) {
 #ifdef DEBUG
                                if (swpagerdebug & SDB_ANOM)
-                                       printf("swpg_clean: %x on list, flags %x\n",
+                                       printf("swap_pager_clean: page %x on list, flags %x\n",
                                               m, spc->spc_flags);
 #endif
                                tspc = spc;
                                               m, spc->spc_flags);
 #endif
                                tspc = spc;
@@ -695,10 +731,10 @@ swap_pager_clean(m, rw)
                if (tspc && tspc == spc) {
 #ifdef DEBUG
                        if (swpagerdebug & SDB_ANOM)
                if (tspc && tspc == spc) {
 #ifdef DEBUG
                        if (swpagerdebug & SDB_ANOM)
-                               printf("swpg_clean: %x done while looking\n",
+                               printf("swap_pager_clean: page %x done while looking\n",
                                       m);
 #endif
                                       m);
 #endif
-                       tspc = SWP_CLEAN_NULL;
+                       tspc = NULL;
                }
                spc->spc_flags = SPC_FREE;
                vm_pager_unmap_page(spc->spc_kva);
                }
                spc->spc_flags = SPC_FREE;
                vm_pager_unmap_page(spc->spc_kva);
@@ -708,18 +744,19 @@ swap_pager_clean(m, rw)
                        printf("swpg_clean: free spc %x\n", spc);
 #endif
        }
                        printf("swpg_clean: free spc %x\n", spc);
 #endif
        }
+#ifdef DEBUG
        /*
         * If we found that the desired page is already being cleaned
         * mark it so that swap_pager_iodone() will not set the clean
         * flag before the pageout daemon has another chance to clean it.
         */
        if (tspc && rw == B_WRITE) {
        /*
         * If we found that the desired page is already being cleaned
         * mark it so that swap_pager_iodone() will not set the clean
         * flag before the pageout daemon has another chance to clean it.
         */
        if (tspc && rw == B_WRITE) {
-#ifdef DEBUG
                if (swpagerdebug & SDB_ANOM)
                if (swpagerdebug & SDB_ANOM)
-                       printf("swpg_clean: %x on clean list\n", tspc);
-#endif
+                       printf("swap_pager_clean: page %x on clean list\n",
+                              tspc);
                tspc->spc_flags |= SPC_DIRTY;
        }
                tspc->spc_flags |= SPC_DIRTY;
        }
+#endif
        splx(s);
 
 #ifdef DEBUG
        splx(s);
 
 #ifdef DEBUG
@@ -746,38 +783,42 @@ swap_pager_finish(spc)
        if (!vm_object_lock_try(object))
                return(0);
 
        if (!vm_object_lock_try(object))
                return(0);
 
-#ifdef DEBUG
-       spc->spc_m->pagerowned = 0;
-#endif
-
        if (--object->paging_in_progress == 0)
                thread_wakeup((int) object);
 
        if (--object->paging_in_progress == 0)
                thread_wakeup((int) object);
 
+#ifdef DEBUG
        /*
         * XXX: this isn't even close to the right thing to do,
         * introduces a variety of race conditions.
         *
         * If dirty, vm_pageout() has attempted to clean the page
         * again.  In this case we do not do anything as we will
        /*
         * XXX: this isn't even close to the right thing to do,
         * introduces a variety of race conditions.
         *
         * If dirty, vm_pageout() has attempted to clean the page
         * again.  In this case we do not do anything as we will
-        * see the page again shortly.  Otherwise, if no error mark
-        * as clean and inform the pmap system.  If error, mark as
-        * dirty so we will try again (XXX: could get stuck doing
-        * this, should give up after awhile).
+        * see the page again shortly.
         */
         */
-       if ((spc->spc_flags & SPC_DIRTY) == 0) {
-               if (spc->spc_flags & SPC_ERROR) {
-                       printf("swap_pager: clean of %x failed\n",
-                              VM_PAGE_TO_PHYS(spc->spc_m));
-                       spc->spc_m->laundry = TRUE;
-               } else {
-                       spc->spc_m->clean = TRUE;
-                       pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
-               }
+       if (spc->spc_flags & SPC_DIRTY) {
+               if (swpagerdebug & SDB_ANOM)
+                       printf("swap_pager_finish: page %x dirty again\n",
+                              spc->spc_m);
+               spc->spc_m->busy = FALSE;
+               PAGE_WAKEUP(spc->spc_m);
+               vm_object_unlock(object);
+               return(1);
        }
        }
+#endif
        /*
        /*
-        * XXX: allow blocked write faults to continue
+        * If no error mark as clean and inform the pmap system.
+        * If error, mark as dirty so we will try again.
+        * (XXX could get stuck doing this, should give up after awhile)
         */
         */
-       spc->spc_m->page_lock = spc->spc_m->unlock_request = VM_PROT_NONE;
+       if (spc->spc_flags & SPC_ERROR) {
+               printf("swap_pager_finish: clean of page %x failed\n",
+                      VM_PAGE_TO_PHYS(spc->spc_m));
+               spc->spc_m->laundry = TRUE;
+       } else {
+               spc->spc_m->clean = TRUE;
+               pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
+       }
+       spc->spc_m->busy = FALSE;
        PAGE_WAKEUP(spc->spc_m);
 
        vm_object_unlock(object);
        PAGE_WAKEUP(spc->spc_m);
 
        vm_object_unlock(object);
@@ -807,7 +848,7 @@ swap_pager_iodone(bp)
        }
 #ifdef DEBUG
        if (queue_end(&swap_pager_inuse, (queue_entry_t)spc))
        }
 #ifdef DEBUG
        if (queue_end(&swap_pager_inuse, (queue_entry_t)spc))
-               panic("swpg_iodone: bp not found");
+               panic("swap_pager_iodone: bp not found");
 #endif
 
        spc->spc_flags &= ~SPC_BUSY;
 #endif
 
        spc->spc_flags &= ~SPC_BUSY;
@@ -840,35 +881,6 @@ swap_pager_iodone(bp)
                bswlist.b_flags &= ~B_WANTED;
                thread_wakeup((int)&bswlist);
        }
                bswlist.b_flags &= ~B_WANTED;
                thread_wakeup((int)&bswlist);
        }
-#if 0
-       /*
-        * XXX: this isn't even close to the right thing to do,
-        * introduces a variety of race conditions.
-        *
-        * If dirty, vm_pageout() has attempted to clean the page
-        * again.  In this case we do not do anything as we will
-        * see the page again shortly.  Otherwise, if no error mark
-        * as clean and inform the pmap system.  If error, mark as
-        * dirty so we will try again (XXX: could get stuck doing
-        * this, should give up after awhile).
-        */
-       if ((spc->spc_flags & SPC_DIRTY) == 0) {
-               if (spc->spc_flags & SPC_ERROR) {
-                       printf("swap_pager: clean of %x (block %x) failed\n",
-                              VM_PAGE_TO_PHYS(spc->spc_m), blk);
-                       spc->spc_m->laundry = TRUE;
-               } else {
-                       spc->spc_m->clean = TRUE;
-                       pmap_clear_modify(VM_PAGE_TO_PHYS(spc->spc_m));
-               }
-       }
-       /*
-        * XXX: allow blocked write faults to continue
-        */
-       spc->spc_m->page_lock = spc->spc_m->unlock_request = VM_PROT_NONE;
-       PAGE_WAKEUP(spc->spc_m);
-#endif
-
        thread_wakeup((int) &vm_pages_needed);
        splx(s);
 }
        thread_wakeup((int) &vm_pages_needed);
        splx(s);
 }